Skip to content

Commit

Permalink
Add drag and drop support for fieldarray
Browse files Browse the repository at this point in the history
  • Loading branch information
luciodale committed Mar 28, 2021
1 parent a50ee84 commit 3c7a47a
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog
All notable changes to this project will be documented in this file.

## [2.4.0]
### Added
- Add support for fieldarray drag and drop (only top level fieldarrays)

## [2.3.0]
### Added
- Add support for nested field arrays
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ As at this state you must be dying of curiosity, I will dive right into the impl
#### In Deps

```clojure
fork {:mvn/version "2.3.0"}
fork {:mvn/version "2.4.0"}
```

or
Expand Down Expand Up @@ -556,6 +556,12 @@ What follows is a list of the fieldarray available handlers:
:fieldarray/set-handle-blur ;; same as the one in main props (see below)
:fieldarray/handle-change ;; (handle-change evt idx)
:fieldarray/handle-blur ;; (handle-blur evt idx)}
:fieldarray/current-target-idx ;; returns idx of droppable item location (current-target-idx :field-array-key)
:fieldarray/current-dragged-idx ;; returns idx of dragged item (current-dragged-idx :field-array-key)
:fieldarray/next-droppable-target? ;; true if hovered item is > than dragged (next-droppable-target? :field-array-key idx)
:fieldarray/prev-droppable-target? ;; true if hovered item is < than dragged (prev-droppable-target? :field-array-key idx)
:fieldarray/drag-and-drop-handlers ;; all drag and drop handlers
;; i.e. [:div (merge {:class ...} (drag-and-drop-handlers :field-array-key idx))]
```

### Does Fork do anything else for me?
Expand Down
39 changes: 33 additions & 6 deletions examples/fieldarray.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
[fork.re-frame :as fork]
[cljs.pprint :as pprint]))

;; Showing nested field arrays and drag and drop on top level field arrays

(defn field-array-2
[{:keys [normalize-name]}
{:fieldarray/keys [fields
Expand Down Expand Up @@ -45,16 +47,35 @@
remove
touched
handle-change
handle-blur]}]
handle-blur
current-dragged-idx
next-droppable-target
prev-droppable-target
drag-and-drop-handlers]}]
[:div
(doall
(->> fields
(map-indexed
(fn [idx field]
^{:key (str name idx)}
[:div {:style {:padding "1em"
:margin "1em"
:background "blue"}}
[:div
(merge
(drag-and-drop-handlers :field-array-1 idx)
{:style (cond-> {:padding "1em"
:margin "1em"
:background "blue"}

(= idx (current-dragged-idx :field-array-1))
(assoc :opacity 0.5)

(next-droppable-target :field-array-1 idx)
(assoc :border-bottom "10px solid black")

(prev-droppable-target :field-array-1 idx)
(assoc :border-top "10px solid black"))})
[:div "DRAG ME!"]
[:br]
[:br]
[:input
{:name (normalize-name :field-array-1/input)
:value (get field :field-array-1/input)
Expand Down Expand Up @@ -84,9 +105,15 @@
[fork/form {:state state
:keywordize-keys true
:initial-values {:field-array-1
[{:field-array-1/input "hello"
[{:field-array-1/input "hello1"
:field-array-2
[{:field-array-2/input "hello nested1"}]}
{:field-array-1/input "hello2"
:field-array-2
[{:field-array-2/input "hello nested2"}]}
{:field-array-1/input "hello3"
:field-array-2
[{:field-array-2/input "hello nested"}]}]}}
[{:field-array-2/input "hello nested3"}]}]}}
(fn [props]
[:form.manage-pages
[fork/field-array {:props props
Expand Down
2 changes: 1 addition & 1 deletion project.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(defproject fork "2.3.0"
(defproject fork "2.4.0"
:description "Reagent & Re-Frame form library"
:url "https://github.com/luciodale/fork"
:license {:name "MIT"}
Expand Down
74 changes: 72 additions & 2 deletions src/fork/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
[coll pos]
(vec (concat (subvec coll 0 pos) (subvec coll (inc pos)))))

(defn vec-insert-at
[coll pos element]
(vec (concat (subvec coll 0 pos) [element] (subvec coll pos))))

(defn touched
[state k]
(or (:attempted-submissions @state)
Expand Down Expand Up @@ -261,6 +265,40 @@
(or (:attempted-submissions @state)
(get (:touched @state) (conj vec-field-array-key idx input-key))))

(defn handle-drag-start
[state k idx]
(swap! state (fn [old-state]
(-> old-state
(dissoc :drag-and-drop)
(assoc-in [:drag-and-drop k :idx-of-item-being-dragged] idx)))))

(defn handle-drag-end
[state]
(swap! state dissoc :drag-and-drop))

(defn handle-drag-over [e] (.preventDefault e))

(defn handle-drag-enter
[state k idx]
(swap! state assoc-in [:drag-and-drop k :idx-of-element-droppable-location] idx))

(defn handle-drop
[state k vec-field-array-key]
(let [dragged-idx (get-in @state [:drag-and-drop k :idx-of-item-being-dragged])
dropped-idx (get-in @state [:drag-and-drop k :idx-of-element-droppable-location])]
(swap! state update-in (cons :values vec-field-array-key)
#(-> %
(vec-remove dragged-idx)
(vec-insert-at dropped-idx (get % dragged-idx))))))

(defn current-target-idx
[state k]
(some-> @state :drag-and-drop k :idx-of-element-droppable-location))

(defn current-dragged-idx
[state k]
(some-> @state :drag-and-drop k :idx-of-item-being-dragged))

(defn field-array
[props _]
(let [state (get-in props [:props :state])
Expand All @@ -282,7 +320,34 @@
(fn [m] (fieldarray-insert state vec-field-array-key m))
:touched
(fn [idx input-key] (fieldarray-touched
state vec-field-array-key idx input-key))}]
state vec-field-array-key idx input-key))
:current-target-idx
(fn [k] (current-target-idx state k))
:current-dragged-idx
(fn [k] (current-dragged-idx state k))
:next-droppable-target?
(fn [k idx]
(and (= idx (current-target-idx state k))
(> idx (current-dragged-idx state k))))
:prev-droppable-target?
(fn [k idx]
(and (= idx (current-target-idx state k))
(< idx (current-dragged-idx state k))))
:drag-and-drop-handlers
(fn [k idx]
(when (or (nil? (:drag-and-drop @state))
(current-dragged-idx state k))
{:draggable true
:on-drag-start
(fn [_] (handle-drag-start state k idx))
:on-drag-end
(fn [_] (handle-drag-end state))
:on-drag-over
(fn [evt] (handle-drag-over evt))
:on-drag-enter
(fn [_] (handle-drag-enter state k idx))
:on-drop
(fn [_] (handle-drop state k vec-field-array-key))}))}]
(fn [{:keys [props] :as args} component]
(let [fields (get-in (:values props) vec-field-array-key)]
[component props
Expand All @@ -295,4 +360,9 @@
:fieldarray/set-handle-change (:set-handle-change handlers)
:fieldarray/set-handle-blur (:set-handle-blur handlers)
:fieldarray/handle-change (:handle-change handlers)
:fieldarray/handle-blur (:handle-blur handlers)}]))))
:fieldarray/handle-blur (:handle-blur handlers)
:fieldarray/current-target-idx (:current-target-idx handlers)
:fieldarray/current-dragged-idx (:current-dragged-idx handlers)
:fieldarray/next-droppable-target? (:next-droppable-target? handlers)
:fieldarray/prev-droppable-target? (:prev-droppable-target? handlers)
:fieldarray/drag-and-drop-handlers (:drag-and-drop-handlers handlers)}]))))

0 comments on commit 3c7a47a

Please sign in to comment.