mirror of
https://github.com/rowtype-yoga/ry-blocks.git
synced 2024-09-17 16:27:33 +03:00
UseMediaQuery
This commit is contained in:
parent
5b149c0fe9
commit
e3df4432ca
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -1,6 +1,6 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"workbench.colorTheme": "Halcyon",
|
||||
"workbench.colorTheme": "Night Owl Light",
|
||||
"search.useGlobalIgnoreFiles": true,
|
||||
"files.watcherExclude": {
|
||||
"**/.spago/**": true,
|
||||
@ -9,4 +9,4 @@
|
||||
"**/.storybook/**": true,
|
||||
"**/.github/**": true
|
||||
}
|
||||
}
|
||||
}
|
24
src/MediaQuery.js
Normal file
24
src/MediaQuery.js
Normal file
@ -0,0 +1,24 @@
|
||||
// This is for the browser tests to work
|
||||
// JSDOM does not have support for matchMedia
|
||||
// So we just pretend nothing every matches
|
||||
// And never invoke the listeners
|
||||
const stubMatchMedia = () => {
|
||||
if (window.matchMedia) return
|
||||
window.matchMedia = (name) => ({
|
||||
matches: false,
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {}
|
||||
})
|
||||
}
|
||||
export function matchMedia(string) {
|
||||
return (window) => () => {
|
||||
stubMatchMedia()
|
||||
return window.matchMedia(string)
|
||||
}
|
||||
}
|
||||
export function matches(matchMedia) {
|
||||
return () => {
|
||||
stubMatchMedia()
|
||||
return matchMedia.matches
|
||||
}
|
||||
}
|
9
src/MediaQuery.purs
Normal file
9
src/MediaQuery.purs
Normal file
@ -0,0 +1,9 @@
|
||||
module MediaQuery where
|
||||
|
||||
import Effect (Effect)
|
||||
import MediaQuery.Types (MediaQueryList)
|
||||
import Web.HTML (Window)
|
||||
|
||||
foreign import matchMedia ∷ String → Window → Effect MediaQueryList
|
||||
|
||||
foreign import matches ∷ MediaQueryList → Effect Boolean
|
9
src/MediaQuery/Types.purs
Normal file
9
src/MediaQuery/Types.purs
Normal file
@ -0,0 +1,9 @@
|
||||
module MediaQuery.Types where
|
||||
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Web.Event.EventTarget (EventTarget)
|
||||
|
||||
foreign import data MediaQueryList ∷ Type
|
||||
|
||||
toEventTarget ∷ MediaQueryList → EventTarget
|
||||
toEventTarget = unsafeCoerce
|
@ -1,15 +1,3 @@
|
||||
// This is for the browser tests to work
|
||||
// JSDOM does not have support for matchMedia
|
||||
// So we just pretend nothing every matches
|
||||
// And never invoke the listeners
|
||||
const stubMatchMedia = () => {
|
||||
if (window.matchMedia) return
|
||||
window.matchMedia = (name) => ({
|
||||
matches: false,
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {}
|
||||
})
|
||||
}
|
||||
|
||||
export function getComputedStyleImpl(el, window) {
|
||||
return window.getComputedStyle(el)
|
||||
@ -23,15 +11,3 @@ export function getElementStyle(el) {
|
||||
export function setStyleProperty(prop) {
|
||||
return (value) => (style) => () => style.setProperty(prop, value)
|
||||
}
|
||||
export function matchMedia(string) {
|
||||
return (window) => () => {
|
||||
stubMatchMedia()
|
||||
return window.matchMedia(string)
|
||||
}
|
||||
}
|
||||
export function matches(matchMedia) {
|
||||
return () => {
|
||||
stubMatchMedia()
|
||||
return matchMedia.matches
|
||||
}
|
||||
}
|
||||
|
@ -58,15 +58,6 @@ foreign import getElementStyle ∷ Element → Effect ElementStyle
|
||||
|
||||
foreign import setStyleProperty ∷ String → String → ElementStyle → Effect Unit
|
||||
|
||||
foreign import data MediaQueryList ∷ Type
|
||||
|
||||
foreign import matchMedia ∷ String → Window → Effect MediaQueryList
|
||||
|
||||
foreign import matches ∷ MediaQueryList → Effect Boolean
|
||||
|
||||
toEventTarget ∷ MediaQueryList → EventTarget
|
||||
toEventTarget = unsafeCoerce
|
||||
|
||||
getDocumentElement ∷ MaybeT Effect Element
|
||||
getDocumentElement = do
|
||||
win ← window # lift
|
||||
|
@ -10,13 +10,16 @@ import Yoga.Prelude.View
|
||||
|
||||
import Data.Array as Array
|
||||
import Fahrtwind as F
|
||||
import MediaQuery (matchMedia, matches)
|
||||
import MediaQuery.Types (MediaQueryList)
|
||||
import MediaQuery.Types as MediaQueryList
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Emotion as E
|
||||
import React.Basic.Hooks as React
|
||||
import Web.Event.EventTarget (addEventListener, eventListener, removeEventListener)
|
||||
import Web.HTML (window)
|
||||
import Web.HTML.Event.EventTypes as Event
|
||||
import Yoga.Block.Container.Style (DarkOrLightMode(..), matchMedia, matches, setDarkOrLightMode)
|
||||
import Yoga.Block.Container.Style (DarkOrLightMode(..), setDarkOrLightMode)
|
||||
import Yoga.Block.Container.Style as Styles
|
||||
|
||||
type PropsF f =
|
||||
@ -32,10 +35,10 @@ type Props =
|
||||
component ∷ ∀ p q. Union p q Props => ReactComponent { | p }
|
||||
component = rawComponent
|
||||
|
||||
mkPrefersDark ∷ Effect Styles.MediaQueryList
|
||||
mkPrefersDark ∷ Effect MediaQueryList
|
||||
mkPrefersDark = matchMedia "(prefers-color-scheme: dark)" =<< window
|
||||
|
||||
mkPrefersLight ∷ Effect Styles.MediaQueryList
|
||||
mkPrefersLight ∷ Effect MediaQueryList
|
||||
mkPrefersLight = matchMedia "(prefers-color-scheme: light)" =<< window
|
||||
|
||||
rawComponent ∷ ∀ p. ReactComponent { | p }
|
||||
@ -64,18 +67,18 @@ rawComponent =
|
||||
whenM (matches prefersDarkMediaQuery) do
|
||||
setSystemThemeVariant (Just DarkMode)
|
||||
notifySystemThemeChanged DarkMode
|
||||
addEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
|
||||
addEventListener Event.change darkModeListener true (MediaQueryList.toEventTarget prefersDarkMediaQuery)
|
||||
-- Light Mode listener
|
||||
lightModeListener <-
|
||||
eventListener \_ -> do
|
||||
whenM (matches prefersLightMediaQuery) do
|
||||
setSystemThemeVariant (Just LightMode)
|
||||
notifySystemThemeChanged LightMode
|
||||
addEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
|
||||
addEventListener Event.change lightModeListener true (Styles.toEventTarget prefersLightMediaQuery)
|
||||
addEventListener Event.change darkModeListener true (MediaQueryList.toEventTarget prefersDarkMediaQuery)
|
||||
addEventListener Event.change lightModeListener true (MediaQueryList.toEventTarget prefersLightMediaQuery)
|
||||
pure do
|
||||
removeEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
|
||||
removeEventListener Event.change lightModeListener true (Styles.toEventTarget prefersLightMediaQuery)
|
||||
removeEventListener Event.change darkModeListener true (MediaQueryList.toEventTarget prefersDarkMediaQuery)
|
||||
removeEventListener Event.change lightModeListener true (MediaQueryList.toEventTarget prefersLightMediaQuery)
|
||||
pure
|
||||
$ fragment
|
||||
[ R.div' </ { ref }
|
||||
|
36
src/Yoga/Block/Hook/UseMediaQuery.purs
Normal file
36
src/Yoga/Block/Hook/UseMediaQuery.purs
Normal file
@ -0,0 +1,36 @@
|
||||
module Yoga.Block.Hook.UseMediaQuery where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Newtype (class Newtype)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import MediaQuery (matchMedia, matches)
|
||||
import MediaQuery.Types as MQL
|
||||
import React.Basic.Hooks (UseEffect, UseState, Hook, coerceHook)
|
||||
import React.Basic.Hooks as React
|
||||
import Web.Event.EventTarget (addEventListener, eventListener, removeEventListener)
|
||||
import Web.HTML (window)
|
||||
import Web.HTML.Event.EventTypes as Event
|
||||
|
||||
newtype UseMediaQuery hooks = UseMediaQuery
|
||||
(UseEffect String (UseState Boolean hooks))
|
||||
|
||||
derive instance Newtype (UseMediaQuery hooks) _
|
||||
|
||||
useMediaQuery :: String -> Hook UseMediaQuery Boolean
|
||||
useMediaQuery query = coerceHook React.do
|
||||
let check = window >>= matchMedia query >>= matches
|
||||
|
||||
queryMatches /\ setMatches <-
|
||||
React.useState' (unsafePerformEffect check)
|
||||
|
||||
React.useEffect query do
|
||||
queryList <- window >>= matchMedia query
|
||||
let target = MQL.toEventTarget queryList
|
||||
listener <- eventListener (const (check >>= setMatches))
|
||||
addEventListener Event.change listener true target
|
||||
pure do
|
||||
removeEventListener Event.change listener true target
|
||||
|
||||
pure queryMatches
|
Loading…
Reference in New Issue
Block a user