Well, at the moment the code is a little scatter-brained, and I'm not sure I 
can make it work for 100% of the intended use-cases, yet.

For one, I want to better support "collaborative" events -- for example, 
distinguishing drag-enter and drag-leave events requires tracking across 
multiple components. This requires coordination at the master component level 
which is currently missing.

Additionally, as of 0.2.3, I'm noticing some effects from the differences 
between "render state" and out-of-render-loop states, which I'll need to 
account for.

Those caveats aside: Here's the way it hangs together.

Components are defined in one (or more) namespaces. Then there's the "ux" 
namespace, which is required by those wishing to get DnD features (and future 
"universal" features, such as "add item to selection")

The Root component of the application calls (ux/setup-ux-master [app owner 
opts] ...)  during will-mount.  

(ux/setup ...) creates some channels. One for putting drag-events onto, one for 
reporting bounds upwards, and a disperser (a mult over drag-events) so that we 
can direct drag events to interested listeners.

When root om/builds sub-components, it just passes down the data that is 
created by ux in opts.  Right now that's a bit hacky, but I hope I can 
alleviate some of that by using the new data locations (init-state, state, 
shared) in 0.2.3

When a sub-component is interested in receiving drag-events,  it calls 
(ux/register [owner ... handler-fn] 
The handler function is for drag events that the sub-component is receiving. 
(Right now, this also reports bounds upwards, which I intend to separate out 
for readability/compos-ability)

The neat part about keeping all this in the ux ns, is that we only need to look 
in the one file for where we're storing all this data (the channels etc). This 
makes changing any of that a little friendlier, and the components don't need 
to care (aside from having to call some functions in the right places)

It also means I could potentially use ::qualified-keys for collision 
protection. (I plan on trying that out soon).

ux/register finds the disperser multi-chan and taps it with a filter that only 
receives drag-events that are within the calling-components bounds, adding a 
(go..) loop with the handler-function it was passed in. The fact that every 
component controls it's own filter (via updating it's own :bounds on 
Did-Update) means we get targeted drag-events for "free".  Unfortunately, we 
don't get drag-enter and -leave, which made me sad, because the current 
solution seems so elegant.

The drag-start, drag-end, dragging functions are also in ux/ and are bound to 
the appropriate components with (om/bind ..) as usual.  These update the local 
state of the owner where appropriate, and push an event on the command channel 
when "decision" states are hit (e.g. drag-end). 

I *could* create them with handler functions as parameters, but I figured I'd 
rather have a "command handler" at the Root component level to manage app-state.

For me, I like having the logic of the components in the components, the logic 
of the application at the root level, and the logic of the 
orthogonal-user-interactivity in a separate namespace. 

Now, I have a specific application I was building this for - so this would need 
some work to be made truly "bolt-on".  (there are assumptions about the names 
of refs, which'd have to be injected, for example).

As an aside: In my application, the app-state revolves around a list of items.  
These items are displayed in multiple lists based on a filter, and sorted based 
on an attribute of the data. This means the "drop" handlers between the two 
lists simply set an attribute on the data, and React just puts them in the 
appropriate position of the relevant list in the next render pass automatically.



On Thursday, January 23, 2014 1:52:58 PM UTC-8, David Nolen wrote:
> It'd be a nice to get a detailed writeup about your approach if you have the 
> time and feel inclined :)
> 
> 
> David
> 
> 
> 
> On Thu, Jan 23, 2014 at 4:42 PM, David Pidcock <[email protected]> wrote:
> 
> 
> On Thursday, January 23, 2014 10:13:49 AM UTC-8, David Nolen wrote:
> 
> > Om's current API more or less follows this line of thinking - components 
> > are machines. However both the opaque nature of machines and the lack of 
> > fine grained control around immutable value storage (app state wrapped in 
> > an atom) have their downsides. I want Om components to have knobs. So while 
> > a component designer may decide to split their state in a certain fashion - 
> > users of the components should be able to reconfigure this without the 
> > system falling apart.
> 
> 
> 
> 
> I am enjoying the ability to add behaviours to components via merging data 
> into local component state. It's quite handy when trying to achieve 
> orthogonal separation of concerns.
> 
> 
> 
> For example - one might have several components on a page. Perhaps their 
> primary purpose is to display certain items in various ways. Perhaps you have 
> a group of items you want to split into different lists based on 
> classification rules.
> 
> 
> 
> 
> One way to do this is to extend your sub-components, or to wrap them in a 
> bigger component that manages the communication between them.
> 
> 
> 
> Using Om's opts, local-state, and shared,  lets me put all the logic (and 
> inter-component communication necessary) for drag-n-drop into a separate 
> namespace, and then I can pull into the components the DnD behaviour, and 
> implement the few handler functions for the stuff that's specific to each 
> component's concern (e.g. mutate app-state on a drop).
> 
> 
> 
> 
> Now, I've been dwelling in OO/Imperative land for a long time, so I'm sure 
> there are cooler ways to do all this.. but I'm having fun with it :D
> 
> 
> 
> 
> 
> 
> 
> --
> 
> Note that posts from new members are moderated - please be patient with your 
> first post.
> 
> ---
> 
> You received this message because you are subscribed to the Google Groups 
> "ClojureScript" group.
> 
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected].
> 
> To post to this group, send email to [email protected].
> 
> Visit this group at http://groups.google.com/group/clojurescript.

-- 
Note that posts from new members are moderated - please be patient with your 
first post.
--- 
You received this message because you are subscribed to the Google Groups 
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/clojurescript.

Reply via email to