thheller / shadow-css

CSS-in-CLJ(S)
https://github.com/thheller/shadow-css
Eclipse Public License 1.0
108 stars 10 forks source link

Alias data attributes #16

Closed kimo-k closed 4 months ago

kimo-k commented 12 months ago

Hey there, this library is brilliant IMO.

Is there a recommended way to select data attributes? I have a lot of different ones. For instance, I could do:

(css [:data-attr/my-ns__x=my-ns__a {:color "red"}]

;; resolves to: 
(css ["&[data-my-ns__x=\":my-ns/a\"" {:color "red"}])

That seems brittle. I'd rather not hard-code every possible attr/value combination as a single-keyword alias. I'd much rather do do something like:

(css [^:data {:my-ns/x :my-ns/a} {:color "red"})]

;; resolves to:
(css ["&[data-my-ns__x=\":my-ns/a\"" {:color "red"}])

I don't mind registering individual aliases for :my-ns/x and :my-ns/a. But it would be great if shadow-css had some way to compose them into a data-attr. What do you think?

thheller commented 12 months ago

I'm not quite sure what problem this is solving. What purpose do those data attributes serve? Is it just for styling or are they used for something else? I think I'd generally recommend solving this in code rather than css. So something like

[:div {:class (if (some-condition? ...) (css {:color "red"}) (css {:color "blue"}))} ...]

kimo-k commented 12 months ago

Thanks for the quick reply. What I'm doing is similar to how zag.js implements styling. Reagent calculates data attributes representing the abstract collection of states a component is in. Css rules select the data attributes and the class, mapping rules to a particular element in a particular state.

Instead of your example, it's [:div {:class $my-button :data-my-ns__x (str (if some-condition? :my-ns/a :my-ns/b))}]. Shadow-css handles the name and place of $my-button, but the predicative logic of styling is actually embedded in css, via the shadow-css dsl:

(def $my-button (css ["&[data-my-ns__x=\":my-ns/a\"" {:color "red"}]
                     ["&[data-my-ns__x=\":my-ns/b\"" {:color "blue"}]))
thheller commented 12 months ago

I will need a full example of what you are doing, as I still don't have a clue how that all works together. Seems to me that this is offloading stuff onto CSS that shouldn't be CSS in the first place.

kimo-k commented 12 months ago

Maybe it's easier to consider the general case of targeting a data attribute. Frameworks like bootstrap (e.g. popover) and foundation (e.g. reveal) use data attributes, for instance. How could I target this element without hard-coding the association between "data-state" and "enabled"? <div data-state="enabled">

thheller commented 12 months ago

["&[data-state=enabled]" ...] works fine and I don't see a need for "more"?

kimo-k commented 12 months ago

Unfortunately, it's not user-friendly. The user of my general-purpose library has to understand "&" and "&&&", as well as how to serialize the attr key and the attr value, both of which are namespaced keywords. I already need an adapter, for instance, to convert :my-ns/some-key to :data-my_ns__some_key, to represent the qualified keyword in the DOM. And I use "&&&" to control style composition via specificity, composing app-level themes, component-level themes and hiccup-level declarations.

I see your point that it's highly bespoke, but I just had a sense that a general use-case would emerge. Data attributes are a rare feature of css where the key can vary as broadly as the val. From a certain point of view, it makes sense to express a data-attr as a tuple, rather than reifying the key & val into a single token.

thheller commented 4 months ago

Closing as I still do not understand a need here.

Feel free to re-open with a practical real world example repo that shows the problem in actual code.