Skip to content

Commit 8dcca01

Browse files
author
Joe Reuter
authored
🪟🧹 Introduce flex component (#20944)
1 parent 2a83aec commit 8dcca01

17 files changed

+298
-58
lines changed

airbyte-webapp/src/components/CreateConnection/CreateConnectionNameField.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Field, FieldProps } from "formik";
22
import { FormattedMessage, useIntl } from "react-intl";
33

44
import { ControlLabels } from "components/LabeledControl";
5+
import { FlexContainer } from "components/ui/Flex";
56
import { Heading } from "components/ui/Heading";
67
import { Input } from "components/ui/Input";
78

@@ -16,7 +17,7 @@ export const CreateConnectionNameField = () => {
1617
<Section>
1718
<Field name="name">
1819
{({ field, meta }: FieldProps<string>) => (
19-
<div className={styles.flexRow}>
20+
<FlexContainer alignItems="flex-start">
2021
<div className={styles.leftFieldCol}>
2122
<ControlLabels
2223
className={styles.connectionLabel}
@@ -42,7 +43,7 @@ export const CreateConnectionNameField = () => {
4243
})}
4344
/>
4445
</div>
45-
</div>
46+
</FlexContainer>
4647
)}
4748
</Field>
4849
</Section>

airbyte-webapp/src/components/CreateConnection/DataResidency.module.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
@use "scss/variables";
22

3-
.flexRow {
4-
display: flex;
5-
flex-direction: row;
6-
justify-content: flex-start;
7-
align-items: flex-start;
8-
gap: variables.$spacing-md;
9-
}
10-
113
.leftFieldCol {
124
flex: 1;
135
max-width: 640px;

airbyte-webapp/src/components/CreateConnection/DataResidency.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FormattedMessage, useIntl } from "react-intl";
44

55
import { DataGeographyDropdown } from "components/common/DataGeographyDropdown";
66
import { ControlLabels } from "components/LabeledControl";
7+
import { FlexContainer } from "components/ui/Flex";
78

