Skip to content

Commit 8515c09

Browse files
Add DragAndDropHalogenHooks (#152)
1 parent b9b4f2e commit 8515c09

File tree

8 files changed

+163
-0
lines changed

8 files changed

+163
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Running a web-compatible recipe:
9595
| | :heavy_check_mark: | [CatGifsReactHooks](recipes/CatGifsReactHooks) | A React port of the ["HTTP - Cat GIFs" Elm Example](https://elm-lang.org/examples/cat-gifs). |
9696
| :heavy_check_mark: | | [DiceCLI](recipes/DiceCLI) | This recipe shows how to create an interactive command line prompt that repeatedly generates a random number between 1 and 6. |
9797
| :heavy_check_mark: | :heavy_check_mark: | [DiceLog](recipes/DiceLog) | This recipe shows how to log a random integer between 1 and 6 (representing a roll of a die) in either the node.js or web browser console. |
98+
| | :heavy_check_mark: | [DragAndDropHalogenHooks](recipes/DragAndDropHalogenHooks) | A Halogen port of the ["Files - Drag-and-Drop" Elm Example](https://elm-lang.org/examples/drag-and-drop). |
9899
| | :heavy_check_mark: | [FileUploadHalogenHooks](recipes/FileUploadHalogenHooks) | A Halogen port of the ["Files - Upload" Elm Example](https://elm-lang.org/examples/upload). |
99100
| | :heavy_check_mark: | [FindDomElementJs](recipes/FindDomElementJs) | This recipe shows how to find elements in the DOM by using query selectors. |
100101
| | :heavy_check_mark: | [GroceriesHalogenHooks](recipes/GroceriesHalogenHooks) | A Halogen port of the ["HTML - Groceries" Elm Example](https://elm-lang.org/examples). |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/bower_components/
2+
/node_modules/
3+
/.pulp-cache/
4+
/output/
5+
/generated-docs/
6+
/.psc-package/
7+
/.psc*
8+
/.purs*
9+
/.psa*
10+
/.spago
11+
/web-dist/
12+
/prod-dist/
13+
/prod/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# DragAndDropHalogenHooks
2+
3+
A Halogen port of the ["Files - Drag-and-Drop" Elm Example](https://elm-lang.org/examples/drag-and-drop).
4+
5+
## Expected Behavior:
6+
7+
### Browser
8+
9+
When the user drags a file from their computer on top of the dashed area, the area will change colors, indicating that the file will be uploaded once the user drops it there. The user can also select a list of files by clicking on the button instead. The labels in the example show the names of the last-uploaded files (i.e. `files = `) and whether the user is currently dragging a file over the droppable area (i.e. `hover = `).
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{ name = "DragAndDropHalogenHooks"
2+
, dependencies =
3+
[ "console"
4+
, "effect"
5+
, "halogen-css"
6+
, "halogen-hooks"
7+
, "halogen-hooks-extra"
8+
, "interpolate"
9+
, "psci-support"
10+
, "random"
11+
]
12+
, packages = ../../packages.dhall
13+
, sources = [ "recipes/DragAndDropHalogenHooks/src/**/*.purs" ]
14+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
module DragAndDropHalogenHooks.Main where
2+
3+
import Prelude hiding (top)
4+
5+
import CSS (alignItems, backgroundColor, backgroundImage, border, borderRadius, color, column, darkgray, dashed, display, displayNone, flex, flexDirection, gray, height, justifyContent, lightgray, linearGradient, margin, padding, purple, px, solid, vGradient, width)
6+
import CSS as CSS
7+
import CSS.Common (center)
8+
import DOM.HTML.Indexed.InputType (InputType(..))
9+
import Data.Interpolate (i)
10+
import Data.Maybe (Maybe(..), maybe)
11+
import Data.String (toUpper)
12+
import Data.Tuple.Nested ((/\))
13+
import Effect (Effect)
14+
import Effect.Class (class MonadEffect)
15+
import Halogen (ClassName(..))
16+
import Halogen as H
17+
import Halogen.Aff as HA
18+
import Halogen.HTML as HH
19+
import Halogen.HTML.CSS as HC
20+
import Halogen.HTML.Events as HE
21+
import Halogen.HTML.Properties as HP
22+
import Halogen.Hooks as Hooks
23+
import Halogen.Hooks.Extra.Actions.Events (preventDefault)
24+
import Halogen.VDom.Driver (runUI)
25+
import Web.File.File as File
26+
import Web.File.FileList as FileList
27+
import Web.HTML.Event.DataTransfer as DataTransfer
28+
import Web.HTML.Event.DragEvent (dataTransfer)
29+
import Web.HTML.Event.DragEvent as DragEvent
30+
31+
main :: Effect Unit
32+
main =
33+
HA.runHalogenAff do
34+
body <- HA.awaitBody
35+
void $ runUI hookComponent Nothing body
36+
37+
hookComponent
38+
:: forall unusedQuery unusedInput unusedOutput anyMonad
39+
. MonadEffect anyMonad
40+
=> H.Component HH.HTML unusedQuery unusedInput unusedOutput anyMonad
41+
hookComponent = Hooks.component \_ _ -> Hooks.do
42+
hover /\ hoverIdx <- Hooks.useState false
43+
files /\ filesIdx <- Hooks.useState []
44+
Hooks.pure $
45+
HH.div
46+
[ HC.style do
47+
border dashed (px 6.0) $ if hover then purple else CSS.fromInt 0xcccccc
48+
borderRadius (px 20.0) (px 20.0) (px 20.0) (px 20.0)
49+
width (px 480.0)
50+
height (px 100.0)
51+
margin (px 100.0) (px 100.0) (px 100.0) (px 100.0)
52+
padding (px 20.0) (px 20.0) (px 20.0) (px 20.0)
53+
display flex
54+
flexDirection column
55+
justifyContent center
56+
alignItems center
57+
, HE.onDragEnter \e -> Just do
58+
preventDefault DragEvent.toEvent e
59+
Hooks.put hoverIdx true
60+
, HE.onDragOver \e -> Just do
61+
preventDefault DragEvent.toEvent e
62+
Hooks.put hoverIdx true
63+
, HE.onDragLeave \e -> Just do
64+
preventDefault DragEvent.toEvent e
65+
Hooks.put hoverIdx false
66+
, HE.onDrop \e -> Just do
67+
preventDefault DragEvent.toEvent e
68+
let
69+
mbFileList = DataTransfer.files $ dataTransfer e
70+
fileArray = maybe [] FileList.items mbFileList
71+
Hooks.put filesIdx fileArray
72+
]
73+
-- Note: Elm uses a button that, when clicked, will do the following:
74+
-- 1. create an input element
75+
-- 2. add it to the DOM
76+
-- 3. create a mouse event
77+
-- 4. dispatch the mouse event to the input element
78+
-- 5. (implication) file dialogue appears
79+
-- 6. user selects a file
80+
-- 7. input event handler runs a callback using user's selected file
81+
-- 8. input element is removed from DOM
82+
--
83+
-- The approach used below is based on this SO answer:
84+
-- https://stackoverflow.com/a/47094148
85+
[ HH.label
86+
[ HP.for "file-input" ]
87+
[ HH.div
88+
-- simulate button-like appearance
89+
[ HC.style do
90+
margin (px 4.0) (px 4.0) (px 4.0) (px 4.0)
91+
border solid (px 2.0) gray
92+
borderRadius (px 20.0) (px 20.0) (px 20.0) (px 20.0)
93+
padding (px 20.0) (px 20.0) (px 20.0) (px 20.0)
94+
, HP.class_ $ ClassName "otherCssNotInPurescript-Css"
95+
]
96+
[ HH.text "Upload images" ]
97+
]
98+
, HH.input
99+
[ HP.id_ "file-input"
100+
, HC.style $ display displayNone
101+
, HP.type_ InputFile
102+
, HP.multiple true
103+
, HE.onFileUpload \fileArray -> Just $ Hooks.put filesIdx fileArray
104+
]
105+
, HH.span
106+
[ HC.style $ color (CSS.fromInt 0xcccccc) ]
107+
[ HH.text $ i "{ files = "(show $ map File.name files)", hover = "(toUpper $ show hover)" }" ]
108+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.otherCssNotInPurescript-Css {
2+
background-color: lightblue;
3+
cursor: pointer;
4+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>DragAndDropHalogenHooks</title>
6+
<link rel="stylesheet" href="./index.css">
7+
</head>
8+
9+
<body>
10+
<script src="./index.js"></script>
11+
</body>
12+
</html>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"use strict";
2+
require("../../../output/DragAndDropHalogenHooks.Main/index.js").main();

0 commit comments

Comments
 (0)