humbleui 2023-03-17

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

👍 1

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

🤔 1

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

💯 1

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

👍 1

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 👀