Last active
August 10, 2021 14:26
-
-
Save not-in-stock/c53dd9f2f47f56547ecaa57bdcdea3e0 to your computer and use it in GitHub Desktop.
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
| (ns not-in-stock.components.scrollbars | |
| (:require [clojure.walk :as walk] | |
| goog.object | |
| [medley.core :as medley] | |
| ["react-custom-scrollbars" :default ReactCustomScrollbars] | |
| [reagent.core :as r] | |
| [superstring.core :as str])) | |
| (defn- lisp-keyword [kw] | |
| (keyword (str/lisp-case kw))) | |
| (defn- js->clj-kw [x] | |
| (walk/prewalk | |
| (fn [node] | |
| (if (map-entry? node) | |
| [(lisp-keyword (key node)) (val node)] | |
| node)) | |
| (js->clj-kw x))) | |
| (defn- wrap-on-update [f] | |
| (fn [values] | |
| (f (js->clj-kw values)))) | |
| (defn- transform-props [props] | |
| (medley/update-existing props :on-update wrap-on-update)) | |
| (def ^:private impl | |
| (r/adapt-react-class ReactCustomScrollbars)) | |
| (defn- bottom-shadow-opacity [values shadow-height] | |
| (let [{:keys [scroll-top scroll-height client-height]} values | |
| double-height (* 2 shadow-height) | |
| bottom-scroll-top (- scroll-height client-height)] | |
| (* (/ 1 double-height) | |
| (- bottom-scroll-top | |
| (max scroll-top | |
| (- bottom-scroll-top double-height)))))) | |
| (defn- top-shadow-opacity [values shadow-height] | |
| (let [{:keys [scroll-top]} values | |
| double-height (* 2 shadow-height)] | |
| (* (/ 1 double-height) | |
| (min scroll-top | |
| double-height)))) | |
| (defn- shadow-gradient [color direction] | |
| (str "linear-gradient(" direction ", " color " 0%, rgba(0, 0, 0, 0) 100%)")) | |
| (defn- shadow-bottom [color height *values] | |
| (let [values @*values] | |
| [:div {:style {:opacity (bottom-shadow-opacity values height) | |
| :position :absolute | |
| :bottom 0 | |
| :left 0 | |
| :right 0 | |
| :height height | |
| :background (shadow-gradient color "to top")}}])) | |
| (defn- shadow-top [color height *values] | |
| (let [values @*values] | |
| [:div {:style {:opacity (top-shadow-opacity values height) | |
| :position :absolute | |
| :top 0 | |
| :left 0 | |
| :right 0 | |
| :height height | |
| :background (shadow-gradient color "to bottom")}}])) | |
| (defn- transform-shadow-props [props] | |
| (-> props | |
| (update :color #(or % "grey")) | |
| (update :height #(or % 10)))) | |
| (defn- shadow [] | |
| (let [this (r/current-component) | |
| props (transform-shadow-props (r/props this)) | |
| {:keys [top bottom color height *values]} props | |
| children (r/children this)] | |
| (cond-> [:div {:style {:position :relative}}] | |
| top (conj [shadow-top color height *values]) | |
| :always (into children) | |
| bottom (conj [shadow-bottom color height *values])))) | |
| (defn- wrap-shadow-on-update [f on-update-fn] | |
| (fn [values] | |
| (when f (f values)) | |
| (on-update-fn values))) | |
| (def ^:private ref-fns | |
| ["scrollTop" | |
| "scrollLeft" | |
| "scrollToTop" | |
| "scrollToBottom" | |
| "scrollToLeft" | |
| "scrollToRight" | |
| "getScrollLeft" | |
| "getScrollTop" | |
| "getScrollWidth" | |
| "getScrollHeight" | |
| "getClientWidth" | |
| "getClientHeight" | |
| "getValues"]) | |
| (def ^:private ref-fn-name->kw | |
| (into {} (for [ref-fn ref-fns] | |
| [ref-fn (keyword (str/lisp-case ref-fn))]))) | |
| (defn- component->ref-fns [component] | |
| (into {} (for [ref-fn ref-fns] | |
| [(ref-fn-name->kw ref-fn) (goog.object/get component ref-fn)]))) | |
| (defn- deep-merge [& maps] | |
| (if (every? #(or (nil? %) | |
| (map? %)) maps) | |
| (apply merge-with deep-merge maps) | |
| (last maps))) | |
| (defn- transform-shadow-scrollbars-props [props on-update-fn *scroll-bar-ref] | |
| (-> props | |
| (update :on-update wrap-shadow-on-update on-update-fn) | |
| (deep-merge {:style {:position :relative} | |
| :ref #(reset! *scroll-bar-ref (component->ref-fns %))}))) | |
| (defn simple-scrollbars [] | |
| (let [this (r/current-component) | |
| props (r/props this)] | |
| (into [impl (transform-props props)] | |
| (r/children this)))) | |
| (defn scrollbars [] | |
| (let [*values (r/atom []) | |
| *scrollbar-fns (atom nil)] | |
| (fn [] | |
| (let [this (r/current-component) | |
| props (r/props this) | |
| {shadow-props :shadow | |
| :keys [on-component-update on-component-mount]} props] | |
| (if (some? shadow-props) | |
| [shadow (assoc shadow-props :*values *values) | |
| (into [(with-meta simple-scrollbars | |
| {:component-did-mount #(when on-component-update | |
| (on-component-update @*scrollbar-fns)) | |
| :component-did-update #(when on-component-update | |
| (on-component-mount @*scrollbar-fns))}) | |
| (-> props | |
| (dissoc :shadow :on-component-update :on-component-mount) | |
| (transform-shadow-scrollbars-props #(reset! *values %) | |
| *scrollbar-fns))] | |
| (r/children this))] | |
| (into [simple-scrollbars props] | |
| (r/children this))))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.