Fork me on GitHub
#clojurescript
<
2022-10-03
>
Lidor Cohen09:10:28

hello! I write a lambda and I need to return a promise, however, I prefer working with channels throughout my code. Is there an easy way from go to promise (chann->p)?

p-himik10:10:00

Nothing built-in, but It's a one-liner given the constructor js/Promise.

Lidor Cohen14:10:09

You're right, I was out of my game this morning 😅

M J10:10:39

Hi, I have an element that uses "focus" and "onblur".. I want to trigger the on-blur when pressing the ENTER key For now it prints "on-blur". Any idea how?

[:div {:class (label-text-field-style padding)
             :on-blur  #(do (reset! (:label-clicked? state) false)
                            (reset! label-clicked-out? false)
                            (when new-folder?
                              (re-posh/dispatch [::wevents/update-folder-new false]))
                            (reset! (:is-new-folder? state) false))
             :on-key-down (fn [^js/Event e]
                            (when (= (-> e .-which) 13) (println "cause onblur here"))
                            (when (or (= (-> e .-which) 13) (= (-> e .-which) 32))
                              (.stopPropagation e)))}]

p-himik10:10:42

The most straightforward way to do it would be to remove the focus from the element by calling .blur on its DOM node.

thheller10:10:15

(-> e (.-target) (.blur)) instaed of the println

🙌 2
M J10:10:48

THANKS! 🙏

p-himik10:10:00

BTW can be slightly shorter with (.. e -target blur). :)

🙌 2
thheller10:10:46

I don't like .. but sure that works too 🙂

p-himik11:10:07

Just a personal preference? And maybe the fact that IIRC Cursive still doesn't treat it right.

thheller11:10:50

nah just too limited. can only do interop forms, too many times I started with .. but then wanted to call a clojure function

thheller11:10:02

so now just using -> and adding a couple extra dots where needed

p-himik11:10:17

Ah, true, makes sense.

thheller11:10:57

also works better with as-> cond-> etc

skylize15:10:28

Sharing parts of this tangent to the main channel, because it's interesting and others might find it useful. > @thheller (-> e (.-target) (.blur))... > @p-himik BTW can be slightly shorter with (.. e -target blur). 🙂 > @thheller I don't like .. but sure that works too 🙂 > @p-himik Just a personal preference? ... > @thheller ... can only do interop forms, too many times I started with .. but then wanted to call a clojure function > so now just using -> and adding a couple extra dots where needed > also works better with as-> cond-> etc

Gabriel Kovacs22:10:22

I was googeling .. a couple of hours ago. Syntax in Clojure/-Script can be so much fun :)

skylize22:10:11

@U02AMR8032L Best results I can find on such things comes from searching for "clojurescript interop"

👍 1
M J11:10:08

I have this element that turns hover value true or false when mouse is hovering over it. The problem is, when I right-click (using context-menu) the "on-mouse-leave" doesn;t work at all. Any suggestions?

(defn folder-item [{:keys [name editable selected onClick onChange onDelete confirmDelete copyLink workspace-id folder-id new-folder? deletable? clicked-folder-details clicked-workspace-id clicked-workspace-name count delete-notification]}]
  (let [context-menu (reagent/atom nil)
        hover? (reagent/atom false)
        label-clicked-out? (reagent/atom false)
        delete-action (if (not= deletable? true) confirmDelete onDelete)]
    (fn []
      [:div {:onContextMenu (handle-context-menu-fn context-menu :folder-item nil clicked-folder-details clicked-workspace-id clicked-workspace-name count delete-notification) :style {:cursor "context-menu"}}
       [re-com/button
        :src       (at)
        :label
        [h-box
         :size "auto"
         :justify :between
         :children [(when @hover? [h-box
                                                 :children [[folder-item-ellipsis-menu folder-id delete-action copyLink label-clicked-out? clicked-folder-details clicked-workspace-id clicked-workspace-name count] ;; deletable? delete-folder-action
                                                            [folder-item-menu-component delete-action copyLink label-clicked-out? context-menu]] ;; deletable? delete-folder-action
                                                 :height "24px"])] :align :center]
        
        :attr     {
                   :on-mouse-enter #(do
                                      (println "enter")
                                     (reset! hover? true))
                   :on-mouse-leave  #(do
                                       (println "leave")
                                     (reset! hover? false))
                   
                   
                   :on-key-up (fn [^js/Event e]
                                (when (= (-> e .-which) 32)
                                  (.preventDefault e)))}]])))
My question is, how to make on-mouse-leave work and not get ignored when we right-click the element...

p-himik11:10:42

That's just how it works in browsers. But you can also listen to the contextmenu event, I believe.

Mícheál Ó Catháin12:10:31

