@@ -1,27 +1,95 @@
11module Yoga.React.Native.MacOS.SplitView
2− ( nativeSplitView
3− , NativeSplitViewAttributes
4− , DividerPosition
2+ ( splitView
53 ) where
64
7−import Prelude (Unit)
8−import Effect (Effect)
9−import React.Basic (ReactComponent)
10−import Yoga.React.Native.Attributes (BaseAttributes)
11−import Yoga.React.Native.Internal (FFINativeComponent, createNativeElement)
5+import Prelude
126
13−foreign import splitViewImpl :: forall props. ReactComponent props
7+import Data.Tuple.Nested ((/\))
8+import Effect.Uncurried (mkEffectFn2)
9+import Effect.Unsafe (unsafePerformEffect)
10+import React.Basic (JSX)
11+import React.Basic.Events (EventHandler, handler_)
12+import React.Basic.Hooks as React
13+import Unsafe.Coerce (unsafeCoerce)
14+import Yoga.React (component)
15+import Yoga.React.Native (view, tw)
16+import Yoga.React.Native.PanResponder as Pan
17+import Yoga.React.Native.Style as Style
1418
15−nativeSplitView :: FFINativeComponent NativeSplitViewAttributes
16−nativeSplitView = createNativeElement splitViewImpl
19+type SplitViewProps =
20+ { initialPosition :: Number
21+ , minPaneWidth :: Number
22+ , left :: JSX
23+ , right :: JSX
24+ }
1725
18−type DividerPosition = { position :: Number }
26+splitView :: SplitViewProps -> JSX
27+splitView = component "SplitView" \props -> React.do
28+ sidebarWidth /\ setSidebarWidth <- React.useState' props.initialPosition
29+ hovered /\ setHovered <- React.useState' false
30+ widthRef <- React.useRef props.initialPosition
31+ startWidthRef <- React.useRef 0.0
1932
20−type NativeSplitViewAttributes = BaseAttributes
21− ( initialPosition :: Number
22− , minPaneWidth :: Number
23− , dividerThickness :: Number
24− , dividerColor :: String
25− , dividerHoverColor :: String
26− , onDividerPosition :: DividerPosition -> Effect Unit
27− )
33+ React.useEffect sidebarWidth do
34+ React.writeRef widthRef sidebarWidth
35+ pure (pure unit)
36+
37+ pr <- React.useMemo unit \_ -> unsafePerformEffect $ Pan.create
38+ { onStartShouldSetPanResponder: mkEffectFn2 \_ _ -> pure true
39+ , onMoveShouldSetPanResponder: mkEffectFn2 \_ _ -> pure true
40+ , onPanResponderGrant: mkEffectFn2 \_ _ -> do
41+ w <- React.readRef widthRef
42+ React.writeRef startWidthRef w
43+ , onPanResponderMove: mkEffectFn2 \_ (gs :: Pan.GestureState) -> do
44+ sw <- React.readRef startWidthRef
45+ let newWidth = max props.minPaneWidth (sw + gs.dx)
46+ setSidebarWidth newWidth
47+ }
48+
49+ let handlers = toResponderHandlers (Pan.panHandlers pr)
50+ let dColor = if hovered then "rgba(128,128,128,0.6)" else "rgba(128,128,128,0.3)"
51+
52+ pure do
53+ view { style: tw "flex-1 flex-row" }
54+ [ view
55+ { style: Style.style { width: sidebarWidth, overflow: "hidden" }
56+ , allowsVibrancy: true
57+ }
58+ [ props.left ]
59+ , view
60+ { style: Style.style { width: 5.0, cursor: "col-resize", alignItems: "center", justifyContent: "center" }
61+ , onStartShouldSetResponder: handlers.onStartShouldSetResponder
62+ , onMoveShouldSetResponder: handlers.onMoveShouldSetResponder
63+ , onResponderGrant: handlers.onResponderGrant
64+ , onResponderMove: handlers.onResponderMove
65+ , onResponderRelease: handlers.onResponderRelease
66+ , onResponderTerminate: handlers.onResponderTerminate
67+ , onResponderTerminationRequest: handlers.onResponderTerminationRequest
68+ , onMouseEnter: handler_ (setHovered true)
69+ , onMouseLeave: handler_ (setHovered false)
70+ }
71+ [ view
72+ { style: Style.style { width: 1.0, height: "100%", backgroundColor: dColor }
73+ , pointerEvents: "none"
74+ }
75+ (mempty :: Array JSX)
76+ ]
77+ , view
78+ { style: tw "flex-1" <> Style.style { overflow: "hidden" } }
79+ [ props.right ]
80+ ]
81+
82+-- PanResponder.panHandlers returns responder-named event handlers
83+-- but the PureScript type uses pan-prefixed names, so we coerce
84+toResponderHandlers :: Pan.PanResponderHandlers -> ResponderHandlers
85+toResponderHandlers = unsafeCoerce
86+
87+type ResponderHandlers =
88+ { onStartShouldSetResponder :: EventHandler
89+ , onMoveShouldSetResponder :: EventHandler
90+ , onResponderGrant :: EventHandler
91+ , onResponderMove :: EventHandler
92+ , onResponderRelease :: EventHandler
93+ , onResponderTerminate :: EventHandler
94+ , onResponderTerminationRequest :: EventHandler
95+ }