Merge pull request #3236 from penpot/akshay-gupta7-akshayg7-add-shadows-reorder

🎉 Add ability to change shadows' order and place new shadows at first
This commit is contained in:
Eva Marco 2023-05-24 13:42:52 +02:00 committed by GitHub
commit df1c56da2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 305 additions and 193 deletions

View file

@ -24,6 +24,7 @@
- Removed sizing variables from radius (by @ondrejkonec) [Github #3184](https://github.com/penpot/penpot/pull/3184) - Removed sizing variables from radius (by @ondrejkonec) [Github #3184](https://github.com/penpot/penpot/pull/3184)
- Dashboard search, set focus after shortcut (by @akshay-gupta7) [Github #3196](https://github.com/penpot/penpot/pull/3196) - Dashboard search, set focus after shortcut (by @akshay-gupta7) [Github #3196](https://github.com/penpot/penpot/pull/3196)
- Library name dropdown arrow is overlapped by library name (by @ondrejkonec) [Taiga #5200](https://tree.taiga.io/project/penpot/issue/5200) - Library name dropdown arrow is overlapped by library name (by @ondrejkonec) [Taiga #5200](https://tree.taiga.io/project/penpot/issue/5200)
- Reorder shadows (by @akshay-gupta7) [Github #3236](https://github.com/penpot/penpot/pull/3236)
## 1.18.4 ## 1.18.4

View file

@ -786,7 +786,8 @@
} }
} }
.grid-option { .grid-option,
.shadow-option {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
.advanced-options { .advanced-options {
.row-flex { .row-flex {
@ -797,6 +798,15 @@
position: absolute; position: absolute;
top: 12px; top: 12px;
} }
.element-set-actions-button {
min-width: auto;
min-height: auto;
padding-right: 10px;
svg {
width: 12px;
height: 12px;
}
}
} }
} }
@ -807,7 +817,8 @@
margin-left: 0.25rem; margin-left: 0.25rem;
} }
.element-set-content .grid-option-main { .element-set-content .grid-option-main,
.element-set-content .shadow-option-main {
align-items: center; align-items: center;
display: flex; display: flex;
padding: 0.3rem 0; padding: 0.3rem 0;
@ -857,11 +868,13 @@
} }
} }
.grid-option-main-actions { .grid-option-main-actions,
.shadow-option-main-actions {
display: flex; display: flex;
visibility: hidden; visibility: hidden;
.grid-option:hover & { .grid-option:hover &,
.shadow-option:hover & {
visibility: visible; visibility: visible;
} }
} }

View file

