Fork me on GitHub
#clojurescript
<
2020-04-02
>
coby01:04:37

I'm trying to consume a React component that has its own CSS-in-JS stylesheet. Here is the basic example from the README:

import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import 'react-tabs/style/react-tabs.css';

export default () => (
  <Tabs>
    <TabList>
      <Tab>Title 1</Tab>
      <Tab>Title 2</Tab>
    </TabList>

    <TabPanel>
      <h2>Any content 1</h2>
    </TabPanel>
    <TabPanel>
      <h2>Any content 2</h2>
    </TabPanel>
  </Tabs>
);
How would I make use of react-tabs/styles/react-tabs.css from CLJS?

dnolen01:04:00

@ctamayo If you want to use ClojureScript directly then just use webpack - https://clojurescript.org/guides/webpack

dnolen01:04:11

I believe shadow-cljs removes some of these steps if you're looking for something more "out of the box"

coby01:04:04

Cool, I'm using shadow-cljs already but I didn't see anything in the user guide about importing CSS from an npm lib. Would prefer to avoid Webpack if at all possible because...well, Webpack. 😆

coby01:04:12

Ah... > shadow-cljs currently provides no support for directly compiling CSS but the usual tools will work and should be run separately. Just make sure the output is generated into the correct places. so I guess by choosing this library I'm choosing to use Webpack or equivalent. Dang.

dnolen01:04:49

right so ClojureScript didn't go there because that's just where you end up

dnolen01:04:21

Webpack just does too many things and too many random libs depend on it - trying to attack it is a waste of time

dnolen01:04:42

but to your point - I would probably not use a library that complicate the build

dnolen01:04:46

I don't care how cool it is

coby02:04:05

Makes sense. I guess JS as a compilation target is a fundamentally leaky abstraction, given the nature of JS...

dnolen02:04:28

there's nothing wrong with JS as a compilation target

dnolen02:04:00

the problem is people wanting conveniences and not thinking through the repercussions for complexity

dnolen02:04:22

