Skip to content

Commit 99bcd03

Browse files
author
Madeline Trotter
authored
Refactor Responsive components (#89)
* Refactor Responsive components - no more wrapping dom elements - avoid rendering unused jsx * Include pixel values of responsive breakpoints as exports
1 parent c7a2ab7 commit 99bcd03

File tree

8 files changed

+109
-74
lines changed

8 files changed

+109
-74
lines changed

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"purescript-profunctor-lenses": ">=4.0.0 <7.0.0",
3131
"purescript-random": "^4.0.0",
3232
"purescript-react-basic": "^11.0.0",
33-
"purescript-react-basic-hooks": "^1.0.1",
33+
"purescript-react-basic-hooks": "^2.0.1",
3434
"purescript-react-dnd-basic": "^6.1.3",
3535
"purescript-record": ">= 1.0.0 < 3.0.0",
3636
"purescript-simple-json": ">=4.0.0 <7.0.0",

docs/Examples/Form.example.purs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Data.Nullable as Nullable
1616
import Data.String as String
1717
import Data.String.NonEmpty (NonEmptyString, appendString, length, toString)
1818
import Data.Symbol (SProxy(..))
19+
import Effect (Effect)
1920
import Effect.Aff (Milliseconds(..), delay, error, throwError)
2021
import Effect.Class (liftEffect)
2122
import Effect.Random (randomRange)
@@ -38,7 +39,7 @@ import React.Basic.DOM (css)
3839
import React.Basic.DOM as R
3940
import React.Basic.DOM.Events (preventDefault)
4041
import React.Basic.Events (handler, handler_)
41-
import React.Basic.Hooks (JSX, CreateComponent, component, element, useState, (/\))
42+
import React.Basic.Hooks (JSX, ReactComponent, component, element, useState, (/\))
4243
import React.Basic.Hooks as React
4344
import Web.File.File as File
4445

@@ -97,12 +98,14 @@ metaForm = ado
9798
in unit
9899

99100
mkUserFormExample
100-
:: CreateComponent
101-
{ inlineTable :: Boolean
102-
, forceTopLabels :: Boolean
103-
, readonly :: Boolean
104-
, simulatePauses :: Boolean
105-
}
101+
:: Effect
102+
( ReactComponent
103+
{ inlineTable :: Boolean
104+
, forceTopLabels :: Boolean
105+
, readonly :: Boolean
106+
, simulatePauses :: Boolean
107+
}
108+
)
106109
mkUserFormExample = do
107110
component "UserFormExample" \props -> React.do
108111
userDialog /\ setUserDialog <- useState Nothing
@@ -520,3 +523,4 @@ addressForm = ado
520523
{ label: un State state
521524
, value: state
522525
}
526+

docs/Examples/Responsive.example.purs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,22 @@ import Prelude
44

55
import Lumi.Components.Column (column_)
66
import Lumi.Components.Example (example)
7-
import Lumi.Components.Responsive (desktop_, mobile_)
8-
import Lumi.Components.Text (body_, h2_)
7+
import Lumi.Components.Responsive (desktop, mobile, phone)
8+
import Lumi.Components.Text (body_, p_)
99
import React.Basic (JSX)
1010

1111
docs :: JSX
1212
docs =
13-
column_ $
14-
[ h2_ "Desktop and mobile"
15-
, example $
16-
column_
17-
[ mobile_
18-
[ body_ "Mobile: this text only is only visible on mobile-sized screens."
13+
column_
14+
$ [ p_ "The following component renders different values at each of these sizes: desktop, mobile, and phone"
15+
, p_ "Note that phone sized screens still report themselves as \"mobile\" as well."
16+
, example
17+
$ column_
18+
[ mobile \_ ->
19+
body_ "Mobile: this text only is only rendered on mobile-sized screens."
20+
, desktop \_ ->
21+
body_ "Desktop: this text only is only rendered on desktop-sized screens."
22+
, phone \_ ->
23+
body_ "Phone: this text only is only rendered on phone-sized screens."
1924
]
20-
, desktop_
21-
[ body_ "Desktop: this text only is only visible on desktop-sized screens."
22-
]
23-
]
24-
]
25+
]

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"react-dnd-html5-backend": "^2.6.0",
3737
"react-dom": "^16.6.1",
3838
"react-router": "^5.0.1",
39-
"react-router-dom": "^5.0.1"
39+
"react-router-dom": "^5.0.1",
40+
"use-media": "^1.4.0"
4041
},
4142
"devDependencies": {
4243
"@babel/core": "^7.5.5",

src/Lumi/Components/Responsive.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"use strict";
2+
3+
exports.useMedia_ = require("use-media").default;
Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,77 @@
11
module Lumi.Components.Responsive where
22

33
import Prelude
4+
import Effect (Effect)
5+
import Effect.Uncurried (EffectFn1, runEffectFn1)
6+
import Effect.Unsafe (unsafePerformEffect)
7+
import React.Basic.Hooks (Hook, JSX, ReactComponent, component, element, unsafeHook)
8+
import React.Basic.Hooks as React
49

5-
import JSS (JSS, jss)
6-
import React.Basic (JSX, element)
7-
import React.Basic.DOM (CSS, css, unsafeCreateDOMComponent)
8-
9-
type ResponsiveProps =
10-
{ style :: CSS
11-
, children :: Array JSX
12-
}
13-
14-
mobile :: ResponsiveProps -> JSX
15-
mobile = element (unsafeCreateDOMComponent "lumi-mobile")
16-
17-
mobile_ :: Array JSX -> JSX
18-
mobile_ = mobile <<< { style: css {}, children: _ }
19-
20-
desktop :: ResponsiveProps -> JSX
21-
desktop = element (unsafeCreateDOMComponent "lumi-desktop")
22-
23-
desktop_ :: Array JSX -> JSX
24-
desktop_ = desktop <<< { style: css {}, children: _ }
25-
26-
styles :: JSS
27-
styles = jss
28-
{ "@global":
29-
{ "lumi-desktop":
30-
{ "display": "flex"
31-
, "flex-shrink": "0"
32-
, "@media (max-width: 860px)":
33-
{ "display": "none !important"
34-
}
35-
}
36-
, "lumi-mobile":
37-
{ "display": "flex"
38-
, "flex-shrink": "0"
39-
, "@media (min-width: 861px)":
40-
{ "display": "none !important"
41-
}
42-
}
43-
}
44-
}
10+
foreign import data MediaQuery :: Type
11+
12+
foreign import data UseMediaQuery :: Type -> Type
13+
14+
useMedia :: String -> Hook UseMediaQuery Boolean
15+
useMedia mq = unsafeHook (runEffectFn1 useMedia_ mq)
16+
17+
foreign import useMedia_ :: EffectFn1 String Boolean
18+
19+
useIsPhone :: Hook UseMediaQuery Boolean
20+
useIsPhone = map not (useMedia ("(min-width: " <> show minWidthNonPhone <> "px)"))
21+
22+
useIsMobile :: Hook UseMediaQuery Boolean
23+
useIsMobile = map not useIsDesktop
24+
25+
useIsDesktop :: Hook UseMediaQuery Boolean
26+
useIsDesktop = useMedia ("(min-width: " <> show minWidthDesktop <> "px)")
27+
28+
-- | Prefer `useIsPhone` or `phone` to using this value
29+
-- | directly. Named in the negative because -- | this
30+
-- | width is the first size that is _not_ a phone and
31+
-- | trying to use this width as a "max-width" leaves
32+
-- | out fractional pixels (447.5px) which sometimes
33+
-- | occur on high-dpi displays.
34+
minWidthNonPhone :: Int
35+
minWidthNonPhone = 448
36+
37+
minWidthDesktop :: Int
38+
minWidthDesktop = 860
39+
40+
mobile :: (Unit -> JSX) -> JSX
41+
mobile = element c <<< { render: _ }
42+
-- WARNING: Don't add any arguments the `mobile` function!
43+
-- `c` must be fully applied at module creation!
44+
where
45+
c =
46+
unsafePerformEffect do
47+
mkMediaComponent "Mobile" useIsMobile
48+
49+
phone :: (Unit -> JSX) -> JSX
50+
phone = element c <<< { render: _ }
51+
-- WARNING: Don't add any arguments the `phone` function!
52+
-- `c` must be fully applied at module creation!
53+
where
54+
c =
55+
unsafePerformEffect do
56+
mkMediaComponent "Phone" useIsPhone
57+
58+
desktop :: (Unit -> JSX) -> JSX
59+
desktop = element c <<< { render: _ }
60+
-- WARNING: Don't add any arguments the `desktop` function!
61+
-- `c` must be fully applied at module creation!
62+
where
63+
c =
64+
unsafePerformEffect do
65+
mkMediaComponent "Desktop" useIsDesktop
66+
67+
mkMediaComponent ::
68+
String ->
69+
Hook UseMediaQuery Boolean ->
70+
Effect (ReactComponent { render :: Unit -> JSX })
71+
mkMediaComponent name umq = do
72+
component ("MediaQuery(" <> name <> ")") \{ render } -> React.do
73+
isMatch <- umq
74+
if isMatch then
75+
pure (render unit)
76+
else
77+
mempty

src/Lumi/Components/Styles.purs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import Lumi.Components.NativeSelect as NativeSelect
3636
import Lumi.Components.Navigation as Navigation
3737
import Lumi.Components.Pagination as Pagination
3838
import Lumi.Components.Pill as Pill
39-
import Lumi.Components.Responsive as Responsive
4039
import Lumi.Components.Row as Row
4140
import Lumi.Components.Select as Select
4241
import Lumi.Components.Slider as Slider
@@ -49,16 +48,6 @@ import Lumi.Components.Toast as Toast
4948
import Lumi.Components.Tooltip as Tooltip
5049
import Lumi.Components.Upload as Upload
5150

52-
-- /* Grid unit */
53-
-- $u: 4px;
54-
55-
-- /* Widths */
56-
-- $break-point-cinema: 1700px;
57-
-- $break-point-desktop: 1600px;
58-
-- $break-point-laptop: 1100px;
59-
-- $break-point-mobile: 860px;
60-
-- $break-point-phone: 448px;
61-
6251
attachGlobalComponentStyles :: Effect Unit
6352
attachGlobalComponentStyles = do
6453
jssInstance <- JSS.createInstance JSS.preset
@@ -92,7 +81,6 @@ attachGlobalComponentStyles = do
9281
, Navigation.styles
9382
, Pagination.styles
9483
, Pill.styles
95-
, Responsive.styles
9684
, Row.styles
9785
, Select.styles
9886
, Slider.styles

0 commit comments

Comments
 (0)