Git Product home page Git Product logo

spade's People

Contributors

dhleong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

eehah5ru

spade's Issues

Support for Custom DOM Injection Targets

Please support injection of <style> tags into custom DOM targets, not just (.-head js/document) which is hard-coded in inject!.

There are at least two use cases for this:

For example, re-frame-10x is rendered into a shadow root then sets a *dom* atom in a slightly modified spade so that <style> tags are rendered inside the shadow dom.

It is not clear to me if the general solution in spade should be also global; i.e. two options would be

  • all defclass / defglobal render to some custom dom set early, or default to (.-head js/document) if not set
  • per defclass / defglobal arg or meta so styles can be rendered to different dom contexts on a case by case basis if needed, or default to (.-head js/document) if not set

Further optimize for the expected case of "pure" style functions

In most cases, for any given input a style function should always return the same style. It turns out that we do not take advantage of that just now, but we could! Currently, whenever a style function is called, we:

  1. Call its "factory" function, which invokes the user-provided code and:
  2. Compiles the style spec into CSS, and:
  3. Generates a class name for the style+params
  4. If the style doesn't exist in the DOM, we create it; otherwise:
  5. If the CSS is changed, update the DOM

This is great for local dev, since the factory code might have changed since the last time we ran it, but in production for most cases, 1, 2, and 5 are completely unnecessary, and 3 probably ought to be memoized.

I propose for v1.2.0 we do some refactoring. The new flow would look like:

  1. Generate a class name for the style+params via a new, memoized function we generate. In the common case where the function takes no parameters, we might be able to inline this instead
  2. If the style doesn't exist in then DOM, we call the "factory" function to invoke the user-provided code and compile it into CSS, then create the DOM <style> element
  3. Otherwise, IF the (new) :always-compile-css? compiler flag is true (we will default to goog.DEBUG so this does not happen in prod by default) we call the "factory" function to generate CSS as above and, if changed, update the DOM

This should significantly reduce overhead for the hot path case of using a style function in a virtualized list—and, well, just in general—while not requiring any changes to user code for most cases, or having any impact on the dev cycle.

For weird cases where a style should always be rebuilt each time it's used we could add an escape hatch by annotating the style function with metadata:

(defattrs ^:always-compile-css not-referentially-transparent-attrs []
  {:color (js/Math.random) ; or whatever
   ...
   })

I honestly can't think of a good use case for this, however, so this escape hatch might be deferred until someone asks for it (unless it turns out to be very simple to add).

Support composition

I think we could very easily support this by supporting a special keyword :composes in the root style. Here you just pass a class name, or a vector of class names, presumably from calling a defclass style (eg: (style-class)), or by doing a (:class (style-attrs)) thing, if you really want to. So it might look like this:

(defclass ship []
  {:background "#999"}
  [:.wings {:background "#777"}])
  
(defattrs stealth-ship []
  {:composes (ship)
   :background "#777"})

Seems very intuitive to me.

Trouble with Media Queries

I'm not sure if I'm doing something wrong or if there's a bug with the media query implementation.

Here's what I tried:

(defclass test-class []
          (at-media {:min-width "200px"}
                    {:margin-left "10em"})
          {:background-color "blue"
           :margin-left "1em"
           :width "4em"
           :height "4em"})

(defcard
  test
  "Testing media queries"
  (fn []
    (sab/html
      [:div {:class (test-class)}])))

Here's what it results in:

devcard

The classes work perfectly except for media queries. I've tried all manner of things to get media queries to work, but nothing seems to take effect.

Please advise, thanks!

Compose Multiple Styles

Is it possible to compose multiple styles ? E.g.

(defclass example
  []
  {:composes [(shadow) (color-3) (big-text)]})

A little glitch in the defglobal macro

> (macroexpand '(defglobal x []))
(do
 (clojure.core/defn
  x-factory$
  [style-name24459 params24460]
  {:name style-name24459, :css (spade.runtime/compile-css [[]])})
 (clojure.core/let
  [factory-name24461 (spade.util/factory->name x-factory$)]
  (def x
   (spade.runtime/ensure-style! :global factory-name24461 x-factory$ nil))))

It should be clojure.core/def x not just def x. (And I'm not sure about cljs.core/do vs. do. I can't think clearly anymore, it's 4:30 a.m.)

Binding Forms Incompatible with defclass

Binding forms such as let are incompatible with defclass as such forms only return the value of the last form.

E.g.

(defclass example
   []
   (let [a true]
      {:background (if a :blue :grey)}
      [:h4
        {:color (if a :black :white)}]
      [:&:hover
        {:border [[(px 1) :solid :grey]]}]))

;; will only output
;; [:&:hover
;;        {:border [[(px 1) :solid :grey]]
;; as the first 2 forms are ignored due to the let

The root cause of this is defclass macro return semantics being different to defn / do in that it returns all top level forms, instead of the value of the last form. Its understandable once analyzed that the above let example does what it does in that context, but it is initially surprising behavior for a Clojure(Script) programmer. It certainly caught me out because I was trying to bind a common value with let and it took me awhile to realise why all the styles were not coming through.

I'm not sure how to fix this. Maybe a mitigation such as allowing a single form return style for defclass could work ? E.g.

(defclass example
  []
  [(let ... ])

Unable to generate style names when compiled under `:simple` optimizations

Global styling via defglobal seems to not work with :simple optimization. The weird thing is that global styles work just fine in :advanced optimization.

Here's a lightweight, sample project for your viewing convenience:
https://github.com/sansarip/yacwat-simple

You can change the :optimization level in the prod.cljs.edn file to :simple and then compile a jar that you can run with lein prod - more detailed instructions in the README.

Is this intentional / am I doing something wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.