(I just mean JS didn't used to have this problem)

coby02:04:37

fair point, I guess fundamentally this particular problem doesn't have to do with JS at all

coby02:04:45

but yeah this is just for a proof of concept anyway, absolutely no need for fussing around with complicated builds. I'll probably just manually copy the stylesheet, clap my hands, and say "fixed forever!"

12
coby02:04:14

And since I'm talking to you, thank you for your work on ClojureScript!!

☝️ 24
8
dnolen02:04:28

thanks for using it 🙂

24
lilactown04:04:45

what utilities do people find for datascript?

teodorlu11:04:36

I wanted to play with some COVID-19 data, and visualize. I got some JSON sources, had a look inside. Wrote a bit of Clojure to extract the entities I was looking for. Got a flat sequence of namespaced maps. Put that into Datascript, and ran queries on it. I then put the result into Oz to visualize. Note that this was from the JVM.

lilactown04:04:04

I’m super keen on using it, because datalog 😅

lilactown04:04:47

I’m thinking of using it for some tests. I have an operation that produces a tree of data that I need to make some assertions on. would people think it reasonable to pull in datascript, write a datalog query that describes the properties I want and assert that it’s true?

victorb09:04:29

I'm in a bit of a pickle here. I have two strings, one text and one "link" string structure (comes from the outside and needs to arrive as strings), and I'm trying to build up a [:span] where I replace some subpart of the text with a parsed structure from the link string. I'm currently trying to find the best solution for this, but I arrived at using read-string but wanted to check if there is a different way of doing it without mudding the code too much. Another idea was to split everything into lists from the text and then replace elements in the list, but the replaced part sometimes has spaces between it, which means I need to replace many elements sometimes, and I couldn't come up with a clean solution for it. Any other ideas would be the most welcome! Current code looks something like this:

(defn create-link [text link]
  [:a
   {:href link
    :target "_blank"}
   text])

(defn linkify-content [text link]
  (let [[link-text link-href] (clojure.string/split link #":")]
    [:span
     (read-string (clojure.string/replace text link-text (create-link link-text link-href)))]))
Then it's used like this:
(linkify-content "Check out this tutorial first" "this tutorial:"))

victorb09:04:42

I'd love to be able to remove the read-string as it adds quite a bit to the final bundle and also obviously want to avoid a compromised endpoint to introduce XSS

victorb09:04:26

Another idea is to use dangerouslySetInnerHTML from react which fixes the bundle size issue with read-string but the XSS possibility remains

victorb09:04:08

alright, managed to find a solution that is a bit cleaner. Wrote a function that works like clojure.string/split but keeps the match, so end up with ["check out " "this tutorial" "first"] then replace the matching element with the :a element and pass that to reagent render

victorb10:04:41

in case anyone is interested, final code ended up being:

(defn split-keep [s m]
  (interpose m (clojure.string/split s (re-pattern m))))

(defn string->list-with-link [text match link]
  (map (fn [el]
         (if (= el match)
           [:a
            {:href link
             :target "_blank"
             :style {:color "#0146E0"
                     :font-weight "bolder"}}
            match]
           el))
       (split-keep text match)))

(defn linkify-content [text link]
  (let [[link-text link-href] (clojure.string/split link #"\|")]
    [:span
     (string->list-with-link text link-text link-href)]))

Felipe Marques13:04:38

Hi everyone, I'm trying to use spec in clojurescript and I keep getting this error that I can't understand. When I evaluate the following code:

(defn path-generator []
  (gen/fmap (fn [[path object-name]]
              (apply str (concat (vec (interleave path ["/"]))
                                 object-name)))
            (gen/tuple (gen/vector not-empty-alphanumeric-gen)
                       not-empty-alphanumeric-gen)))

(s/def ::path (s/with-gen
                (s/and string? #(re-matches #"^\/?((\.?[A-Za-z0-9-_+]+(\.[A-Za-z0-9-_+]+)*)\/)*\.?[A-Za-z0-9-_+]+(\.[A-Za-z0-9-_+]+)*$" %))
                path-generator))
The error is: SyntaxError: Invalid or unexpected token Does anyone have a similar error?

mauricio.szabo13:04:09

@marques.goncalves.fel check your regexp. Sometimes regexes from Clojure are not compatible with ClojureScript.

Felipe Marques13:04:02

oh, yeah, that's probably that. I'm moving a Clojure project into .cljc. Thanks! I'll take a look!

ak-coram19:04:30

does anyone know of CLJS libraries for deterministic serialization?

ak-coram19:04:59

found https://github.com/hkupty/debris , but it's binary and CLJ only

mkvlr19:04:05

not ClojureScript but JavaScript: https://github.com/paroga/cbor-js

mkvlr19:04:41

there’s also a clojure version https://github.com/greglook/clj-cbor and a lot more implementations https://cbor.io/impls.html

ak-coram19:04:17

Thanks, but I'm hoping I can use sets and custom tags with EDN.

lilactown21:04:46

are statically known keywords hoisted into the constants table? e.g. if I have the code:

(cond
  loading? :loading
  error :error
  :else :done)
will those keyword constructions be hoisted to be done at load time?

lilactown21:04:01

mainly I’m interested in maintaining referential identity. it looks like at least at dev time, they are not hoisted

isak21:04:08

> This option is mainly intended to be used for a release build since it can increase performance due to decreased allocation. Defaults to true under :advanced optimizations otherwise to false.

lilactown21:04:42

do you know if this would be terrible to enable at dev time?

isak21:04:37

i'm not sure - hard to see why it would be, but i'm sure they must have done it that way for a reason. Maybe it negatively impacts compile/reload time

isak21:04:02

For :optimize-constants, what do people think of making it also hoist small collections like #{:foo :bar}, so people can write code like (contains? #{:foo :bar} x) without creating new collections?

lilactown21:04:03

seems great on it’s face

lilactown21:04:23

I’ve always wondered why immutable structures are created more than once

lilactown21:04:34

metadata, I guess is why…

isak21:04:53

:thinking_face:

lilactown21:04:10

probably bad for GC too? you’d have to do your own sweep every once and awhile

isak22:04:03

Bad for memory required at rest, but less GC pressure when executing code. I would think probably worth it for most apps, especially if its only for small collections of constants that would already be in the constants table.

Spaceman22:04:53

suppose I have received a jpg file as an input stream from the server in the body of the response, and I want to display it as an image using the src attribute on an re-agent img tag. How can I do that?

Spaceman22:04:20

okay, how do I convert the input stream to a base64 string?

Spaceman22:04:41

I don't have a binary string. It's an input stream

Spaceman22:04:53

(prn (.btoa js/WindowOrWorkerGlobalScope (:body response)))

Spaceman22:04:56

doesn't work

isak22:04:44

what kind of inputstream do you have? It should always be possible to read the whole input stream to get the binary string

isak22:04:51

I found this example on MDN, are you using fetch?

const image = document.querySelector('.my-image');
fetch('flowers.jpg').then(function(response) {
  return response.blob();
}).then(function(blob) {
  const objectURL = URL.createObjectURL(blob);
  image.src = objectURL;
});

Spaceman22:04:47

I created it using this in the server: (io/input-stream "blur.jpg")

Spaceman22:04:10

and then in cljs I did (prn (.btoa js/WindowOrWorkerGlobalScope (:body response)))

Spaceman22:04:26

and it gives me "no reader function for tag object."

isak22:04:11

what are you using on the client though? if you use fetch, you can use a promise to convert it to a blob, which you can then use to create the URI

isak22:04:14

as shown above

Spaceman22:04:54

This gives an exception: (go (let [response (<! (http/get (str "http://localhost:5000" "/get-image")))] (prn "segmentation response" (:body response)) (prn (.blob (:body response))) ))

Spaceman22:04:01

cljs-http.client

isak23:04:40

I haven't used that API, but guessing .blob will return a channel or promise, so you need to <! that as well

Spaceman23:04:31

how about this?:

const toBase64 = file => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = error => reject(error);
});

async function Main() {
   const file = document.querySelector('#myfile').files[0];
   console.log(await toBase64(file));
}

Spaceman23:04:39

okay, so I have the following: (go (let [response (<! (http/get (str url "/run-segmentation"))) file-reader (js/FileReader.) ] (prn "input stream is" (:body response)) (js/console.log "file reader " file-reader) (set! (.-onload file-reader) (fn [e] (let [data-url (-> e .-target .-result)] (prn "data-url is " data-url) (dispatch [:blurred data-url]) ))) (.readAsDataURL file-reader (:body response)) ))

Spaceman23:04:28

but I'm getting at (.readAsDataURL file-reader (:body response)) parameter 1 is not of type blob.

Spaceman23:04:34

How do I convert this input-stream to a blob?