membrane

Ben Sless 2022-09-10T15:30:54.985789Z

Is there anything I need to do to make a scroll view scrollable? I'm scrolling with a mouse and nothing happens

Ben Sless 2022-09-10T15:30:58.609759Z

(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))

phronmophobic 2022-09-10T15:39:03.772209Z

All of the defui components are pure functions. The defui macro helps wire up all the incidental state.

phronmophobic 2022-09-10T15:39:41.230029Z

I think view would need to also be a defui component for it to work for that example.

phronmophobic 2022-09-10T15:40:15.889259Z

You can also wire up the state manually, which you might want to do if you're using your own state management

phronmophobic 2022-09-10T15:47:46.191479Z

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))

phronmophobic 2022-09-10T15:48:47.063159Z

I have an example/experiment of using datascript that I can clean up as an example

phronmophobic 2022-09-10T15:56:49.828729Z

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.

Ben Sless 2022-09-10T15:57:21.661449Z

I read it months ago, will refresh

Ben Sless 2022-09-10T16:03:24.576869Z

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

phronmophobic 2022-09-10T16:05:06.089499Z

> I can't control as a user how they get resolved in the state. There is a way to do it

phronmophobic 2022-09-10T16:06:31.081959Z

> 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?

Ben Sless 2022-09-10T16:11:01.973019Z

I can sketch something when I get to the computer in a few min

phronmophobic 2022-09-10T16:12:00.587599Z

If you think it would be easier, we could setup a time to either pair-program or discuss your ideas at some point

Ben Sless 2022-09-10T16:18:08.927739Z

That would be very helpful. Then I could also figure if my ideas are off base

Ben Sless 2022-09-10T16:44:25.826289Z

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))}))

👀 1
phronmophobic 2022-09-10T16:50:46.278979Z

I'm not sure I've got the interpretation of that syntax right. Something like a scrollview of chat UIs? Are the chats editable?

Ben Sless 2022-09-10T16:54:09.528959Z

the chats aren't editable, but you can send messages and get updates from server

phronmophobic 2022-09-10T16:55:08.644409Z

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.

phronmophobic 2022-09-10T16:57:20.519199Z

I'm sure your busy, but I'm not really doing anything if you wanted to do a quick video call.

phronmophobic 2022-09-10T17:01:54.312099Z

Just cleaned up a half-baked datascript experiment from before: https://github.com/phronmophobic/membrane-datascript/blob/main/src/com/phronemophobic/todo.clj

Ben Sless 2022-09-10T17:02:40.604499Z

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?

phronmophobic 2022-09-10T17:03:49.132209Z

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.

Ben Sless 2022-09-10T17:04:38.051189Z

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

phronmophobic 2022-09-10T17:04:38.531319Z

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 syntax

Ben Sless 2022-09-10T17:05:26.063489Z

I'll make sure to study it and come with prepared questions!

Ben Sless 2022-09-10T17:06:20.310059Z

A specific screen could be a query filter + find, updates just take the diff and apply the find

👍 1
phronmophobic 2022-09-10T17:07:57.333119Z

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

Ben Sless 2022-09-10T17:18:26.173409Z

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

👍 1
phronmophobic 2022-09-10T17:21:48.721249Z

there are still some things to work out, but I think the datascript I linked example comes pretty close

phronmophobic 2022-09-10T17:25:12.694559Z

or it's potentially a good starting point

phronmophobic 2022-09-10T18:52:52.004869Z

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.

Ben Sless 2022-09-10T19:28:33.469729Z

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

phronmophobic 2022-09-10T19:49:22.673369Z

> 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.