Skip to content

Commit 4a5225f

Browse files
committed
refactoring in progress
1 parent cb383c4 commit 4a5225f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3847
-75
lines changed

.storybook/config.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { configure } from "@storybook/react";
2+
3+
// Load stories dynamically
4+
const req = require.context("../src", true, /\.stories\.js$/);
5+
function loadStories() {
6+
req.keys().forEach(filename => req(filename));
7+
}
8+
9+
configure(loadStories, module);

README.md

+51-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,56 @@
11
## Design Systems with Styled System
22

3-
The goal of this exercise is to learn how to build a design system using Styled System.
3+
The goal of this exercise is to learn how to style React applications in an idomatic way.
4+
5+
# Exercise
6+
7+
## Part 1, Styled-Components and Storybook
8+
9+
### Input component
10+
11+
Use styled-components to implement the style for the `Input` component defined in `src/component-based-styling/components/Input/index`.
12+
13+
There should be three stories in `src/component-based-styling/components/Input/input.stories.js` that show the following 3 styles.
14+
15+
1. The default Input style should be:
16+
17+
```
18+
{
19+
padding: 5px;
20+
}
21+
```
22+
23+
2. The "error" style when Input receives the prop `error={true}`. The error style is the following:
24+
25+
```
26+
{
27+
padding: 5px;
28+
border: 1px solid red;
29+
}
30+
```
31+
32+
3. The "disabled" style when Input receives the prop `disabled={true}`. The disabled style is the following:
33+
34+
```
35+
{
36+
padding: 5px;
37+
border: 1px solid grey;
38+
background-color: grey;
39+
}
40+
```
41+
42+
4. What happens if we do this `<Input error disabled />`? What is the border color of the input? Should we improve that? How? Discuss with your peers.
43+
44+
#### Button component
45+
46+
Task 1. Using styled-components, implement some Bootstrap button styles in `src/component-based-styling/components/Form/Button` using the styles defined in that file. Then create the following stories in `src/component-based-styling/components/button/button.stories.js`:
47+
48+
1. Default, no props required.
49+
2. Button primary when prop `primary={true}`
50+
3. Button large when prop `large={true}`
51+
4. Button block when prop `block={true}`
52+
53+
Bonus question. The default <Button /> (meaning no props) doesn't have a border, why? Should we fix that? How would you fix it? Discuss with your peers. Hint, what's the default style for the [Bootstrap button](https://getbootstrap.com/docs/4.3/components/buttons/)?
454

555
## Prerequisites
656

package.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"react": "^16.8.6",
77
"react-dom": "^16.8.6",
8+
"react-helmet": "^5.2.1",
89
"react-router": "^5.0.1",
910
"react-router-dom": "^5.0.1",
1011
"react-scripts": "3.0.1",
@@ -15,7 +16,8 @@
1516
"start": "react-scripts start",
1617
"build": "react-scripts build",
1718
"test": "react-scripts test",
18-
"eject": "react-scripts eject"
19+
"eject": "react-scripts eject",
20+
"storybook": "start-storybook -p 9001 -c .storybook"
1921
},
2022
"eslintConfig": {
2123
"extends": "react-app"
@@ -31,5 +33,8 @@
3133
"last 1 firefox version",
3234
"last 1 safari version"
3335
]
36+
},
37+
"devDependencies": {
38+
"@storybook/react": "^5.1.11"
3439
}
3540
}

src/App.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React from "react";
22
import { Switch, Route, Link } from "react-router-dom";
33

4-
import MyFirstBox from "./pages/MyFirstBox";
5-
import Typography from "./pages/Typography";
6-
import Color from "./pages/Color";
7-
import Spacing from "./pages/Spacing";
8-
import Flex from "./pages/Flex";
9-
import MyBoxIsNotADiv from "./pages/MyBoxIsNotADiv";
10-
import ResponsiveStyles from "./pages/ResponsiveStyles";
11-
import VariantCSSObject from "./pages/VariantCSSObject";
4+
import MyFirstBox from "./pages/design-system/MyFirstBox";
5+
import Typography from "./pages/design-system/Typography";
6+
import Color from "./pages/design-system/Color";
7+
import Spacing from "./pages/design-system/Spacing";
8+
import Flex from "./pages/design-system/Flex";
9+
import MyBoxIsNotADiv from "./pages/design-system/MyBoxIsNotADiv";
10+
import ResponsiveStyles from "./pages/design-system/ResponsiveStyles";
11+
import VariantCSSObject from "./pages/design-system/VariantCSSObject";
1212

