Skip to content

Commit d20e809

Browse files
authored
Emotion-based experiment for writing and composing component styles (#101)
* Emotion-based experiment for writing and composing component styles * Trying a different approach to button styles * Add LumiComponent abstraction over ReactComponent+defaults * Tag emotion * Emotion v2 * Add warnings to Components2 files * Add lumiElement operator (%) * WIP Border, Box & Slat components * Add lumiElement' for allowing style overrides * Add sibling border styles * Button, link, and plain Slat implementations; improve examples * Remove Firefox button outlines from elements with 'focusable' styles * Size example columns evenly * WIP * Make theming a bit more implicit * Hide first and last border in top/bottom bordered lists * wip * wip2 * Clean up/simplify api * Extract theme from component definitions/props * WIP * Add style labels to primary styles, differentiate primary styles from modifiers * docs * Add Link to components2 * Link-styled buttons * Fix button (2) loading state * Add missing S40 spacing * Clean up button (2) * Rearrange v2 examples * Adjust button modifiers for consistency with other components * Fix typo
1 parent 357060e commit d20e809

29 files changed

+1859
-74
lines changed

bower.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929
"purescript-prelude": "^4.0.1",
3030
"purescript-profunctor-lenses": ">=4.0.0 <7.0.0",
3131
"purescript-random": "^4.0.0",
32-
"purescript-react-basic": "^11.0.0",
33-
"purescript-react-basic-hooks": "^2.0.1",
34-
"purescript-react-dnd-basic": "^6.1.3",
32+
"purescript-react-basic": "^13.0.0",
33+
"purescript-react-basic-emotion": "^4.0.0",
34+
"purescript-react-basic-hooks": "^4.0.0",
35+
"purescript-react-dnd-basic": "^6.1.4",
3536
"purescript-record": ">= 1.0.0 < 3.0.0",
3637
"purescript-simple-json": ">=4.0.0 <7.0.0",
3738
"purescript-strings": "^4.0.0",

docs/App.jsx

+51-7
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,23 @@ const fromComponentPath = title => ({
5050
apiReference: `${pursuitBasePath}/docs/Lumi.Components.${title}`
5151
});
5252

53+
const fromComponentPathv2 = title => ({
54+
docs: Loadable({
55+
loader: () =>
56+
// Note: The string bits inside `require(...)` need to stay static strings, or Webpack
57+
// won't be able to infer which files need to be included in the bundle.
58+
import(`purs/Lumi.Components2.Examples.${title}`).then(module_ => () =>
59+
module_.docs
60+
),
61+
loading: () => null // these load quickly enough that a noisy loader makes it look slower
62+
}),
63+
title,
64+
path: `/v2/${changeCase.hyphen(title)}`,
65+
componentSource: `${repoSourceBasePath}/src/Lumi/Components2/${title}.purs`,
66+
exampleSource: `${repoSourceBasePath}/docs/Examples2/${title}.example.purs`,
67+
apiReference: `${pursuitBasePath}/docs/Lumi.Components2.${title}`
68+
});
69+
5370
const componentLoaders = [
5471
"Badge",
5572
"Border",
@@ -99,14 +116,20 @@ const componentLoaders = [
99116
"Wizard"
100117
].map(fromComponentPath);
101118

119+
const componentv2Loaders = ["Box", "Button", "ButtonGroup", "Link", "Slat"].map(
120+
fromComponentPathv2
121+
);
122+
102123
const App = () => {
103124
const [menuOpen, setMenuOpen] = useState(false);
104125
const toggleMenu = () => setMenuOpen(menuOpen => !menuOpen);
105126
const closeMenu = () => setMenuOpen(false);
106127

107128
const [components, setComponents] = useState(null);
129+
const [componentsv2, setComponentsv2] = useState(null);
108130
useEffect(() => {
109131
Promise.all(componentLoaders).then(setComponents);
132+
Promise.all(componentv2Loaders).then(setComponentsv2);
110133
}, []);
111134

112135
return (
@@ -116,11 +139,23 @@ const App = () => {
116139
{isMobile => (
117140
<Root>
118141
<Header isMobile={isMobile} toggleMenu={toggleMenu} />
119-
{components === null ? (
142+
{(components && componentsv2) == null ? (
120143
loader({})
121144
) : (
122145
<Content closeMenu={closeMenu}>
123146
<SideNav isMobile={isMobile} menuOpen={menuOpen}>
147+
<NavSubtitle>
148+
Components v2
149+
<div
150+
style={{
151+
fontSize: 12,
152+
color: colors.black5
153+
}}
154+
>
155+
(alpha)
156+
</div>
157+
</NavSubtitle>
158+
{componentsv2.map(renderNavLink)}
124159
<NavSubtitle>Components</NavSubtitle>
125160
{components.map(renderNavLink)}
126161
</SideNav>
@@ -129,6 +164,7 @@ const App = () => {
129164
<ErrorBoundary>
130165
<Switch>
131166
<Route exact path="/" render={() => h1_("Welcome")} />
167+
{componentsv2.map(renderRoute)}
132168
{components.map(renderRoute)}
133169
<Redirect to="/" />
134170
</Switch>
@@ -166,7 +202,11 @@ const renderRoute = component => (
166202
render={() =>
167203
column_([
168204
row({
169-
style: { alignItems: "center", marginBottom: "24px" },
205+
style: {
206+
alignItems: "center",
207+
marginBottom: "24px",
208+
flexWrap: "wrap"
209+
},
170210
children: [
171211
h1_(component.title),
172212
<a
@@ -233,7 +273,11 @@ const Root = ({ children }) =>
233273
const Title = ({ children }) => (
234274
<Link
235275
to="/"
236-
style={{ color: cssStringHSLA(colors.black1), textDecoration: "none" }}
276+
style={{
277+
color: cssStringHSLA(colors.black1),
278+
textDecoration: "none",
279+
whiteSpace: "nowrap"
280+
}}
237281
>
238282
{mainHeader_(children)}
239283
</Link>
@@ -244,7 +288,7 @@ const Version = ({ children }) =>
244288
...subsectionHeader,
245289
color: colorNames.black1,
246290
children: children,
247-
style: { marginLeft: 10 }
291+
style: { marginLeft: 10, whiteSpace: "nowrap" }
248292
});
249293

250294
const MenuLink = ({ toggleMenu }) =>
@@ -354,17 +398,17 @@ const SideNav = ({ children, isMobile, menuOpen }) => {
354398
const NavSubtitle = ({ children }) =>
355399
text({
356400
...sectionHeader,
357-
children: children,
401+
children,
358402
style: {
359403
fontSize: "16px",
360404
marginBottom: "10px",
361-
marginTop: "10px"
405+
marginTop: "20px"
362406
}
363407
});
364408

365409
const ExampleArea = ({ children }) =>
366410
column({
367-
children: children,
411+
children,
368412
style: {
369413
width: "100%",
370414
padding: "20px"

docs/Examples/Link.example.purs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
module Lumi.Components.Examlpes.Link where
1+
module Lumi.Components.Examples.Link where
22

33
import Prelude
4-
54
import Data.Maybe (Maybe(..))
65
import Effect.Console (log)
76
import Effect.Uncurried (mkEffectFn1)
@@ -21,16 +20,18 @@ docs =
2120
{ onClick: mkEffectFn1 \_ -> log "Propagated"
2221
, style: R.css { display: "flex", flexDirection: "column" }
2322
, children:
24-
[ link defaults
23+
[ link
24+
defaults
2525
{ href = URL "#/link"
2626
, navigate = pure $ log "link clicked"
2727
, text = body_ "Click here"
2828
}
29-
, link defaults
29+
, link
30+
defaults
3031
{ href = URL "#/input"
3132
, target = Just "_blank"
3233
, text = body_ "This should open in a new tab"
3334
}
34-
]
35+
]
3536
}
3637
]

docs/Examples2/Box.example.purs

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
module Lumi.Components2.Examples.Box where
2+
3+
import Prelude
4+
import Color.Scheme.MaterialDesign (blue, green, red)
5+
import Lumi.Components (lumiElement)
6+
import Lumi.Components.Example (example)
7+
import Lumi.Components.Spacing (Space(..), vspace)
8+
import Lumi.Components.Text (h2_, p_)
9+
import Lumi.Components2.Box (box)
10+
import Lumi.Styles.Box (FlexAlign(..), _alignSelf, _justify, _row)
11+
import React.Basic (JSX)
12+
import React.Basic.Emotion as E
13+
14+
docs :: JSX
15+
docs =
16+
let
17+
childBox color =
18+
lumiElement box
19+
_
20+
{ css =
21+
\_ ->
22+
E.css
23+
{ backgroundColor: E.color color
24+
, height: E.prop S40
25+
, width: E.prop S40
26+
}
27+
}
28+
29+
exampleContent =
30+
[ childBox red
31+
, childBox green
32+
, childBox blue
33+
]
34+
in
35+
lumiElement box
36+
_
37+
{ content =
38+
[ p_ "Box is a simple building block component. Lumi components default to building off of Box and generally expect their JSX arguments to be Box-compatible elements."
39+
, p_ "A Box is essentially a div which defaults to a flex column. The most common flex settings are available as prop modifiers. Nested boxes will also stretch to fill their given space by default. If a component shouldn't grow beyond a specific size under any circumstances, be sure to give it a max-width!"
40+
, vspace S24
41+
, h2_ "Defaults"
42+
, example $ lumiElement box
43+
$ _ { content = exampleContent }
44+
, h2_ "Row"
45+
, example $ lumiElement box
46+
$ _row
47+
$ _ { content = exampleContent }
48+
, h2_ "Align/justify"
49+
, example $ lumiElement box
50+
$ _row
51+
$ _alignSelf Stretch -- only necessary because `example` isn't a Box
52+
$ _justify End
53+
$ _ { content = exampleContent }
54+
, h2_ "Space evenly"
55+
, example $ lumiElement box
56+
$ _row
57+
$ _alignSelf Stretch -- only necessary because `example` isn't a Box
58+
$ _justify SpaceEvenly
59+
$ _ { content = exampleContent }
60+
]
61+
}

0 commit comments

Comments
 (0)