This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-10
Channels
- # announcements (9)
- # babashka (19)
- # beginners (39)
- # calva (7)
- # cherry (1)
- # cider (2)
- # clojure (31)
- # clojure-europe (8)
- # clojure-norway (9)
- # datalevin (10)
- # events (2)
- # fulcro (10)
- # hyperfiddle (9)
- # joker (1)
- # lsp (50)
- # membrane (34)
- # minecraft (2)
- # missionary (21)
- # off-topic (17)
- # pedestal (1)
- # polylith (8)
- # reitit (3)
- # sql (4)
- # squint (16)
- # xtdb (14)
Is there anything I need to do to make a scroll view scrollable? I'm scrolling with a mouse and nothing happens
(defn view
[& _args]
(basic/scrollview
{:scroll-bounds [150 150]
:offset [0 0]
:body (ui/vertical-layout
(basic/textarea {:text "HELLO WORLD" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "Hello world" :border? false})
(basic/textarea {:text "goodbye world" :border? false}))}))
(java2d/run (component/make-app #'view))
All of the defui
components are pure functions. The defui
macro helps wire up all the incidental state.
I think view
would need to also be a defui
component for it to work for that example.
You can also wire up the state manually, which you might want to do if you're using your own state management
This is probably closer to what you want:
(defui view
[{:keys []}]
(basic/scrollview
{:scroll-bounds [150 150]
;; :offset [0 0]
:body (apply
ui/vertical-layout
(for [i (range 10)]
(basic/textarea {:text (get extra [::text i] "initial text") :border? false})
))}))
(java2d/run (component/make-app #'view))
I have an example/experiment of using datascript that I can clean up as an example
Not sure if you've read https://blog.phronemophobic.com/reusable-ui-components.html, but it talks about the design for creating reusable, "stateful" components with only pure functions.
One thought I had when skimming it again, the problem with the syntax introduced by references is I can't control as a user how they get resolved in the state. Wonder if it could be possible to do something similar to hyperfiddle and let them be queries on the state
> I can't control as a user how they get resolved in the state. There is a way to do it
> Wonder if it could be possible to do something similar to hyperfiddle and let them be queries on the state I'm not sure I know what you mean. Do you have a short code example?
If you think it would be easier, we could setup a time to either pair-program or discuss your ideas at some point
roughly:
[{:keys [db chat]}]
(basic/scrollview
{:scroll-bounds [150 150]
:offset [0 0]
:body (ui/vertical-layout
(d/q '[:find (pull ?e)
:in $ ?chat
:where
[?e :chat/name ?chat]]
$db
$chat))}))
I'm not sure I've got the interpretation of that syntax right. Something like a scrollview of chat UIs? Are the chats editable?
In general, my position is that the updates from the server would happen in application code that is more or less separated from the UI code.
I'm sure your busy, but I'm not really doing anything if you wanted to do a quick video call.
Just cleaned up a half-baked datascript experiment from before: https://github.com/phronmophobic/membrane-datascript/blob/main/src/com/phronemophobic/todo.clj
Oh man, I appreciate it, but like you guessed, sort of busy. Just about dinner time. Let's try to schedule something for the near future?
Sounds good. I'll be out of town from the 11-18th, so my schedule is a bit uncertain this week, but I could probably make something work.
I was thinking instead of application code handling server events, they'll first be pushed to DB, then the tx diff will be sent to the UI Whole new meaning to materializes view
Anyway, you might find the datascript experiment interesting.
(skia/run-sync
(make-app #'my-todo-app conn
;; query
[{:todo-lists [:db/id
{:todos [:complete? :description :db/id]}]}
'*]
;; root-id
1))
Which looks at least sorta similar to your example syntaxA specific screen could be a query filter + find, updates just take the diff and apply the find
Generally, I have some ideas on the backburner for integrating spec-like descriptions with components so I would be interested to see if your approach might be similar. I'm not super familiar hyperfiddle, but my main hesitation is that instead of simplifying things and taking them apart, it looks like they're making it easy to smash everything together
forget HF then, just think of screen -> filter -> db -> filtered-db -> view Where the updates emit tx updates which pass through the same filter and get added to the filtered DB and then the redrawn view just pulls from it
there are still some things to work out, but I think the datascript I linked example comes pretty close
or it's potentially a good starting point
I also wanted to leave you with one additional design challenge when integrating queries with components. Most designs start with assuming the following: 1. each component will specify a query for only the state it requires 2. the view is constructed by generating the full query for the UI which gets fed to the view function to create the UI. The challenge is that you can't do both 1 and 2 while still supporting views like tabbed views. For a tabbed view, you only want to fetch the data for the currently selected tab, but you don't know which tab is visible without first fetching the state for the tab view container. Essentially, to satisfy 1 and 2 while supporting components like tabs requires that generating the query and fetching the data need to be interleaved. Having an arbitrarily nested tabbed view of tabbed views would make a bad UI, but there are still realistic situations that require multiple interleavings of generating queries and fetching data. One workaround is to drop the requirement to only fetch the required data and instead fetch anything that could potentially be required, but that's a potentially big concession. It's not an insurmountable challenge, but it's an area that seems to have a weak story when looking at query+component frameworks like fulcro. Anyways, just some food for thought.
This is a weakness of the design My naive answer is that should be solved by composition. You want the state for tabs to be updated (maybe? I would assume yes), but not rendered. To render or not to render is different from fetching the data itself and actually building the UI. The only question is if this approach fits membrane
> You want the state for tabs to be updated (maybe? I would assume yes), but not rendered. To render or not to render is different from fetching the data itself and actually building the UI That sounds like the workaround I mentioned. Essentially, you fetch all the data that could potentially be required regardless of whether or not it gets drawn. That's pretty easy to do with membrane. That's plausible for the tab example, but let's say you have a search bar that allows you to type in an address which will show up in a map view. The data that is potentially required 1) depends on the state of the address input and 2) could potentially require the map data for every location on the planet.