Skip to content

Commit

Permalink
feat(Flex): add new Flex layout component
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Oct 12, 2023
1 parent cf0d5b6 commit dbb465b
Show file tree
Hide file tree
Showing 104 changed files with 1,311 additions and 924 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ComponentBox from '../../../../shared/tags/ComponentBox'
import { Card, Layout, P } from '@dnb/eufemia/src'
import { Card, Flex, P } from '@dnb/eufemia/src'
import { Field, Form } from '@dnb/eufemia/src/extensions/forms'

export const Default = () => {
Expand Down Expand Up @@ -34,10 +34,10 @@ export const VerticalFields = () => {
return (
<ComponentBox scope={{ Field }}>
<Card>
<Layout.Vertical>
<Flex.Vertical>
<Field.String label="Label" value="Value" />
<Field.String label="Label" value="Value" />
</Layout.Vertical>
</Flex.Vertical>
</Card>
</ComponentBox>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,26 @@ import * as Examples from './Examples'

`Card` is a block section element showing the white box with rounded gray borders, adding spacing automatically.

It uses [Layout.FlexItem](/uilib/components/layout/FlexItem) under the hood. When one of these props where given, `stack`, `direction` or `spacing` – the [Layout.FlexContainer](/uilib/components/layout/FlexContainer) will be used.
It uses [Flex.Item](/uilib/components/flex/item) under the hood. When one of these props where given, `stack`, `direction` or `spacing` – the [Flex.Container](/uilib/components/flex/container) will be used.

**BETA:** The design is not 100% finalised and may change to be officially approved by UX through an RFC.

```jsx
import { Card } from '@dnb/eufemia'
import { Form, Field } from '@dnb/eufemia/extensions/forms'

render(
<Form.Handler data={existingData} onSubmit={submitHandler}>
<Card>
<Field.Email path="/dataPath" />
<Form.ButtonRow>
<Form.SubmitButton />
</Form.ButtonRow>
</Card>
</Form.Handler>,
)
```

## Accessibility

It uses a `section` element. Which allows you to add an `aria-label` or `aria-labelledby` to provide screen readers with landmarks.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ showTabs: true

## Properties

| Property | Type | Description |
| -------------------------------------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------- |
| `stack` | `boolean` | _(optional)_ True to stack the sub components with lines between. The `spacing` will default to `medium`. |
| `direction` | `string` | _(optional)_ Defaults to `vertical`. |
| `alignSelf` | `string` | _(optional)_ Defaults to `stretch`. |
| `element` | `string` or `React.Element` | _(optional)_ Define the type of element. Defaults to `section`. |
| [Layout.FlexContainer](/uilib/components/layout/FlexContainer) | Various | _(optional)_ FlexContainer properties. |
| [Layout.FlexItem](/uilib/components/layout/FlexItem) | Various | _(optional)_ FlexItem properties. |
| [Space](/uilib/components/space/properties) | Various | _(optional)_ Spacing properties like `top` or `bottom` are supported. |
| Property | Type | Description |
| -------------------------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------- |
| `stack` | `boolean` | _(optional)_ True to stack the sub components with lines between. The `spacing` will default to `medium`. |
| `direction` | `string` | _(optional)_ Defaults to `vertical`. |
| `alignSelf` | `string` | _(optional)_ Defaults to `stretch`. |
| `element` | `string` or `React.Element` | _(optional)_ Define the type of element. Defaults to `section`. |
| [Flex.Container](/uilib/components/flex/container) | Various | _(optional)_ Flex.Container properties. |
| [Flex.Item](/uilib/components/flex/item) | Various | _(optional)_ Flex.Item properties. |
| [Space](/uilib/components/space/properties) | Various | _(optional)_ Spacing properties like `top` or `bottom` are supported. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: 'Flex'
description: 'To make it easier to build application layout and form-views in line with defined design sketches, there are a number of components for layout.'
status: 'new'
theme: 'sbanken'
showTabs: true
tabs:
- title: Info
key: /info
- title: Demos
key: /demos
---

import Info from 'Docs/uilib/components/flex/info'
import Demos from 'Docs/uilib/components/flex/demos'

<Info />
<Demos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
import React from 'react'
import styled from '@emotion/styled'
import ComponentBox from '../../../../shared/tags/ComponentBox'
import MediaQuery from '@dnb/eufemia/src/shared/MediaQuery'
import { Slider, Code, Button, Card, Flex } from '@dnb/eufemia/src'
import {
TestElement,
Field,
FieldBlock,
Form,
} from '@dnb/eufemia/src/extensions/forms'
import { defaultBreakpoints } from '@dnb/eufemia/src/shared/MediaQueryUtils'
import { defaultQueries } from '@dnb/eufemia/src/shared/useMedia'
import { useMedia, useMediaQuery } from '@dnb/eufemia/src/shared'

export const LayoutComponents = () => {
return (
<ComponentBox
scope={{
Field,
Form,
}}
>
<Flex.Stack>
<Form.MainHeading>Profile</Form.MainHeading>

<Card stack>
<Form.SubHeading>Name</Form.SubHeading>

<Field.String label="Fornavn" value="John" />
<Field.String label="Etternavn" value="Smith" />
</Card>

<Card stack>
<Form.SubHeading>More information</Form.SubHeading>

<Field.NationalIdentityNumber value="20058512345" />
<Field.Email value="john@smith.email" />
<Field.PhoneNumber value="+47 98765432" />
</Card>
</Flex.Stack>
</ComponentBox>
)
}

export const colors = [
{ background: '#babeee' } as React.CSSProperties,
{ background: '#dfe0ee' } as React.CSSProperties,
{ background: '#90d2c3' } as React.CSSProperties,
{ background: '#ecf4be' } as React.CSSProperties,
]

export const HorizontalFlexItemResponsiveSize = () => {
return (
<ComponentBox
scope={{ colors, TestElement, Field }}
data-visual-test="flex-item-size"
>
<Flex.Container>
<Flex.Item size={8}>
<TestElement style={colors[0]}>FlexItem (8)</TestElement>
</Flex.Item>
<Flex.Item size={4}>
<TestElement style={colors[1]}>FlexItem (4)</TestElement>
</Flex.Item>
<Flex.Item size={{ small: 12, medium: 4 }}>
<TestElement style={colors[2]}>
FlexItem (small: 8, medium: 4)
</TestElement>
</Flex.Item>
<Flex.Item size={{ small: 12, medium: 8 }}>
<TestElement style={colors[3]}>
FlexItem (small: 4, medium: 8)
</TestElement>
</Flex.Item>
</Flex.Container>
</ComponentBox>
)
}

export const HorizontalFlexItemResponsiveSizeCustomColumns = () => {
return (
<ComponentBox
scope={{
colors,
TestElement,
Field,
defaultBreakpoints,
defaultQueries,
}}
data-visual-test="flex-item-custom-size"
>
{() => {
const breakpoints = {
...defaultBreakpoints,
xsmall: '30em',
}

const queries = {
...defaultQueries,
xsmall: { min: 0, max: 'xsmall' },
small: { min: 'xsmall', max: 'small' },
}

const CustomMediaQuery = styled.div`
display: flex;
flex-direction: column;
.dnb-flex-container[data-media-key='xsmall']
.dnb-flex-item--responsive {
--size: var(--xsmall);
}
`

return (
<CustomMediaQuery>
<Flex.Container
direction="horizontal"
sizeCount={4}
breakpoints={breakpoints}
queries={queries}
>
<Flex.Item size={{ small: 2, medium: 3, large: 1 }}>
<TestElement style={colors[0]}>FlexItem</TestElement>
</Flex.Item>
<Flex.Item size={{ small: 2, medium: 1, large: 2 }}>
<TestElement style={colors[1]}>FlexItem</TestElement>
</Flex.Item>
<Flex.Item
size={{ xsmall: 4, small: 2, medium: 1, large: 1 }}
>
<TestElement style={colors[2]}>FlexItem</TestElement>
</Flex.Item>
<Flex.Item
size={{ xsmall: 4, small: 2, medium: 3, large: 4 }}
>
<TestElement style={colors[3]}>FlexItem</TestElement>
</Flex.Item>
</Flex.Container>
</CustomMediaQuery>
)
}}
</ComponentBox>
)
}

export const HorizontalAutoSize = () => {
return (
<ComponentBox
scope={{
Field,
FieldBlock,
}}
hideCode
>
<FieldBlock label="Label">
<Flex.Container>
<Flex.Item size={{ small: 12, large: 'auto' }}>
<Field.String
path="/firstName"
label="First name"
width="medium"
minLength={2}
/>
</Flex.Item>
<Flex.Item size={{ small: 12, large: 'auto' }}>
<Field.String
path="/lastName"
label="Last name"
width="medium"
required
/>
</Flex.Item>
<Flex.Item size={{ small: 12, large: 'auto' }}>
<FieldBlock width="large">
<Slider
min={1900}
max={new Date().getFullYear()}
step={1}
value={2010}
label="Birth year"
label_direction="vertical"
tooltip
alwaysShowTooltip
/>
</FieldBlock>
</Flex.Item>
</Flex.Container>
</FieldBlock>
</ComponentBox>
)
}

const useWindowWidth = () => {
const [innerWidth, setWidth] = React.useState(
typeof window !== 'undefined' ? window.innerWidth : 0,
)

React.useEffect(() => {
const resizeHandler = () => {
setWidth(window.innerWidth)
}
window.addEventListener('resize', resizeHandler)
return () => window.removeEventListener('resize', resizeHandler)
}, [])

return { innerWidth }
}

export const MediaQueryUseMedia = () => (
<ComponentBox scope={{ useMedia, useWindowWidth }} hideCode>
{() => {
const Playground = () => {
const { isSmall, isMedium, isLarge, isSSR } = useMedia()
const { innerWidth } = useWindowWidth()

return (
<Code>
<pre>
{JSON.stringify(
{ isSmall, isMedium, isLarge, isSSR, innerWidth },
null,
2,
)}
</pre>
</Code>
)
}
return <Playground />
}}
</ComponentBox>
)

export const MediaQueryLiveExample = () => (
<ComponentBox scope={{ MediaQuery, useMediaQuery }} hideCode>
{() => {
const Playground = () => {
const [query, updateQuery] = React.useState({
screen: true,
not: true,
min: 'small',
max: 'large',
})

const match1 = useMediaQuery({
matchOnSSR: true,
when: query,
})
const match2 = useMediaQuery({
matchOnSSR: true,
not: true,
when: query,
})

React.useEffect(() => {
console.log('mediaQuery:', match1, match2)
}, [match1, match2])

return (
<>
<Button
onClick={() => {
updateQuery({
...query,
screen: !query.screen,
})
}}
right
>
Switch
</Button>
<MediaQuery when={query}>
<Code>when</Code>
</MediaQuery>
<MediaQuery not when={query}>
<Code>not when</Code>
</MediaQuery>
</>
)
}
return <Playground />
}}
</ComponentBox>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: 'Flex.Container'
description: '`Flex.Container` is a building block for CSS Grid based layouts.'
hideInMenu: true
showTabs: true
tabs:
- title: Info
key: '/info'
- title: Demos
key: '/demos'
- title: Properties
key: '/properties'
---

import Info from 'Docs/uilib/components/flex/container/info'
import Demos from 'Docs/uilib/components/flex/container/demos'

<Info />
<Demos />
Loading

0 comments on commit dbb465b

Please sign in to comment.