89
import { Geography } from "core/request/AirbyteClient";
910
import { useAvailableGeographies } from "packages/cloud/services/geographies/GeographiesService";
@@ -25,7 +26,7 @@ export const DataResidency: React.FC<DataResidencyProps> = ({ name = "geography"
2526
<Section title={formatMessage({ id: "connection.geographyTitle" })}>
2627
<Field name={name}>
2728
{({ field, form }: FieldProps<Geography>) => (
28-
<div className={styles.flexRow}>
29+
<FlexContainer alignItems="flex-start">
2930
<div className={styles.leftFieldCol}>
3031
<ControlLabels
3132
nextLine
@@ -57,7 +58,7 @@ export const DataResidency: React.FC<DataResidencyProps> = ({ name = "geography"
5758
onChange={(geography) => setFieldValue(name, geography)}
5859
/>
5960
</div>
60-
</div>
61+
</FlexContainer>
6162
)}
6263
</Field>
6364
</Section>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ComponentStory, ComponentMeta } from "@storybook/react";
2+
3+
import { FlexContainer } from "./FlexContainer";
4+
import { FlexItem } from "./FlexItem";
5+
6+
export default {
7+
title: "Ui/Flex",
8+
component: FlexContainer,
9+
} as ComponentMeta<typeof FlexContainer>;
10+
11+
const Template: ComponentStory<typeof FlexContainer> = (args) => <FlexContainer {...args} />;
12+
13+
const Item = ({ label, grow }: { label: string; grow?: boolean }) => (
14+
<FlexItem grow={grow} style={{ backgroundColor: "#dddddd", borderRadius: 5, padding: 20 }}>{`<FlexItem${
15+
grow ? " grow" : ""
16+
}>${label}</FlexItem>`}</FlexItem>
17+
);
18+
19+
export const NoGrow = Template.bind({});
20+
NoGrow.args = {
21+
children: (
22+
<>
23+
<Item label="first" />
24+
<Item label="second with a lot of content" />
25+
<Item label="third" />
26+
<Item label="forth" />
27+
</>
28+
),
29+
};
30+
31+
export const Grow = Template.bind({});
32+
Grow.args = {
33+
children: (
34+
<>
35+
<Item label="first" grow />
36+
<Item label="second" />
37+
</>
38+
),
39+
};
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
@use "scss/variables";
2+
3+
.container {
4+
display: flex;
5+
}
6+
7+
.directionRow {
8+
flex-direction: row;
9+
}
10+
11+
.directionColumn {
12+
flex-direction: column;
13+
}
14+
15+
.directionColumnReverse {
16+
flex-direction: column-reverse;
17+
}
18+
19+
.directionRowReverse {
20+
flex-direction: row-reverse;
21+
}
22+
23+
.gapXs {
24+
gap: variables.$spacing-xs;
25+
}
26+
27+
.gapSm {
28+
gap: variables.$spacing-sm;
29+
}
30+
31+
.gapMd {
32+
gap: variables.$spacing-md;
33+
}
34+
35+
.gapLg {
36+
gap: variables.$spacing-lg;
37+
}
38+
39+
.gapXl {
40+
gap: variables.$spacing-xl;
41+
}
42+
43+
.gap2xl {
44+
gap: variables.$spacing-2xl;
45+
}
46+
47+
.alignItemsStart {
48+
align-items: flex-start;
49+
}
50+
51+
.alignItemsEnd {
52+
align-items: flex-end;
53+
}
54+
55+
.alignItemsCenter {
56+
align-items: center;
57+
}
58+
59+
.alignItemsBaseline {
60+
align-items: baseline;
61+
}
62+
63+
.alignItemsStretch {
64+
align-items: stretch;
65+
}
66+
67+
.justifyContentStart {
68+
justify-content: flex-start;
69+
}
70+
71+
.justifyContentEnd {
72+
justify-content: flex-end;
73+
}
74+
75+
.justifyContentCenter {
76+
justify-content: center;
77+
}
78+
79+
.justifyContentBetween {
80+
justify-content: space-between;
81+
}
82+
83+
.justifyContentAround {
84+
justify-content: space-around;
85+
}
86+
87+
.justifyContentEvenly {
88+
justify-content: space-evenly;
89+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import classNames from "classnames";
2+
import React, { HTMLAttributes } from "react";
3+
4+
import styles from "./FlexContainer.module.scss";
5+
6+
interface FlexContainerProps {
7+
className?: string;
8+
/**
9+
* The flex-direction css property
10+
*/
11+
direction?: "row" | "column" | "row-reverse" | "column-reverse";
12+
/**
13+
* gap between the flex items - defaults to `md` if not provided. None means no gap is applied, the others map to the respective scss spacing variable.
14+
*/
15+
gap?: "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
16+
/**
17+
* The align-items css property
18+
*/
19+
alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
20+
/**
21+
* The justify-content css property
22+
*/
23+
justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
24+
}
25+
26+
/**
27+
* Renders a div element which layouts its children as flex items as specified by the props.
28+
* Children of a `FlexContainer` can but don't have to be `FlexItem` elements.
29+
*/
30+
export const FlexContainer: React.FC<React.PropsWithChildren<FlexContainerProps & HTMLAttributes<HTMLDivElement>>> = ({
31+
className,
32+
direction = "row",
33+
gap = "md",
34+
alignItems = "stretch",
35+
justifyContent = "flex-start",
36+
children,
37+
...otherProps
38+
}) => {
39+
const fullClassName = classNames(
40+
{
41+
[styles.directionRow]: direction === "row",
42+
[styles.directionColumn]: direction === "column",
43+
[styles.directionRowReverse]: direction === "row-reverse",
44+
[styles.directionColumnReverse]: direction === "column-reverse",
45+
[styles.gapXs]: gap === "xs",
46+
[styles.gapSm]: gap === "sm",
47+
[styles.gapMd]: gap === "md",
48+
[styles.gapLg]: gap === "lg",
49+
[styles.gapXl]: gap === "xl",
50+
[styles.gap2xl]: gap === "2xl",
51+
[styles.alignItemsStart]: alignItems === "flex-start",
52+
[styles.alignItemsEnd]: alignItems === "flex-end",
53+
[styles.alignItemsCenter]: alignItems === "center",
54+
[styles.alignItemsBaseline]: alignItems === "baseline",
55+
[styles.alignItemsStretch]: alignItems === "stretch",
56+
[styles.justifyContentStart]: justifyContent === "flex-start",
57+
[styles.justifyContentEnd]: justifyContent === "flex-end",
58+
[styles.justifyContentCenter]: justifyContent === "center",
59+
[styles.justifyContentBetween]: justifyContent === "space-between",
60+
[styles.justifyContentAround]: justifyContent === "space-around",
61+
[styles.justifyContentEvenly]: justifyContent === "space-evenly",
62+
},
63+
styles.container,
64+
className
65+
);
66+
67+
return (
68+
<div className={fullClassName} {...otherProps}>
69+
{children}
70+
</div>
71+
);
72+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@use "scss/variables";
2+
3+
.alignSelfStart {
4+
align-items: flex-end;
5+
}
6+
7+
.alignSelfEnd {
8+
align-items: flex-end;
9+
}
10+
11+
.alignSelfCenter {
12+
align-items: center;
13+
}
14+
15+
.alignSelfBaseline {
16+
align-items: baseline;
17+
}
18+
19+
.alignSelfStretch {
20+
align-items: stretch;
21+
}
22+
23+
.grow {
24+
flex-grow: 1;
25+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import classNames from "classnames";
2+
import React, { HTMLAttributes } from "react";
3+
4+
import styles from "./FlexItem.module.scss";
5+
6+
interface FlexItemProps {
7+
className?: string;
8+
/**
9+
* Sets `flex-grow` to 1 if truthy
10+
*/
11+
grow?: boolean;
12+
/**
13+
* The `align-self` css property
14+
*/
15+
alignSelf?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
16+
}
17+
18+
/**
19+
* Renders a div element which sets css properties for flex children as given by the props.
20+
* This component can be used within a `FlexContainer` parent if grow or self-align props should be set, but it can also be omitted
21+
* in case no special flex properties are required.
22+
*/
23+
export const FlexItem: React.FC<React.PropsWithChildren<FlexItemProps & HTMLAttributes<HTMLDivElement>>> = ({
24+
className,
25+
grow,
26+
alignSelf,
27+
children,
28+
...otherProps
29+
}) => {
30+
const fullClassName = classNames(
31+
{
32+
[styles.grow]: grow,
33+
[styles.alignSelfStart]: alignSelf === "flex-start",
34+
[styles.alignSelfEnd]: alignSelf === "flex-end",
35+
[styles.alignSelfCenter]: alignSelf === "center",
36+
[styles.alignSelfBaseline]: alignSelf === "baseline",
37+
[styles.alignSelfStretch]: alignSelf === "stretch",
38+
},
39+
className
40+
);
41+
42+
return (
43+
<div className={fullClassName} {...otherProps}>
44+
{children}
45+
</div>
46+
);
47+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { FlexContainer } from "./FlexContainer";
2+
export { FlexItem } from "./FlexItem";

airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionForm.module.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@
1010
pointer-events: none;
1111
}
1212

13-
.flexRow {
14-
display: flex;
15-
flex-direction: row;
16-
justify-content: flex-start;
17-
align-items: flex-start;
18-
gap: variables.$spacing-md;
19-
}
20-
2113
.leftFieldCol {
2214
flex: 1;
2315
max-width: 640px;

airbyte-webapp/src/views/Connection/ConnectionForm/ConnectionFormFields.module.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,6 @@
1111
pointer-events: none;
1212
}
1313

14-
.flexRow {
15-
display: flex;
16-
flex-direction: row;
17-
justify-content: flex-start;
18-
align-items: flex-start;
19-
gap: variables.$spacing-md;
20-
}
21-
2214
.leftFieldCol {
2315
flex: 1;
2416
max-width: 640px;

0 commit comments

Comments
 (0)