In response to a bug I found, I'm considering how to write a library option to enable the behavior of "text-input ignoring certain keys."
My exact case is that I want to input text, then press Enter to 'submit' (clear text + invoke a function.) The library currently invokes the parent :enter callback but also adds an empty newline/enter character to the end of the :text string, which triggers a UI re-update (and an exception in my bugged case.)
Here's the options I'm considering, & does anyone have any advice or thoughts before I start implementation?
-----------------
A) Implement preventDefault (ala Elm) as a supported option for the TextInput class. This would take a seq of keyword 'keys' that should be ignored.
B) Option A might be better implemented as the ability to stop further event propagation as it's "captured" from the parent to child elements? Then a wrapping focusable or on-key-focused could handle this.
C) Ignore A/B, extend :on-change as suggested by Lilactown's example in https://github.com/HumbleUI/HumbleUI/issues/68
(let [*num (atom {:text "23"})]
(ui/text-field
{:on-change #(when (Float/parseFloat %) (swap! *num assoc :text %))}
*num))
This would hypothetically allow :on-change to override the text-input's default behavior and control all set text. It will require some good refactor, as the current draft impl only invokes :on-change as a side-effect.Opened https://github.com/HumbleUI/HumbleUI/pull/71 . My initial commit breaks parent on-key-focus callbacks though, might be a better way to do this
I'm tracking down a bug where events are propagating down to the text-input class even when a higher level :enter handler returns nil on the :enter key-event.
In the worst case, :text still gets updated to include a \r at the end, but the :line value gets nil'd and the UI library crashes. It might be that triggering another update to the state during the key-event is causing this, or perhaps from blocking the UI thread for too long.
LMK if you have any pointers on this but otherwise I'll keep going until I can PR a fix
All event handlers happen on UI thread, there’s now way to hold it for too long
I’ll take a look if yoy can open an issue
Sure, I'll try to nail down a more exact repro if I can't figure it out myself.
There was one other edge --
text-input doesn't seem to work inside of a ui/dynamic block. Higher level focusable will still trigger a (mouse click) callback, but text-input doesn't respond to any key-events. I haven't gone digging yet but we'll see
that’s probably focus issue because text field is recreated by dynamic. I still have to figure it out
Try creating text input outside
It does work outside -- did a few repros with the only difference being the wrapping dynamic. It's almost certainly the cause
I'm interested in rewriting these to play nice together. Have any notes you'd want to bring up?
I wish it was so simple. I’m afraid to solve this properly you’ll need to replace dynamic with smth better
There might be an easier fix right now, probably in focus-controller somewhere. I bet your issue is that text-field loses focus
What I meant: try creating it outside (as a value) but then use that value inside dynamic
I understand it won’t always work
But might be possible in your case
Your theory is correct from tests -- creating text-field in a let above the dynamic, & then using it inside dynamic works. I see this is already open at Text field inside of dynamic loses focus when re-rendered - https://github.com/HumbleUI/HumbleUI/issues/50
I originally tried using dynamic for a wrapping router component on the state's :main-screen value. This is a nice pattern that I don't want to giveup, so I'll go looking for the simple fix you alluded to (storing text-field focus in the atom)
You mention eventually replacing dynamic with something more reliable. I understand if you're too busy for a writeup, but I'd love to know your thoughts here in case I need to try & implement this
Found some success adding key :focused to the :text-input state & having it set :focused of its wrapping Focusable component. Thanks for the clues -- code appears to work but has some awkward parts. I'll refactor & test more tomorrow
Take a look at ui/on-key-focused The way it works is that if your callback returns truth-y value, the event propagation stops and child never receives it
Returning nil fixed my UI with just a few characters. Thanks & I'll comb through the src a little more this week 👀