First off, I'm not sure if this is the right channel for my query - set me right if needed please! I have a working pair of javascript files: • one file which creates an AudioContext and an AudioWorkletNode, • the other file which does the audio processing, by extending the class AudioWorkletProcessor As I say these js files work when called from a simple html file. I am trying to bring these js files into my website which is implemented in clojure/clojurescript using libraries hiccup, compojure, ring. After various troubleshooting efforts the following error persists in the browser console:

Uncaught ReferenceError: AudioWorkletProcessor is not defined
I have upgraded clojure, clojurescript and dependencies to latest releases, to no effect. At an impass. Any steers as to what I can try to resolve the error would be appreciated!

thheller14:10:49

I believe the AudioWorkletProcessor is only available in an actual audio worklet. the one instantiated in the other file. So you can only port the other file to CLJS, but the actual worklets is probably best left as JS.

Mícheál Ó Catháin14:10:50

Thanks @thheller. In fact I have left both files as JS. I am including both JS files using (something like) ...

(hiccup.page.html5.include-js ["webaudio.js" "processor.js"])

thheller15:10:56

yeah you don't load the processor directly via the html

thheller15:10:14

at least I'd assume that the webaudio.js is triggering the load, not the html

Mícheál Ó Catháin17:10:15

Thanks @thheller! That helped narrow it down. I needed to specify the directory name "js" within the "public" folder when loading processor.js from webaudio.js, i.e., "js/processor.js". Wasn't necessary when running with basic html and javascript using python's http.server..... now I know!

skylize15:10:28

Sharing parts of this tangent to the main channel, because it's interesting and others might find it useful. > @thheller (-> e (.-target) (.blur))... > @p-himik BTW can be slightly shorter with (.. e -target blur). 🙂 > @thheller I don't like .. but sure that works too 🙂 > @p-himik Just a personal preference? ... > @thheller ... can only do interop forms, too many times I started with .. but then wanted to call a clojure function > so now just using -> and adding a couple extra dots where needed > also works better with as-> cond-> etc

Abhinav16:10:15

Hi, I was wondering if there is a way to achieve the same effect intern has in clojurescript. I have a macro that I’m interning in the clojure.core ns. but the macro is a cljc macro, and I’d like to be able to “intern” the macro in cljs.core namespace as well. is this possible?

timothypratley17:10:22

Hi 👋 This seems to work: .clj file

