Skip to content

Commit 8053c79

Browse files
committed
add factory pattern
1 parent 6fbae2e commit 8053c79

File tree

7 files changed

+133
-4
lines changed

7 files changed

+133
-4
lines changed

Diff for: README.md

+62-1
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,70 @@ In this version we leverage context to build a `<Theme />` component that takes
7777

7878
There is one obvious concern with this approach. There could be name-clashing between libraries that use the same key in the `theme` object. This could be solved by following a namespace convention like prefixing the keys with the npm package name.
7979

80+
#### Factory Pattern
81+
82+
https://github.com/nikgraf/future-react-ui/tree/master/ui-lib/Factory
83+
84+
In this version we assume there is a package which includes a completely unstyled version of the UI kits while there is a second one which takes all the needed components and return themed components buy leveraging a factory function.
85+
86+
```
87+
/**
88+
* Returns a the provided component as themed component.
89+
*
90+
* Note: defaultProps could be useful for default special behavioural in
91+
* different ui libraries.
92+
*/
93+
export default (Component, theme, defaultProps) => (props) => {
94+
return <Component {...defaultProps} theme={theme} {...props} />;
95+
};
96+
```
97+
98+
For example these UI
99+
100+
##### Not styled components
101+
102+
- belle-core (unstyled kit)
103+
- elemental-core (unstyled kit)
104+
- react-toolbox-core (unstyled kit)
105+
- react-select (unstyled component)
106+
- react-autocomplete (unstyled component)
107+
- react-modal (unstyled component)
108+
109+
##### Themed
110+
111+
- belle (themed with belle style and based on belle-core)
112+
- belle-flat (themed with a flat theme and based on belle-core)
113+
- elemental (themed with the elemental theme and based on elemental-core)
114+
- react-toolbox (themed with the material theme and based on react-toolbox-core)
115+
- your-product-ui-lib (themed with your company style and based on belle-core[Toggle, Rating] & react-select & react-modal)
116+
- your-friends-product-ui-lib (themed with their company style and based on react-select & react-modal & react-autocomplete)
117+
118+
Usage:
119+
```
120+
import Hint from 'elemental/Hint';
121+
122+
const customTheme = {
123+
questionMark: 'custom-class-for-question-mark-gold',
124+
visibleContent: 'custom-class-visible-content',
125+
};
126+
127+
export default (props) => {
128+
return (
129+
<div>
130+
{/* Globally theme component */}
131+
<Hint />
132+
{/* Overwriting the theme locally for this case */}
133+
<Hint theme={theme}/>
134+
</div>
135+
);
136+
};
137+
```
138+
80139
## Temporary Conclusion
81140

82-
While the Theme component based idea is pretty powerful it's issues make me not having this as a default way of doing things. I'm not sure if there are some up/downsides between Module export vs Static property, but currently I'm leaning more to the static property implementation. If you have some ideas/feedback please reach out to me and let's discuss. (Github Issues might be best, but Twitter, Email, Skype, Hangout works as well)
141+
While the Theme component based idea is pretty powerful the issues make me not like it as a default. For some time I was convinced that Module export or Static property would be one of the winners. Right now I'm pretty convinced the Factory Pattern is the clear winner. It is super flexible and allows people to create their own company UI kits. They can easily provide their own styling as well as set other props as default suited to their needs. Another benefit is that you can easily get started with prototyping by using an already style version (e.g. belle-flat) and replace it later with your custom product style.
142+
143+
If you have some ideas/feedback please reach out to me and let's discuss. (Github Issues might be best, but Twitter, Email, Skype, Hangout works as well)
83144

84145
## License
85146

Diff for: app/index.html

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
.custom-class-for-question-mark-blue {
1818
color: blue;
1919
}
20+
.custom-class-for-question-mark-gold {
21+
color: gold;
22+
}
2023
 </style>
2124
</head>
2225
<body>

Diff for: app/index.js

