Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit d4ca3af

Browse files
authored
feat: Flex component (#802)
* initial * remove support for 'center' prop * refactor the API * rename refactoring * merge master * remove unnecessary type cast * remove prototyping shortcuts * adjust marker strategy for Flex Item * revert marker strategy for flex item * introduce semantic names to size values * apply semantic size values to flex item styles * fix prop types of Flex component * remove unnecessary 'as' prop in media card example * rename type of flex item variables * fix typo * remove unnecessary comments * update flex item marker comment * further remove stale comments * further refactoring * rename refactoring * add padding to examples * address review comments * add types * simplify gap render condition * remove obsolete comment * optimize the amount of types necessary * remove inline style prop * imtroduce type for Flex Gap * introduce additional flex item size option * refine prop types of flex item * use built-in TS types * minor syntax simplification * add type for flex variables in styles func * expose prop types to public interface * reorder preferences of merged styles * upd * update changelog * upd changelog * upd media card example
1 parent de45998 commit d4ca3af

20 files changed

+572
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
2424
- Add single search flavor for `Dropdown` component @Bugaa92 ([#839](https://github.com/stardust-ui/react/pull/839))
2525
- Add multiple selection flavor for `Dropdown` component @Bugaa92 ([#845](https://github.com/stardust-ui/react/pull/845))
2626
- Add `black` and `white` options for the `color` prop of the `Label` component @mnajdova ([#855](https://github.com/stardust-ui/react/pull/855))
27+
- Add `Flex` component @kuzhelov ([#802](https://github.com/stardust-ui/react/pull/802))
2728

2829
<!--------------------------------[ v0.20.0 ]------------------------------- -->
2930
## [v0.20.0](https://github.com/stardust-ui/react/tree/v0.20.0) (2019-02-06)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as React from 'react'
2+
import { Flex, Segment } from '@stardust-ui/react'
3+
4+
const FlexExampleColumns = () => (
5+
<>
6+
<Flex gap="gap.small" padding="padding.medium">
7+
<Flex.Item size="size.half">
8+
<Segment content="1/2" />
9+
</Flex.Item>
10+
11+
<Flex.Item size="size.half">
12+
<Segment content="1/2" />
13+
</Flex.Item>
14+
</Flex>
15+
16+
<Flex gap="gap.small" padding="padding.medium">
17+
<Flex.Item size="size.quarter">
18+
<Segment content="1/4" />
19+
</Flex.Item>
20+
21+
<Flex.Item size="size.half">
22+
<Segment content="1/2" />
23+
</Flex.Item>
24+
25+
<Flex.Item size="size.quarter">
26+
<Segment content="1/4" />
27+
</Flex.Item>
28+
</Flex>
29+
30+
<Flex gap="gap.small" padding="padding.medium" style={{ minHeight: 200 }}>
31+
<Flex.Item size="size.half">
32+
<Segment content="Full-height, even when my content doesn't fill the space." />
33+
</Flex.Item>
34+
35+
<Flex.Item size="size.half">
36+
<Segment content="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum mollis velit non gravida venenatis. Praesent consequat lectus purus, ut scelerisque velit condimentum eu. Maecenas sagittis ante ut turpis varius interdum. Quisque tellus ipsum, eleifend non ipsum id, suscipit ultricies neque." />
37+
</Flex.Item>
38+
</Flex>
39+
</>
40+
)
41+
42+
export default FlexExampleColumns
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as React from 'react'
2+
import { Flex, Input, Button, Label } from '@stardust-ui/react'
3+
4+
const FlexExampleInput = () => (
5+
<Flex gap="gap.medium" debug>
6+
<Flex.Item grow>
7+
<Flex>
8+
<Label
9+
icon="plane"
10+
styles={{ background: 'darkgrey', height: 'auto', padding: '0 15px' }}
11+
/>
12+
13+
<Flex.Item grow>
14+
<Input placeholder="Enter your flight #" fluid />
15+
</Flex.Item>
16+
</Flex>
17+
</Flex.Item>
18+
19+
<Button content="Load" />
20+
</Flex>
21+
)
22+
23+
export default FlexExampleInput
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as React from 'react'
2+
import { Flex, Segment } from '@stardust-ui/react'
3+
4+
const FlexExampleItemsAlignment = () => (
5+
<Flex column gap="gap.large" hAlign="center" vAlign="center" debug>
6+
{[
7+
[
8+
{ hAlign: 'start', vAlign: 'start' },
9+
{ hAlign: 'start', vAlign: 'center' },
10+
{ hAlign: 'start', vAlign: 'end' },
11+
],
12+
[
13+
{ hAlign: 'center', vAlign: 'start' },
14+
{ hAlign: 'center', vAlign: 'center' },
15+
{ hAlign: 'center', vAlign: 'end' },
16+
],
17+
[
18+
{ hAlign: 'end', vAlign: 'start' },
19+
{ hAlign: 'end', vAlign: 'center' },
20+
{ hAlign: 'end', vAlign: 'end' },
21+
],
22+
].map(rowOfAlignmentProps => (
23+
<Flex gap="gap.large">
24+
{rowOfAlignmentProps.map((alignmentProps: any) => (
25+
<Flex inline {...alignmentProps} style={{ width: '100px', height: '100px' }} debug>
26+
<Segment styles={{ width: '30px', height: '30px' }} />
27+
</Flex>
28+
))}
29+
</Flex>
30+
))}
31+
</Flex>
32+
)
33+
34+
export default FlexExampleItemsAlignment
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from 'react'
2+
import { Flex, Image, Text, Header } from '@stardust-ui/react'
3+
4+
const FlexExampleMediaCard = () => (
5+
<Flex gap="gap.medium" padding="padding.medium" debug>
6+
<Flex.Item size="size.medium">
7+
<div style={{ position: 'relative' }}>
8+
<Image fluid src="public/images/avatar/large/ade.jpg" />
9+
</div>
10+
</Flex.Item>
11+
12+
<Flex.Item grow>
13+
<Flex column gap="gap.small" vAlign="stretch">
14+
<Flex space="between">
15+
<Header as="h3" content="LOREM IPSUM" />
16+
<Text as="pre" content="Oct 24th, 00:01" />
17+
</Flex>
18+
19+
<Text content="Man braid iPhone locavore hashtag pop-up, roof party forage heirloom chillwave brooklyn yr 8-bit gochujang blog." />
20+
21+
<Flex.Item push>
22+
<Text as="pre" content="COPYRIGHT: Stardust-UI Inc." />
23+
</Flex.Item>
24+
</Flex>
25+
</Flex.Item>
26+
</Flex>
27+
)
28+
29+
export default FlexExampleMediaCard
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as React from 'react'
2+
import { Flex, Segment } from '@stardust-ui/react'
3+
4+
const FlexExampleMixedAlignment = () => (
5+
<Flex gap="gap.small" hAlign="center" vAlign="center" debug>
6+
<Flex.Item align="start" size="size.small">
7+
<Segment content="This cell should be top aligned." />
8+
</Flex.Item>
9+
10+
<Flex.Item align="stretch" size="size.small">
11+
<Segment content="Curabitur pulvinar dolor lectus, quis porta turpis ullamcorper nec. Quisque eget varius turpis, quis iaculis nibh. Ut interdum ligula id metus hendrerit cursus. Integer eu leo felis. Aenean commodo ultrices nunc, sit amet blandit elit gravida in. Sed est ligula, ornare ac nisi adipiscing, iaculis facilisis tellus." />
12+
</Flex.Item>
13+
14+
<Flex.Item align="center" size="size.small">
15+
<Segment content="This cell should be center-aligned." />
16+
</Flex.Item>
17+
18+
<Flex.Item align="end" size="size.small">
19+
<Segment content="This cell should be bottom-aligned." />
20+
</Flex.Item>
21+
</Flex>
22+
)
23+
24+
export default FlexExampleMixedAlignment
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as React from 'react'
2+
import { Flex, Button } from '@stardust-ui/react'
3+
4+
const FlexExampleNavMenu = () => (
5+
<Flex gap="gap.small" debug>
6+
<Button content="Logo" icon="chess rook" />
7+
8+
<Flex.Item push>
9+
<Button content="Page 1" />
10+
</Flex.Item>
11+
12+
<Button content="Page 2" />
13+
<Button content="Page 3" />
14+
</Flex>
15+
)
16+
17+
export default FlexExampleNavMenu
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import * as React from 'react'
2+
import ComponentExample from 'docs/src/components/ComponentDoc/ComponentExample'
3+
import ExampleSection from 'docs/src/components/ComponentDoc/ExampleSection'
4+
5+
const Types = () => (
6+
<ExampleSection title="Types">
7+
<ComponentExample
8+
title="Media Card"
9+
description="Flex items alignment options."
10+
examplePath="components/Flex/Types/FlexExampleMediaCard"
11+
/>
12+
<ComponentExample
13+
title="Input"
14+
description="Flex items alignment options."
15+
examplePath="components/Flex/Types/FlexExampleInput"
16+
/>
17+
<ComponentExample
18+
title="Nav Menu"
19+
description="Flex items alignment options."
20+
examplePath="components/Flex/Types/FlexExampleNavMenu"
21+
/>
22+
<ComponentExample
23+
title="Items Alignment"
24+
description="Flex items alignment options."
25+
examplePath="components/Flex/Types/FlexExampleItemsAlignment"
26+
/>
27+
<ComponentExample
28+
title="Mixed Alignment"
29+
description="Flex mixed alignment feature."
30+
examplePath="components/Flex/Types/FlexExampleMixedAlignment"
31+
/>
32+
<ComponentExample
33+
title="Columns (item size)"
34+
description="Flex columns example."
35+
examplePath="components/Flex/Types/FlexExampleColumns"
36+
/>
37+
</ExampleSection>
38+
)
39+
40+
export default Types
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as React from 'react'
2+
import Types from './Types'
3+
4+
const FlexExamples = () => (
5+
<>
6+
<Types />
7+
</>
8+
)
9+
10+
export default FlexExamples
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import * as PropTypes from 'prop-types'
2+
import * as React from 'react'
3+
import * as _ from 'lodash'
4+
import cx from 'classnames'
5+
6+
import { UIComponent, commonPropTypes } from '../../lib'
7+
import { ReactProps } from '../../types'
8+
import FlexItem from './FlexItem'
9+
import FlexGap from './FlexGap'
10+
11+
export interface FlexProps {
12+
/** Defines if container should be inline element. */
13+
inline?: boolean
14+
15+
/** Sets vertical flow direction. */
16+
column?: boolean
17+
18+
/** Allows overflow items to wrap on the next container's line. */
19+
wrap?: boolean
20+
21+
/** Controls items alignment in horizontal direction. */
22+
hAlign?: 'start' | 'center' | 'end' | 'stretch'
23+
24+
/** Controls items alignment in vertical direction. */
25+
vAlign?: 'start' | 'center' | 'end' | 'stretch'
26+
27+
/** Defines strategy for distributing remaining space between items. */
28+
space?: 'around' | 'between' | 'evenly'
29+
30+
/** Defines gap between each two adjacent child items. */
31+
gap?: 'gap.small' | 'gap.medium' | 'gap.large'
32+
33+
/** Defines container's padding. */
34+
padding?: 'padding.medium'
35+
36+
/** Enables debug mode. */
37+
debug?: boolean
38+
39+
/** Orders container to fill all parent's space available. */
40+
fill?: boolean
41+
}
42+
43+
/**
44+
* Arrange group of items aligned towards common direction.
45+
*/
46+
class Flex extends UIComponent<ReactProps<FlexProps>> {
47+
static Item = FlexItem
48+
49+
static Gap = FlexGap
50+
51+
static displayName = 'Flex'
52+
static className = 'ui-flex'
53+
54+
static defaultProps = {
55+
as: 'div',
56+
}
57+
58+
public static propTypes = {
59+
...commonPropTypes.createCommon({
60+
content: false,
61+
}),
62+
63+
inline: PropTypes.bool,
64+
65+
column: PropTypes.bool,
66+
67+
wrap: PropTypes.bool,
68+
69+
hAlign: PropTypes.oneOf(['start', 'center', 'end', 'stretch']),
70+
vAlign: PropTypes.oneOf(['start', 'center', 'end', 'stretch']),
71+
72+
space: PropTypes.oneOf(['around', 'between', 'evenly']),
73+
74+
gap: PropTypes.oneOf(['gap.small', 'gap.medium', 'gap.large']),
75+
76+
padding: PropTypes.oneOf(['padding.medium']),
77+
fill: PropTypes.bool,
78+
79+
debug: PropTypes.bool,
80+
}
81+
82+
renderComponent({ ElementType, classes, unhandledProps }): React.ReactNode {
83+
return (
84+
<ElementType className={classes.root} {...unhandledProps}>
85+
{this.renderChildren(classes.gap)}
86+
</ElementType>
87+
)
88+
}
89+
90+
renderChildren = (gapClasses: string) => {
91+
const { column, gap, children } = this.props
92+
93+
return React.Children.map(children, (child: React.ReactElement<any>, index) => {
94+
const childElement =
95+
child.type && ((child.type as any) as typeof FlexItem).__isFlexItem
96+
? React.cloneElement(child, {
97+
flexDirection: column ? 'column' : 'row',
98+
})
99+
: child
100+
101+
const renderGap = index !== 0
102+
return (
103+
<>
104+
{renderGap && gap && <Flex.Gap className={cx(`${Flex.className}__gap`, gapClasses)} />}
105+
{childElement}
106+
</>
107+
)
108+
})
109+
}
110+
}
111+
112+
export default Flex
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import * as React from 'react'
2+
3+
const FlexGap: React.FC<any> = ({ className }) => <div className={className} />
4+
FlexGap.displayName = 'FlexGap'
5+
6+
export default FlexGap

0 commit comments

Comments
 (0)