@ -10,6 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.schema :as sm]
[app.main.broadcast :as mbc] [app.main.broadcast :as mbc]
[app.main.data.modal :as md] [app.main.data.modal :as md]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
@ -200,7 +201,6 @@
(if (= (:type shape) :frame) (if (= (:type shape) :frame)
(d/merge shape attrs) (d/merge shape attrs)
shape)))))))) shape))))))))
(defn change-stroke (defn change-stroke
[ids attrs index] [ids attrs index]
(ptk/reify ::change-stroke (ptk/reify ::change-stroke
@ -224,7 +224,9 @@
attrs (merge attrs color-attrs)] attrs (merge attrs color-attrs)]
(rx/of (dch/update-shapes ids (fn [shape] (rx/of (dch/update-shapes
ids
(fn [shape]
(let [new-attrs (merge (get-in shape [:strokes index]) attrs) (let [new-attrs (merge (get-in shape [:strokes index]) attrs)
new-attrs (cond-> new-attrs new-attrs (cond-> new-attrs
(not (contains? new-attrs :stroke-width)) (not (contains? new-attrs :stroke-width))
@ -238,9 +240,11 @@
:always :always
(d/without-nils))] (d/without-nils))]
(-> shape (cond-> shape
(cond-> (not (contains? shape :strokes)) (not (contains? shape :strokes))
(assoc :strokes [])) (assoc :strokes [])
:always
(assoc-in [:strokes index] new-attrs)))))))))) (assoc-in [:strokes index] new-attrs))))))))))
(defn change-shadow (defn change-shadow
@ -248,46 +252,65 @@
(ptk/reify ::change-shadow (ptk/reify ::change-shadow
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(rx/of (dch/update-shapes ids (fn [shape] (rx/of (dch/update-shapes
(let [;; If we try to set a gradient to a shadow (for example using the color selection from multiple shapes) let's use the first stop color ids
(fn [shape]
(let [;; If we try to set a gradient to a shadow (for
;; example using the color selection from
;; multiple shapes) let's use the first stop
;; color
attrs (cond-> attrs attrs (cond-> attrs
(:gradient attrs) (get-in [:gradient :stops 0])) (:gradient attrs) (get-in [:gradient :stops 0]))
new-attrs (merge (get-in shape [:shadow index :color]) attrs)] new-attrs (merge (get-in shape [:shadow index :color]) attrs)]
(assoc-in shape [:shadow index :color] new-attrs)))))))) (assoc-in shape [:shadow index :color] new-attrs))))))))
(defn add-shadow
[ids shadow]
(dm/assert! (sm/coll-of-uuid? ids))
(ptk/reify ::add-shadow
ptk/WatchEvent
(watch [_ _ _]
(let [add-shadow (fn [shape]
(update shape :shadow #(into [shadow] %)))]
(rx/of (dch/update-shapes ids add-shadow))))))
(defn add-stroke (defn add-stroke
[ids stroke] [ids stroke]
(ptk/reify ::add-stroke (ptk/reify ::add-stroke
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(let [add (fn [shape attrs] (assoc shape :strokes (into [attrs] (:strokes shape))))] (let [add-stroke (fn [shape] (update shape :strokes #(into [stroke] %)))]
(rx/of (dch/update-shapes (rx/of (dch/update-shapes ids add-stroke))))))
ids
#(add % stroke)))))))
(defn remove-stroke (defn remove-stroke
[ids position] [ids position]
(ptk/reify ::remove-stroke (ptk/reify ::remove-stroke
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(let [remove-fill-by-index (fn [values index] (->> (d/enumerate values) (letfn [(remove-fill-by-index [values index]
(->> (d/enumerate values)
(filterv (fn [[idx _]] (not= idx index))) (filterv (fn [[idx _]] (not= idx index)))
(mapv second))) (mapv second)))
(remove-stroke [shape]
remove (fn [shape] (update shape :strokes remove-fill-by-index position))] (update shape :strokes remove-fill-by-index position))]
(rx/of (dch/update-shapes (rx/of (dch/update-shapes ids remove-stroke))))))
ids
#(remove %)))))))
(defn remove-all-strokes (defn remove-all-strokes
[ids] [ids]
(ptk/reify ::remove-all-strokes (ptk/reify ::remove-all-strokes
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(let [remove-all (fn [shape] (assoc shape :strokes []))] (let [remove-all #(assoc % :strokes [])]
(rx/of (dch/update-shapes ids remove-all))))))
(defn reorder-shadows
[ids index new-index]
(ptk/reify ::reorder-shadow
ptk/WatchEvent
(watch [_ _ _]
(rx/of (dch/update-shapes (rx/of (dch/update-shapes
ids ids
#(remove-all %))))))) #(swap-attrs % :shadow index new-index))))))
(defn reorder-strokes (defn reorder-strokes
[ids index new-index] [ids index new-index]

View file

@ -106,10 +106,11 @@
apply-value apply-value
(mf/use-callback (mf/use-callback
(mf/deps on-change update-input value) (mf/deps on-change update-input value)
(fn [new-value] (fn [new-value event]
(mf/set-ref-val! dirty-ref false) (mf/set-ref-val! dirty-ref false)
(when (and (not= new-value value) (some? on-change)) (when (and (not= new-value value)
(on-change new-value)) (fn? on-change))
(on-change new-value event))
(update-input new-value))) (update-input new-value)))
set-delta set-delta
@ -146,7 +147,7 @@
:else new-value)] :else new-value)]
(apply-value new-value)))))) (apply-value new-value event))))))
handle-key-down handle-key-down
(mf/use-callback (mf/use-callback
@ -180,12 +181,12 @@
handle-blur handle-blur
(mf/use-callback (mf/use-callback
(mf/deps parse-value apply-value update-input on-blur) (mf/deps parse-value apply-value update-input on-blur)
(fn [_] (fn [event]
(let [new-value (or (parse-value) default-val)] (let [new-value (or (parse-value) default-val)]
(if (or nillable new-value) (if (or nillable new-value)
(apply-value new-value) (apply-value new-value event)
(update-input new-value))) (update-input new-value)))
(when on-blur (on-blur)))) (when on-blur (on-blur event))))
on-click on-click
(mf/use-callback (mf/use-callback

View file

@ -8,39 +8,46 @@
(:require (:require
[app.common.colors :as clr] [app.common.colors :as clr]
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.math :as mth]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.colors :as dc]
[app.main.data.workspace.undo :as dwu] [app.main.data.workspace.undo :as dwu]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.numeric-input :refer [numeric-input]]
[app.main.ui.hooks :as h]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def shadow-attrs [:shadow]) (def shadow-attrs [:shadow])
(defn create-shadow [] (defn- create-shadow
(let [id (uuid/next)] []
{:id id {:id (uuid/next)
:style :drop-shadow :style :drop-shadow
:color {:color clr/black :opacity 0.2} :color {:color clr/black
:opacity 0.2}
:offset-x 4 :offset-x 4
:offset-y 4 :offset-y 4
:blur 4 :blur 4
:spread 0 :spread 0
:hidden false})) :hidden false})
(defn valid-number? [value] (defn- remove-shadow-by-index
(or (number? value) (not (js/isNaN (js/parseInt value))))) [values index]
(->> (d/enumerate values)
(filterv (fn [[idx _]] (not= idx index)))
(mapv second)))
(mf/defc shadow-entry (mf/defc shadow-entry
[{:keys [ids index value]}] [{:keys [ids index value on-reorder disable-drag? on-blur open-state-ref]}]
(let [open-shadow (mf/use-state false) (let [basic-offset-x-ref (mf/use-ref nil)
basic-offset-x-ref (mf/use-ref nil)
basic-offset-y-ref (mf/use-ref nil) basic-offset-y-ref (mf/use-ref nil)
basic-blur-ref (mf/use-ref nil) basic-blur-ref (mf/use-ref nil)
@ -49,33 +56,60 @@
adv-blur-ref (mf/use-ref nil) adv-blur-ref (mf/use-ref nil)
adv-spread-ref (mf/use-ref nil) adv-spread-ref (mf/use-ref nil)
shadow-style (str (:style value)) shadow-style (dm/str (:style value))
shadow-id (:id value)
remove-shadow-by-index open-status-ref (mf/with-memo [open-state-ref shadow-id]
(fn [values index] (->> (d/enumerate values) (-> (l/key shadow-id)
(filterv (fn [[idx _]] (not= idx index))) (l/derived open-state-ref)))
(mapv second))) open-shadow (mf/deref open-status-ref)
on-remove-shadow on-remove-shadow
(fn [index] (mf/use-fn
(fn [] (mf/deps ids)
(st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index))))) (fn [event]
(let [index (-> (dom/get-current-target event)
(dom/get-data "index")
(parse-long))]
(st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index))))))
select-text on-drop
(fn [ref] (fn [_] (dom/select-text! (mf/ref-val ref)))) (mf/use-fn
(mf/deps on-reorder index)
(fn [_ data]
(on-reorder index (:index data))))
[dprops dref]
(h/use-sortable
:data-type "penpot/shadow-entry"
:on-drop on-drop
:disabled disable-drag?
:detect-center? false
:data {:id (dm/str "shadow-" index)
:index index
:name (dm/str "Border row" index)})
;; FIXME: this function causes the numeric-input rerender
;; ALWAYS, this is causes because numeric-input design makes
;; imposible implement efficiently any component that uses it;
;; it should be refactored
update-attr update-attr
(fn update-attr (fn update-attr
([index attr valid?] ([index attr]
(update-attr index attr valid? nil)) (update-attr index attr nil))
([index attr update-ref]
([index attr valid? update-ref]
(fn [value] (fn [value]
(when (or (not valid?) (valid? value)) (when (mth/finite? value)
(do (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index attr] value))) (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index attr] value)))
(let [update-node (and update-ref (mf/ref-val update-ref))] (when-let [update-node (and update-ref (mf/ref-val update-ref))]
(when update-node (dom/set-value! update-node value))))))
(dom/set-value! update-node value))))))))
;; FIXME: the same as previous function, imposible to
;; implement efficiently because of numeric-input component
;; and probably this affects all callbacks that that component
;; receives
select-text
(fn [ref] (fn [_] (dom/select-text! (mf/ref-val ref))))
update-color update-color
(fn [index] (fn [index]
@ -96,54 +130,58 @@
toggle-visibility toggle-visibility
(fn [index] (fn [index]
(fn [] (fn []
(st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not)))))] (st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not)))))
[:*
[:div.element-set-options-group {:style {:display (when @open-shadow "none")}}
[:div.element-set-actions-button
{:on-click #(reset! open-shadow true)}
i/actions]
;; [:> numeric-input {:ref basic-offset-x-ref on-toggle-open-shadow
;; :on-change (update-attr index :offset-x valid-number?) (fn []
;; :on-click (select-text basic-offset-x-ref) (swap! open-state-ref update shadow-id not))]
;; :value (:offset-x value)}] [:*
;; [:> numeric-input {:ref basic-offset-y-ref [:div.shadow-option {:class (dom/classnames
;; :on-change (update-attr index :offset-y valid-number?) :dnd-over-top (= (:over dprops) :top)
;; :on-click (select-text basic-offset-y-ref) :dnd-over-bot (= (:over dprops) :bot))
;; :value (:offset-y value)}] :ref dref}
;; [:> numeric-input {:ref basic-blur-ref [:div.shadow-option-main {:style {:display (when open-shadow "none")}}
;; :on-click (select-text basic-blur-ref) [:div.element-set-actions-button
;; :on-change (update-attr index :blur valid-number?) {:on-click on-toggle-open-shadow}
;; :min 0 i/actions]
;; :value (:blur value)}]
[:select.input-select [:select.input-select
{:default-value shadow-style {:default-value shadow-style
:on-change (fn [event] :on-change (fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)] (let [value (-> event dom/get-target dom/get-value d/read-string)]
(st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))}
[:option {:value ":drop-shadow" :selected (when (= shadow-style ":drop-shadow") "selected")} (tr "workspace.options.shadow-options.drop-shadow")] [:option {:value ":drop-shadow"
[:option {:value ":inner-shadow" :selected (when (= shadow-style ":inner-shadow") "selected")} (tr "workspace.options.shadow-options.inner-shadow")]] :selected (when (= shadow-style ":drop-shadow") "selected")}
(tr "workspace.options.shadow-options.drop-shadow")]
[:option {:value ":inner-shadow"
:selected (when (= shadow-style ":inner-shadow") "selected")}
(tr "workspace.options.shadow-options.inner-shadow")]]
[:div.element-set-actions [:div.shadow-option-main-actions
[:div.element-set-actions-button {:on-click (toggle-visibility index)} [:div.element-set-actions-button {:on-click (toggle-visibility index)}
(if (:hidden value) i/eye-closed i/eye)] (if (:hidden value) i/eye-closed i/eye)]
[:div.element-set-actions-button {:on-click (on-remove-shadow index)} [:div.element-set-actions-button
{:data-index index
:on-click on-remove-shadow}
i/minus]]] i/minus]]]
[:& advanced-options {:visible? @open-shadow [:& advanced-options {:visible? open-shadow
:on-close #(reset! open-shadow false)} :on-close on-toggle-open-shadow}
[:div.color-data [:div.color-data
[:div.element-set-actions-button [:div.element-set-actions-button
{:on-click #(reset! open-shadow false)} {:on-click on-toggle-open-shadow}
i/actions] i/actions]
[:select.input-select [:select.input-select
{:default-value (str (:style value)) {:default-value shadow-style
:on-change (fn [event] :on-change (fn [event]
(let [value (-> event dom/get-target dom/get-value d/read-string)] (let [value (-> event dom/get-target dom/get-value d/read-string)]
(st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))}
[:option {:value ":drop-shadow"} (tr "workspace.options.shadow-options.drop-shadow")] [:option {:value ":drop-shadow"
[:option {:value ":inner-shadow"} (tr "workspace.options.shadow-options.inner-shadow")]]] :selected (when (= shadow-style ":drop-shadow") "selected")}
(tr "workspace.options.shadow-options.drop-shadow")]
[:option {:value ":inner-shadow"
:selected (when (= shadow-style ":inner-shadow") "selected")}
(tr "workspace.options.shadow-options.inner-shadow")]]]
[:div.row-grid-2 [:div.row-grid-2
[:div.input-element {:title (tr "workspace.options.shadow-options.offsetx")} [:div.input-element {:title (tr "workspace.options.shadow-options.offsetx")}
@ -151,7 +189,8 @@
:no-validate true :no-validate true
:placeholder "--" :placeholder "--"
:on-focus (select-text adv-offset-x-ref) :on-focus (select-text adv-offset-x-ref)
:on-change (update-attr index :offset-x valid-number? basic-offset-x-ref) :on-change (update-attr index :offset-x basic-offset-x-ref)
:on-blur on-blur
:value (:offset-x value)}] :value (:offset-x value)}]
[:span.after (tr "workspace.options.shadow-options.offsetx")]] [:span.after (tr "workspace.options.shadow-options.offsetx")]]
@ -160,7 +199,8 @@
:no-validate true :no-validate true
:placeholder "--" :placeholder "--"
:on-focus (select-text adv-offset-y-ref) :on-focus (select-text adv-offset-y-ref)
:on-change (update-attr index :offset-y valid-number? basic-offset-y-ref) :on-change (update-attr index :offset-y basic-offset-y-ref)
:on-blur on-blur
:value (:offset-y value)}] :value (:offset-y value)}]
[:span.after (tr "workspace.options.shadow-options.offsety")]]] [:span.after (tr "workspace.options.shadow-options.offsety")]]]
@ -170,7 +210,8 @@
:no-validate true :no-validate true
:placeholder "--" :placeholder "--"
:on-focus (select-text adv-blur-ref) :on-focus (select-text adv-blur-ref)
:on-change (update-attr index :blur valid-number? basic-blur-ref) :on-change (update-attr index :blur basic-blur-ref)
:on-blur on-blur
:min 0 :min 0
:value (:blur value)}] :value (:blur value)}]
[:span.after (tr "workspace.options.shadow-options.blur")]] [:span.after (tr "workspace.options.shadow-options.blur")]]
@ -180,7 +221,8 @@
:no-validate true :no-validate true
:placeholder "--" :placeholder "--"
:on-focus (select-text adv-spread-ref) :on-focus (select-text adv-spread-ref)
:on-change (update-attr index :spread valid-number?) :on-change (update-attr index :spread)
:on-blur on-blur
:value (:spread value)}] :value (:spread value)}]
[:span.after (tr "workspace.options.shadow-options.spread")]]] [:span.after (tr "workspace.options.shadow-options.spread")]]]
@ -194,15 +236,41 @@
:on-change (update-color index) :on-change (update-color index)
:on-detach (detach-color index) :on-detach (detach-color index)
:on-open #(st/emit! (dwu/start-undo-transaction :color-row)) :on-open #(st/emit! (dwu/start-undo-transaction :color-row))
:on-close #(st/emit! (dwu/commit-undo-transaction :color-row))}]]]])) :on-close #(st/emit! (dwu/commit-undo-transaction :color-row))}]]]]]))
(mf/defc shadow-menu (mf/defc shadow-menu
[{:keys [ids type values] :as props}] {::mf/wrap-props false}
(let [on-remove-all-shadows [props]
(fn [_] (st/emit! (dch/update-shapes ids #(dissoc % :shadow)))) (let [ids (unchecked-get props "ids")
type (unchecked-get props "type")
values (unchecked-get props "values")
shadows (:shadow values [])
open-state-ref (mf/with-memo [] (l/atom {}))
disable-drag* (mf/use-state false)
disable-drag? (deref disable-drag*)
on-remove-all
(mf/use-fn
(mf/deps ids)
(fn []
(st/emit! (dch/update-shapes ids #(dissoc % :shadow)))))
handle-reorder
(mf/use-fn
(mf/deps ids)
(fn [new-index index]
(st/emit! (dc/reorder-shadows ids index new-index))))
on-blur
(mf/use-fn
#(reset! disable-drag* false))
on-add-shadow on-add-shadow
(fn [] (mf/use-fn
(st/emit! (dch/update-shapes ids #(update % :shadow (fnil conj []) (create-shadow)) )))] (mf/deps ids)
#(st/emit! (dc/add-shadow ids (create-shadow))))]
[:div.element-set.shadow-options [:div.element-set.shadow-options
[:div.element-set-title [:div.element-set-title
[:span [:span
@ -211,22 +279,28 @@
:group (tr "workspace.options.shadow-options.title.group") :group (tr "workspace.options.shadow-options.title.group")
(tr "workspace.options.shadow-options.title"))] (tr "workspace.options.shadow-options.title"))]
(when-not (= :multiple (:shadow values)) (when-not (= :multiple shadows)
[:div.add-page {:on-click on-add-shadow} i/close])] [:div.add-page {:on-click on-add-shadow} i/close])]
(cond (cond
(= :multiple (:shadow values)) (= :multiple shadows)
[:div.element-set-content [:div.element-set-content
[:div.element-set-options-group [:div.element-set-options-group
[:div.element-set-label (tr "settings.multiple")] [:div.element-set-label (tr "settings.multiple")]
[:div.element-set-actions [:div.element-set-actions
[:div.element-set-actions-button {:on-click on-remove-all-shadows} [:div.element-set-actions-button {:on-click on-remove-all}
i/minus]]]] i/minus]]]]
(seq (:shadow values)) (seq shadows)
[:& h/sortable-container {}
[:div.element-set-content [:div.element-set-content
(for [[index value] (d/enumerate (:shadow values []))] (for [[index value] (d/enumerate shadows)]
[:& shadow-entry {:key (str "shadow-" index) [:& shadow-entry
{:key (dm/str "shadow-" index)
:ids ids :ids ids
:value value :value value
:index index}])])])) :on-reorder handle-reorder
:disable-drag? disable-drag?
:on-blur on-blur
:index index
:open-state-ref open-state-ref}])]])]))