+17-3
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,24 @@ Hint2.theme.questionMark = 'custom-class-for-question-mark-red';
2222
/* Context based theming */
2323
import Hint3 from 'ui-lib/Context/Hint';
2424
import Theme from 'ui-lib/Context/Theme';
25-
const theme = {
25+
const contextTheme = {
2626
hint: {
2727
questionMark: 'custom-class-for-question-mark-blue',
2828
visibleContent: 'custom-class-visible-content',
2929
},
3030
};
3131

32+
/* Factory based theming
33+
* also see /ui-lib/Factory/belle/Hint or /ui-lib/Factory/elemental/Hint
34+
*/
35+
import Hint4Unstyled from '../ui-lib/Factory/ui-core/Hint';
36+
import createComponent from '../ui-lib/Factory/react-themeable/createComponent';
37+
const theme = {
38+
questionMark: 'custom-class-for-question-mark-gold',
39+
visibleContent: 'custom-class-visible-content',
40+
};
41+
const Hint4 = createComponent(Hint, theme);
42+
3243
window.React = React;
3344

3445
const App = () => {
@@ -41,7 +52,6 @@ const App = () => {
4152

4253
<br /><br />
4354

44-
4555
<h2>Unstyled (globally patched classNames)</h2>
4656
<h3>Global theme as module export</h3>
4757
<Hint>Basic closed hint without styling.</Hint>
@@ -54,11 +64,15 @@ const App = () => {
5464

5565

5666
<h3>Global theme as Theme component leveraging context</h3>
57-
<Theme theme={theme}>
67+
<Theme theme={contextTheme}>
5868
<Hint3>Basic closed hint without styling.</Hint3>
5969
<Hint3 isOpen>Basic open hint without styling.</Hint3>
6070
</Theme>
6171

72+
73+
<h3>Factory to create Components with a provided Theme</h3>
74+
<Hint4>Basic closed hint without styling.</Hint4>
75+
<Hint4 isOpen>Basic open hint without styling.</Hint4>
6276
</div>
6377
);
6478
};

Diff for: ui-lib/Factory/belle/Hint.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Hint from '../ui-core/Hint';
2+
import createComponent from '../react-themeable/createComponent';
3+
4+
// An example of generated hashclasses by either JSS, CSSModules or any other
5+
// CSS libraries which generates classes.
6+
const belleTheme = {
7+
base: 'belle-hint-WQE73V',
8+
questionMark: 'belle-hint-FD7ASD',
9+
visibleContent: 'belle-hint-KASD34',
10+
hiddenContent: 'belle-hint-456BFD',
11+
};
12+
13+
export default createComponent(Hint, belleTheme);

Diff for: ui-lib/Factory/elemental/Hint.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Hint from '../ui-core/Hint';
2+
import createComponent from '../react-themeable/createComponent';
3+
4+
// An example of making use of Elemental's global css classes.
5+
const elementalTheme = {
6+
base: 'elemental-hint-wrapper',
7+
questionMark: 'elemental-hint-questionmark',
8+
visibleContent: 'elemental-hint-content',
9+
hiddenContent: 'elemental-hint-hidden-content',
10+
};
11+
12+
export default createComponent(Hint, elementalTheme);

Diff for: ui-lib/Factory/react-themeable/createComponent.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
3+
/**
4+
* Returns a the provided component as themed component.
5+
*
6+
* Note: defaultProps could be useful for default special behavioural in
7+
* different ui libraries.
8+
*/
9+
export default (Component, theme, defaultProps) => (props) => {
10+
return <Component {...defaultProps} theme={theme} {...props} />;
11+
};

Diff for: ui-lib/Factory/ui-core/Hint.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
3+
// This file would be an example of an unstyled component which can be used if
4+
// directly provided with a theme as an alternative to compose your custom UI kit
5+
// with react-themeable's createComponent.
6+
export default ({ children, isOpen = false, theme = {} }) => {
7+
return (
8+
<div className={theme.base}>
9+
<div className={theme.questionMark}>?</div>
10+
<div className={isOpen ? theme.visibleContent : theme.hiddenContent}>
11+
{children}
12+
</div>
13+
</div>
14+
);
15+
};

0 commit comments

Comments
 (0)