1313
const App = () => (
1414
<div style={{ display: "flex" }}>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from "react";
2+
import { Helmet } from "react-helmet";
3+
4+
import RadioGroup from "./example/RadioGroup";
5+
//import RadioOption from "./example/RadioOption";
6+
7+
const Page = () => (
8+
<React.Fragment>
9+
<Helmet>
10+
<link
11+
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
12+
rel="stylesheet"
13+
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
14+
crossorigin="anonymous"
15+
/>
16+
</Helmet>
17+
<div>
18+
<h2>Compound Components</h2>
19+
<h3>Example</h3>
20+
<p>The following components are a compound component:</p>
21+
<p>
22+
<em>
23+
Folder:
24+
src/advanced-ui-patterns/compound-components/example/RadioGroup.jsx
25+
and RadioOption.jsx
26+
</em>
27+
</p>
28+
<div>
29+
<p>What is a compound component?</p>
30+
<RadioGroup
31+
defaultValue="fm"
32+
onChange={radioValue => {
33+
console.log("radioValue", radioValue);
34+
}}
35+
>
36+
<RadioGroup.Option value="1">
37+
A component that returns another component
38+
</RadioGroup.Option>
39+
<RadioGroup.Option value="2">
40+
A function that returns a component
41+
</RadioGroup.Option>
42+
<RadioGroup.Option value="3">
43+
A component that passes props dinamically to its children
44+
</RadioGroup.Option>
45+
<RadioGroup.Option value="4">
46+
I have no idea so I'll wait for my pair to answer
47+
</RadioGroup.Option>
48+
<RadioGroup.Option value="5">
49+
... still waiting for my peers to answer, I think neither of us have
50+
any clue
51+
</RadioGroup.Option>
52+
</RadioGroup>
53+
</div>
54+
<h3>Exercise</h3>
55+
<p>
56+
Refactor the Tabs component in
57+
src/advanced-ui-patterns/compound-components/exercise/ so we don't have
58+
to pass explicitly the state.
59+
</p>
60+
<hr />
61+
</div>
62+
</React.Fragment>
63+
);
64+
65+
export default Page;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
4+
class RadioGroup extends React.Component {
5+
constructor(props) {
6+
super();
7+
this.state = {
8+
value: props.defaultValue
9+
};
10+
}
11+
12+
select(value) {
13+
this.setState({ value }, () => {
14+
this.props.onChange(this.state.value);
15+
});
16+
}
17+
18+
render() {
19+
const children = React.Children.map(this.props.children, child =>
20+
React.cloneElement(child, {
21+
isSelected: child.props.value === this.state.value,
22+
onClick: () => this.select(child.props.value)
23+
})
24+
);
25+
26+
return <div>{children}</div>;
27+
}
28+
}
29+
30+
const RadioOption = ({ onClick, isSelected, children }) => (
31+
<div onClick={onClick}>
32+
<span
33+
className={isSelected ? "fa fa-circle" : "fa fa-circle-o"}
34+
style={{ paddingRight: "10px", cursor: "pointer" }}
35+
/>
36+
{children}
37+
</div>
38+
);
39+
40+
RadioGroup.Option = RadioOption;
41+
42+
RadioGroup.propTypes = {
43+
defaultValue: PropTypes.string
44+
};
45+
46+
export default RadioGroup;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
4+
const RadioOption = ({ onClick, isSelected, children }) => (
5+
<div onClick={ onClick }>
6+
<span
7+
className={ isSelected? 'fa fa-circle': 'fa fa-circle-o' }
8+
style={ {paddingRight: '10px', cursor: 'pointer'} }
9+
/>
10+
{ children }
11+
</div>
12+
)
13+
14+
RadioOption.propTypes = {
15+
value: PropTypes.string
16+
}
17+
18+
export default RadioOption

src/advanced-ui-patterns/compound-components/exercise/Tabs.js

Whitespace-only changes.
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from "react";
2+
import Example from "./example";
3+
import Exercise from "./exercise";
4+
5+
const Page = () => (
6+
<div>
7+
<h2>Context</h2>
8+
<h3>Example</h3>
9+
<p>
10+
<a
11+
target="_blank"
12+
href="https://github.com/reactjsacademy/advanced-react-patterns/tree/master/src/components/patterns/Context/example"
13+
>
14+
source code exercise branch &#187;
15+
</a>
16+
</p>
17+
<Example />
18+
<p>
19+
<em>Folder: src/components/patterns/Context/example/Modal.jsx</em>
20+
</p>
21+
<h3>Exercise</h3>
22+
<p>
23+
<a
24+
target="_blank"
25+
href="https://github.com/reactjsacademy/advanced-react-patterns/tree/master/src/components/patterns/Context/exercise"
26+
>
27+
source code exercise branch &#187;
28+
</a>
29+
</p>
30+
<p>
31+
We are going to create a <strong>Theme Switcher</strong> component using
32+
Context. If you see{" "}
33+
<code>src/components/patterns/Context/exercise/theme.js</code>, there are{" "}
34+
<strong>2 themes defined</strong>. You should be able to toggle between
35+
these 2 themes.
36+
</p>
37+
<p>This component should:</p>
38+
<ul>
39+
<li>
40+
Track the current <code>theme</code> in the state
41+
</li>
42+
<li>Implement a fucntion to toggle the theme</li>
43+
<li>
44+
pass the current theme to the <code>ThemeProvider</code> from{" "}
45+
<code>styled-components</code>
46+
</li>
47+
</ul>
48+
<p>
49+
In order to check if the theme is actually changing, you can refactor the{" "}
50+
<code>Hero</code> component (
51+
<code>src/components/patterns/Context/exercise/components/Hero.jsx</code>)
52+
</p>
53+
<p>
54+
Also, in order to toggle the theme, you need to use the{" "}
55+
<code>ThemeContext.Consumer</code> in order to get access to the function
56+
that toggles the state in your ThemeProvider.
57+
</p>
58+
<Exercise />
59+
<hr />
60+
<h3>Bonus Exercise</h3>
61+
<p>
62+
<a
63+
target="_blank"
64+
href="https://github.com/reactjsacademy/advanced-react-patterns/tree/master/src/components/patterns/Context/xbonus"
65+
>
66+
source code exercise branch &#187;
67+
</a>
68+
</p>
69+
<p>
70+
Implement the Redux Provider in
71+
<code>src/components/patterns/Context/xbonus/Provider.js</code>. Once
72+
implemented, use it in Root.js
73+
</p>
74+
</div>
75+
);
76+
77+
export default Page;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import { Modal as BootstrapModal } from "react-bootstrap";
4+
5+
export const ModalContext = React.createContext();
6+
7+
class Modal extends React.Component {
8+
constructor() {
9+
super();
10+
11+
this.state = {
12+
isOpen: false,
13+
content: null,
14+
backdrop: true
15+
};
16+
}
17+
18+
showModal = (content, backdrop = true) => {
19+
this.setState({
20+
content,
21+
isOpen: true,
22+
backdrop
23+
});
24+
};
25+
26+
hideModal = () => {
27+
this.setState({ isOpen: false });
28+
};
29+
30+
render() {
31+
const { showModal, hideModal, state, props } = this;
32+
const { Provider } = ModalContext;
33+
34+
return (
35+
<Provider value={{ ...state, showModal, hideModal }}>
36+
<BootstrapModal
37+
backdrop={state.backdrop}
38+
show={state.isOpen}
39+
onHide={hideModal}
40+
>
41+
{state.content}
42+
</BootstrapModal>
43+
{props.children}
44+
</Provider>
45+
);
46+
}
47+
}
48+
49+
Modal.propTypes = {
50+
children: PropTypes.object
51+
};
52+
53+
export default Modal;

0 commit comments

Comments
 (0)