(ns ellisperati.macros)
(defmacro foo [& body] (str "bar" body))
(intern 'cljs.core (with-meta 'foo (meta #'foo)) #'foo)
.cljs file
(ns ellisperati.macros
  (:require-macros [ellisperati.macros]))
(prn "FOO" (foo baz))
[Figwheel] Successfully compiled build webapp. "FOO" "bar(baz)" You should be able to combine them in a cljc file using reader conditionals #?(:clj ... :cljs ...) if you really want to do that. If this isn't what you are shooting for could you please elaborate on what you want to achieve?

Abhinav03:10:36

Hey, I’m not sure if this is only works with figwheel. but I couldn’t get it to work with shadow-cljs. this is what my .cljc file looks like

(ns my.macros)

(defmacro foo [& body] (str "bar" body))
#?(:clj (intern 'clojure.core (with-meta 'foo (meta #'foo)) #'foo)
   :cljs (intern 'cljs.core (with-meta 'foo (meta #'foo)) #'foo))
I can’t intern it like this (the way you suggested on twitter)
#?(:clj (do (intern 'clojure.core (with-meta 'foo (meta #'foo)) #'foo)
            (intern 'cljs.core (with-meta 'foo (meta #'foo)) #'foo)))
because when I start the lein repl it throws an error saying it can’t resolve cljs.core the effect I’m trying to achieve is that the macro foo should be available in all clojurescript namespaces without having to explicitly import it, or the namespace.

timothypratley03:10:21

Hi, are you sure you have this code in your my/macros.cljc file:

(ns my.macros
  #?(:cljs (:require-macros [my.macros])))

#?(:clj (do (defmacro foo [& body] (str "bar" body))
            (intern 'clojure.core (with-meta 'foo (meta #'foo)) #'foo)
            (intern 'cljs.core (with-meta 'foo (meta #'foo)) #'foo)))
... the code you pasted doesn't look like what I was advertising 🙂

timothypratley03:10:20

Also might be nice to check what ClojureScript version are you using? I'm on ClojureScript 1.11.60 and Clojure 1.11.1

timothypratley03:10:18

Important thing to note about the differences in the code you pasted: The intern needs to be done in #?(:clj, not #?(:cljs because the macros (even cljs.core macros) live in CLJ land

timothypratley03:10:53

@U02CVMEFEUF does that make sense? FWIW it works for me as you describe (can use foo anywhere without referring it explicitly so long as macros has been referred anywhere prior -- this is required so that foo is interned). If you are still stuck please post a repo or some snippets?

Abhinav03:10:09

you’re right I missed this part

(ns my.macros
  #?(:cljs (:require-macros [my.macros])))
could you explain why I need to do this?

timothypratley03:10:15

Only ClojureScript can :require-macros (it's invalid in Clojure)

timothypratley03:10:45

What happens is the compiler loads CLJC files compiling to ClojureScript, but the :require-macros causes it to then load the exact same file in Clojure (because that's where the macros live), when it loads in Clojure it can't do the ClojureScript stuff, when it loads in ClojureScript it can't do the Clojure stuff

Abhinav03:10:57

I meant I’m requiring the macros defined in the same namespace, which is what I find confusing. I came across a similar pattern in cljs.core

timothypratley03:10:07

That's what makes macros in CLJC confusing 🙂

😅 1
😁 1
Abhinav03:10:09

> What happens is the compiler loads CLJC files compiling to ClojureScript, but the :require-macros causes it to then load the exact same file in Clojure (because that’s where the macros live), when it loads in Clojure it can’t do the ClojureScript stuff, when it loads in ClojureScript it can’t do the Clojure stuff oh I see

Abhinav03:10:34

I will test it out and get back to you

Abhinav10:10:01

hey @U06S1EJPL it worked, the only hitch is that I need to require-macros in one namespace, before It’s available everywhere. but I guess I can live with that. thanks. last question, the reason I could intern these macros was only because the macros are compiled in clojure, but I wouldn’t be able to intern functions :thinking_face:

timothypratley18:10:11

Right. I'm not sure how to add a function such that you can use it without requiring or referring it sorry 🤷

Abhinav14:10:26

@U06S1EJPL sorry to bother you again but If macros get compiled in clojure. then how come macroexpand and its variants don’t work when I call it inside a macro? I’ve tried using cljs.analyzer/macroexpand-1 like this

(ns my.core
  (:refer-clojure :exclude [#?(:cljs macroexpand)])
  (:require
    [cljs.analyzer :as ana]
    [clojure.walk :refer [prewalk]]))


#?(:clj (defn macroexpand*
          [env form]
          (if (contains? env :js-globals)
            (loop [form form
                   form* (ana/macroexpand-1 env form)]
              (if-not (identical? form form*)
                (recur form* (ana/macroexpand-1 env form*))
                form*))
            ;; clj
            (macroexpand form))))


#?(:clj (defn macroexpand-all
          [env form]
          (prewalk (fn [x]
                     (if (seq? x)
                       (macroexpand* env x)
                       x))
                   form)))


#?(:clj (defmacro my-macro
          [form]
          (macroexpand-all form)))
This passes the tests and the macroexpansion happens when I connect to it via the repl. but when I package it and load it via shadow-cljs.edn in another project, the macroexpansion doesn’t take place. what gives? This has been driving me crazy. The link to the code sections the functions- https://github.com/AbhinavOmprakash/snitch/blob/8657b1527e3942e7f87f335fa33f89613ca59569/src/snitch/core.cljc#L48-L69 the place I”m using it https://github.com/AbhinavOmprakash/snitch/blob/619470f6abffe680d0c94fb6fdbb2f3fc15741f6/src/snitch/core.cljc#L431

timothypratley05:10:17

Hi @U02CVMEFEUF -- Looking at the code you linked, it seems suspicious to me that defn* and other macros are not wrapped in #?(:clj) The issue is that when you load a CLJC file, it sees in the ns declaration to refer-macros so it loads the file in "Clojure", but subsequently it continues loading the file in "ClojureScript"... and thus I expect that your macros are getting replaced by ClojureScript functions! When ClojureScript compiles defmacro it actually just creates a function. You don't want that. I expect that if you wrap all your defmacro forms in #?(:clj) it might solve your issue, however I can't promise anything as it's just based on your description and the code. If that doesn't work could you please provide more instructions on how to reproduce the problem you are facing? Specifically the part about "When I package it and load it via shadow-cljs.edn in another project, the macroexpansion doesn’t take place" -- assuming the above is still a problem, could you link to the "other project" and provide instructions on how to build it, and what the expected output is?

timothypratley23:10:08

Any luck getting it to work?

Abhinav08:11:07

Hey, sorry I completely missed this. Yes I managed to get it to work. I think it was some issue with leiningen/shadow-cljs not picking up the latest version of the jar. It got resolved on its own. Thanks for your help 🙂

😎 1
👍 1
timothypratley06:11:44

Oh, great! 🙂

🙂 1