benwinding/command-pal

Accessing internal state of CP from command handlers.

Opened this issue · 1 comments

I am looking at implementing a formatting function for a text area to be triggered from
command pal. To do this, being able to see what control was focused when command-pal
was invoked would be valuable.

Obviously I can't find that when command-pal is active as focus is in the search input.
In pull #33 I set focusedElement to store that data when command-pal is activated by
hotkey or button click.

It would be nice to access that from c.focusedElement (c=CommandPal(...)) or something.
Any ideas on how to do this cleanly?

I did manage to add a new displayPalette() method on #28. But the implementation feels hacky.

I have a new way to do this that should replace #28 (issue #25) as well as expose internal state.

In main.js:

appInternalInfo: object = { focusedElement: null; displayPalette: null, ...};

class CommandPal {
...
  start () {
     this.app = new App({ ...,
          props: { ...
             exposeInternals: appInternalInfo,
         } });

  displayPalette(state) { appInternalInfo.displayPalette(state) }

   /* use setter/getter on (virtual) focusedElement property of CommandPal  */
  get focusedElement() {
    return appInternalInfo.focusedElement && appInternalInfo.focusedElement()
  }

  set focusedElement(newElement) {
    return appInternalInfo.focusedElement(newElement)
  }

in App.svelte:

...
  export let exposeInternals: any; // should be object, but without creating an
                                   // interface here and needing to keep it in sync
                                   // with appInternalInfo in main.js any will do;

  let focusedElement: HTMLElement | null = null;  // also requires casting all
                                              // <HTMLElement>document.activeElement
   exposeInternals.focusedElement = (newValue) => (
       newValue ? focusedElement=newValue : focusedElement )

  exposeInternals.displayPalette = async active_state => {
     if (! showModal) {focusedElement = <HTMLElement>document.activeElement}
     if (active_state === undefined) {
       showModal = !showModal;
    } else if ([true, false].includes(active_state)) {
       showModal = active_state;
    } else {
       throw("Non-boolean: " + active_state +
             " - passed to displayPalette")
    }
  }

  onMount(() => { ... }

This removed the need for an entire file and functions used to pass the displayPalette method.
For read only props, you could use:

$: exposeInternals.read_me = showModal

Plus you can expose both hotkey.js and Fuse that are bundled into command-pal to the
web page so they don't have to load those libraries and can piggyback off the bundled ones.

// in shortcuts.js use
export hk = hotkey;

// in App.svelte
import hk from "./shortcuts";
exposeInternals.Fuse = Fuse
exposeInternals.hotkey = hk

Thoughts?