@@ -8,13 +8,18 @@ import Effect.Unsafe (unsafePerformEffect)
8import React.Basic.DOM as R
8import React.Basic.DOM as R
9import React.Basic.Emotion as E
9import React.Basic.Emotion as E
10import React.Basic.Hooks (reactComponent)
10import React.Basic.Hooks (reactComponent)
11+import React.Basic.Hooks as React
11import Unsafe.Coerce (unsafeCoerce)
12import Unsafe.Coerce (unsafeCoerce)
13+import Web.Event.EventTarget (addEventListener, eventListener, removeEventListener)
14+import Web.HTML (window)
15+import Web.HTML.Event.EventTypes as Event
12−import Yoga.Block.Container.Style (DarkOrLightMode)
16+import Yoga.Block.Container.Style (DarkOrLightMode(..), matchMedia, matches, setDarkOrLightMode)
13import Yoga.Block.Container.Style as Styles
17import Yoga.Block.Container.Style as Styles
15type PropsF f =
19type PropsF f =
16 ( content ∷ JSX
20 ( content ∷ JSX
17 , themeVariant ∷ f (Maybe DarkOrLightMode)
21 , themeVariant ∷ f (Maybe DarkOrLightMode)
22+ , onPreferredSystemThemeChange ∷ f (DarkOrLightMode -> Effect Unit)
20type Props =
25type Props =
@@ -23,20 +28,62 @@ type Props =
23component ∷ ∀ p q. Union p q Props => ReactComponent { | p }
28component ∷ ∀ p q. Union p q Props => ReactComponent { | p }
24component = rawComponent
29component = rawComponent
31+mkPrefersDark ∷ Effect Styles.MediaQueryList
32+mkPrefersDark = matchMedia "(prefers-color-scheme: dark)" =<< window
34+mkPrefersLight ∷ Effect Styles.MediaQueryList
35+mkPrefersLight = matchMedia "(prefers-color-scheme: light)" =<< window
26rawComponent ∷ ∀ p. ReactComponent { | p }
37rawComponent ∷ ∀ p. ReactComponent { | p }
27rawComponent =
38rawComponent =
28 unsafeCoerce
39 unsafeCoerce
29 $ unsafePerformEffect
40 $ unsafePerformEffect
30− $ reactComponent "Container" \({ content, themeVariant } ∷ { | PropsF OptionalProp }) -> React.do
41+ $ reactComponent "Container" \(props@{ content } ∷ { | PropsF OptionalProp }) -> React.do
42+ let propsThemeVariant = props.themeVariant # opToMaybe # join
43+ let notifySystemThemeChanged = props.onPreferredSystemThemeChange ?|| mempty
44+ systemThemeVariant /\ setSystemThemeVariant <- React.useState' Nothing
45+ useEffect propsThemeVariant do
46+ for_ propsThemeVariant setDarkOrLightMode
49+ prefersDarkMediaQuery <- mkPrefersDark
50+ prefersLightMediaQuery <- mkPrefersLight
51+ -- Init system preference
52+ whenM (matches prefersDarkMediaQuery) do
53+ setSystemThemeVariant (Just DarkMode)
54+ notifySystemThemeChanged DarkMode
55+ whenM (matches prefersLightMediaQuery) do
56+ setSystemThemeVariant (Just LightMode)
57+ notifySystemThemeChanged LightMode
58+ -- Dark Mode listener
60+ eventListener \_ -> do
61+ whenM (matches prefersDarkMediaQuery) do
62+ setSystemThemeVariant (Just DarkMode)
63+ notifySystemThemeChanged DarkMode
64+ addEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
65+ -- Light Mode listener
67+ eventListener \_ -> do
68+ whenM (matches prefersLightMediaQuery) do
69+ setSystemThemeVariant (Just LightMode)
70+ notifySystemThemeChanged LightMode
71+ addEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
72+ addEventListener Event.change lightModeListener true (Styles.toEventTarget prefersLightMediaQuery)
74+ removeEventListener Event.change darkModeListener true (Styles.toEventTarget prefersDarkMediaQuery)
75+ removeEventListener Event.change lightModeListener true (Styles.toEventTarget prefersLightMediaQuery)
33 $ Array.cons
78 $ Array.cons
34 ( element E.global
79 ( element E.global
36− case opToMaybe themeVariant # join of
81+ case propsThemeVariant, systemThemeVariant of
37− Nothing -> Styles.global
82+ Nothing, Nothing -> Styles.global
38− Just Styles.DarkMode -> Styles.darkMode
83+ Just Styles.DarkMode, _ -> Styles.darkMode
39− Just Styles.LightMode -> Styles.lightMode
84+ Just Styles.LightMode, _ -> Styles.lightMode
85+ Nothing, Just DarkMode -> Styles.darkMode
86+ Nothing, Just LightMode -> Styles.lightMode