@@ -3,18 +3,24 @@ module Yoga.Modal.Component where
3import Prelude
3import Prelude
4import CSS (JustifyContentValue(..), spaceBetween)
4import CSS (JustifyContentValue(..), spaceBetween)
5import Data.Foldable (foldMap)
5import Data.Foldable (foldMap)
6+import Data.Int (round, toNumber)
7+import Data.Interpolate (i)
6import Data.Maybe (Maybe)
8import Data.Maybe (Maybe)
9+import Data.Tuple.Nested ((/\))
7import Effect (Effect)
10import Effect (Effect)
8import Foreign.Object as Obj
11import Foreign.Object as Obj
12+import Math (pi, pow, sqrt)
9−import React.Basic (JSX)
13+import React.Basic (JSX, fragment)
14+import React.Basic.DOM (css)
10import React.Basic.DOM as R
15import React.Basic.DOM as R
11import React.Basic.DOM.Events (stopPropagation)
16import React.Basic.DOM.Events (stopPropagation)
12import React.Basic.DOM.SVG as SVG
17import React.Basic.DOM.SVG as SVG
13−import React.Basic.Events (EventHandler, handler, handler_)
18+import React.Basic.Events (handler, handler_)
14import React.Basic.Extra.Hooks.UseKeyUp (useKeyUp)
19import React.Basic.Extra.Hooks.UseKeyUp (useKeyUp)
15import React.Basic.Helpers (jsx)
20import React.Basic.Helpers (jsx)
16−import React.Basic.Hooks (ReactComponent, component, useEffect, useMemo, useState)
21+import React.Basic.Hooks (ReactComponent, component, element, useEffect, useState)
17import React.Basic.Hooks as React
22import React.Basic.Hooks as React
23+import React.Basic.Hooks.Spring (animatedPath, useSpring)
18import Record.Extra (pick)
24import Record.Extra (pick)
19import Yoga.Box.Component as Box
25import Yoga.Box.Component as Box
20import Yoga.Cluster.Component as Cluster
26import Yoga.Cluster.Component as Cluster
@@ -40,29 +46,48 @@ makeComponent = do
40 box <- Box.makeComponent
46 box <- Box.makeComponent
41 stack <- Stack.makeComponent
47 stack <- Stack.makeComponent
42 cluster <- Cluster.makeComponent
48 cluster <- Cluster.makeComponent
49+ closeIcon <- mkCloseIcon
43 useStyles <- makeStylesJSS Style.styles
50 useStyles <- makeStylesJSS Style.styles
44 component "Modal" \props -> React.do
51 component "Modal" \props -> React.do
45 cs <- useStyles (pick props)
52 cs <- useStyles (pick props)
46 useKeyUp 27 $ props.onClose ?|| pure unit
53 useKeyUp 27 $ props.onClose ?|| pure unit
54+ animationDone /\ modifyAnimationDone <- useState false
55+ overlayStyle <- useSpring $ const { opacity: 0.0 }
59+ { transform: "translate3d(-50%, -50%, 0) scale3d(0.2, 0.2, 0.0)"
60+ , config: { mass: 0.8, tension: 120, friction: 14 }
63+ overlayStyle.set { opacity: 1.0 }
65+ { transform: "translate3d(-50%, -50%, 0) scale3d(1.0, 1.0, 1.0)"
66+ , onRest: modifyAnimationDone (const true)
48 darkOverlay =
70 darkOverlay =
49 jsx imposter
71 jsx imposter
50− { className: cs.darkOverlay <> " " <> cs.fadeIn
72+ { className: cs.darkOverlay
51 , fixed: true
73 , fixed: true
52 , breakout: false
74 , breakout: false
53 , onClick: props.onClose ?|| mempty # handler_
75 , onClick: props.onClose ?|| mempty # handler_
76+ , style: css overlayStyle.style
56 dialogImposter =
80 dialogImposter =
57 jsx imposter
81 jsx imposter
58 { className: cs.dialog
82 { className: cs.dialog
59 , onClick: handler stopPropagation mempty
83 , onClick: handler stopPropagation mempty
60 , fixed: true
84 , fixed: true
85+ , style: css dialogStyle.style
63 dialogBox =
88 dialogBox =
65− { className: cs.box <> " " <> cs.zoomIn
90+ { className: cs.box
68 dialogBoxStack =
93 dialogBoxStack =
@@ -83,13 +108,20 @@ makeComponent = do
84 { className: cs.closeIcon
109 { className: cs.closeIcon
85 , children:
110 , children:
86− [ props.onClose # foldMap (closeIcon cs <<< handler_)
111+ [ props.onClose
115+ { className: cs.closeIcon, onClick, startAnimation: animationDone }
91− $ darkOverlay
123+ [ darkOverlay
92− [ dialogImposter
124+ , dialogImposter
93 [ dialogBox
125 [ dialogBox
94 [ dialogBoxStack
126 [ dialogBoxStack
95 [ titleCluster [ title ]
127 [ titleCluster [ title ]
@@ -99,27 +131,61 @@ makeComponent = do
102−closeIcon ∷ ∀ a. { closeIcon ∷ String | a } -> EventHandler -> JSX
134+mkCloseIcon ∷
103−closeIcon classes onClick =
135+ Effect
104− SVG.svg
136+ ( ReactComponent
105− { xmlns: "http://www.w3.org/2000/svg"
137+ { className ∷ String
138+ , onClick ∷ Effect Unit
139+ , startAnimation ∷ Boolean
143+ box <- Box.makeComponent
144+ component "CloseIcon" \{ className, onClick, startAnimation } -> React.do
145+ { style, set, stop } <-
148+ { strokeDasharray: "0, " <> show lineLen
153+ { strokeDasharray: "0," <> show circleCircumf
154+ , onRest: set { "strokeDasharray": i lineLen "," lineLen ∷ String }
156+ useEffect startAnimation do
157+ when startAnimation $ circleStyle.set { "strokeDasharray": (i circleCircumf "," circleCircumf) ∷ String }
106− , viewBox: "5 0 100 105"
161+ { viewBox: i "0 0 " width " " width
107− , fillRule: "evenodd"
108− , clipRule: "evenodd"
109− , strokeLinejoin: "round"
110− , strokeMiterlimit: "2"
111− , _data: Obj.singleton "testid" "close-icon-svg"
162+ , _data: Obj.singleton "testid" "close-icon-svg"
112− , onClick
163+ , onClick: handler_ onClick
113− , className: classes.closeIcon
164+ , fill: "none"
114− , children:
166+ , children:
115− [ SVG.g_
167+ [ animatedPath
116− [ SVG.path
168+ { d: i "M" padding "," padding "L" (width - padding) "," (width - padding)
117− { d: "M101.703,36.06c2.054,-2.054 2.054,-5.388 0,-7.442l-7.441,-7.441c-2.054,-2.054 -5.388,-2.054 -7.442,0l-65.643,65.643c-2.054,2.054 -2.054,5.388 0,7.442l7.441,7.441c2.054,2.054 5.388,2.054 7.442,0l65.643,-65.643Z"
169+ , style: css style
172+ { d: i "M" padding "," (width - padding) ",L" (width - padding) "," padding
119− , SVG.path
175+ , animatedPath
120− { d:
176+ { d: move <> line1 <> line2
121− "M86.82,101.703c2.054,2.054 5.388,2.054 7.442,0l7.441,-7.441c2.054,-2.054 2.054,-5.388 0,-7.442l-65.643,-65.643c-2.054,-2.054 -5.388,-2.054 -7.442,0l-7.441,7.441c-2.054,2.054 -2.054,5.388 0,7.442l65.643,65.643Z"
177+ , style: css circleStyle.style
182+ move = i "M " (cx - r) "," cx
183+ line1 = i " a " r "," r " 0 1,0 " (r * 2) ",0 "
184+ line2 = i " a " r "," r " 0 1,0 " (-(r * 2)) ",0 "
188+ r = round ((toNumber width * 0.8) / 2.0)
189+ circleCircumf = round $ 2.0 * pi * toNumber r
190+ aSquare = toNumber (width - (2 * padding)) `pow` 2.0
191+ lineLen = sqrt (aSquare * 2.0)