Created
June 27, 2019 13:51
-
-
Save MangelMaxime/973e4bf2f1db9e04d1b58a18b1c035cd to your computer and use it in GitHub Desktop.
Drag & Drop using Elmish and React hooks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, | |
body { | |
font-size: 16px; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module DragAndDrop | |
open Fable.Core | |
open Fable.Core.JsInterop | |
open Fable.React | |
open Fable.React.Props | |
open Browser | |
open Elmish | |
open Elmish.React | |
type Coords = | |
{ | |
X : float | |
Y : float | |
} | |
type Circle = | |
{ | |
X : float | |
Y : float | |
Coords : Coords | |
IsDragging : bool | |
} | |
type Model = Circle list | |
type Msg = | |
| StartDragging of index : int * pageX : float * pageY : float | |
| Dragging of index : int * pageX : float * pageY : float | |
| EndDragging of index : int | |
let init () = | |
[ | |
{ | |
X = 50. | |
Y = 50. | |
Coords = | |
{ | |
X = 0. | |
Y = 0. | |
} | |
IsDragging = false | |
} | |
{ | |
X = 150. | |
Y = 150. | |
Coords = | |
{ | |
X = 0. | |
Y = 0. | |
} | |
IsDragging = false | |
} | |
] | |
, Cmd.none | |
let update (msg : Msg) (currentModel : Model) = | |
match msg with | |
| StartDragging (rank, pageX, pageY) -> | |
currentModel | |
|> List.mapi (fun index circle -> | |
if rank <> index then | |
circle | |
else | |
{ circle with | |
Coords = | |
{ | |
X = pageX | |
Y = pageY | |
} | |
IsDragging = true | |
} | |
) | |
, Cmd.none | |
| Dragging (rank, pageX, pageY) -> | |
currentModel | |
|> List.mapi (fun index circle -> | |
if rank <> index then | |
circle | |
else | |
let xDiff = circle.Coords.X - pageX | |
let yDiff = circle.Coords.Y - pageY | |
{ circle with | |
X = circle.X - xDiff | |
Y = circle.Y - yDiff | |
Coords = | |
{ | |
X = pageX | |
Y = pageY | |
} | |
} | |
) | |
, Cmd.none | |
| EndDragging rank -> | |
currentModel | |
|> List.mapi (fun index circle -> | |
if rank <> index then | |
circle | |
else | |
{ circle with | |
IsDragging = false | |
} | |
) | |
, Cmd.none | |
type RenderCircleProps = | |
{ | |
Circle : Circle | |
Index : int | |
Dispatch : Dispatch<Msg> | |
key : string | |
} | |
let renderCircle = | |
FunctionComponent.Of( | |
fun (props : RenderCircleProps) -> | |
let handleMouseMove = | |
Hooks.useRef(fun (ev : Types.Event) -> | |
let ev = ev :?> Types.MouseEvent | |
Dragging (props.Index, ev.pageX, ev.pageY) | |
|> props.Dispatch | |
) | |
let color = | |
if props.Circle.IsDragging then | |
"lightblue" | |
else | |
"grey" | |
circle | |
[ | |
OnMouseUp (fun ev -> | |
document.removeEventListener("mousemove", handleMouseMove.current) | |
EndDragging props.Index | |
|> props.Dispatch | |
) | |
OnMouseDown (fun ev -> | |
StartDragging (props.Index, ev.pageX, ev.pageY) | |
|> props.Dispatch | |
document.addEventListener("mousemove", handleMouseMove.current) | |
) | |
Cx props.Circle.X | |
Cy props.Circle.Y | |
R 25. | |
SVGAttr.Fill color | |
SVGAttr.Stroke color | |
SVGAttr.StrokeWidth 1 | |
] | |
[ ] | |
, "Circle" | |
, equalsButFunctions | |
) | |
let view (model : Model) (dispatch : Msg -> unit) = | |
let circles = | |
model | |
|> List.mapi (fun index circle -> | |
renderCircle | |
{ | |
Circle = circle | |
Index = index | |
Dispatch = dispatch | |
key = "circle-" + string index | |
} | |
) | |
|> ofList | |
svg [ | |
Style | |
[ | |
Border "1px solid green" | |
Height "500px" | |
Width "calc(100% - 20px)" | |
Margin "10px" | |
] | |
] | |
[ circles ] | |
// App | |
Program.mkProgram init update view | |
|> Program.withReactSynchronous "elmish-app" | |
|> Program.run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'> | |
<script src="__HOST__/libs/react.production.min.js"></script> | |
<script src="__HOST__/libs/react-dom.production.min.js"></script> | |
<link rel="stylesheet" href="__HOST__/libs/css/bulma.min.css" /> | |
<link rel="stylesheet" href="__HOST__/libs/css/all.min.css" /> | |
</head> | |
<body class="app-container"> | |
<div id="elmish-app" class="elmish-app"></div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment