How can I use use:registerFocus conditionally in Svelte?

Viewed 37

Edit: sadly the wrapping approach used in this answer doesn't seem to work for focusing inputs: https://svelte.dev/repl/41625a0612354910aaa59c5a71499977?version=3.50.1

I am using the useFocus() directive from Svelte Navigator. I have an Input component I use for input boxes - I'd like to add a prop isFocused so one instance of Input can be focused but other instances of Input will not be focused.

How can I use use:registerFocus conditionally in Svelte?

Example on Svelte REPL

Input.svelte:

<script>
  import { useFocus } from "svelte-navigator";
  const registerFocus = useFocus();
    
    // How do I makes the component only enable use:registerFocus if isFocused is true?
    export let isFocused 
    export let value
    
    const maybeRegisterFocus = (element, isFocused) => {
        console.log(`Registering focus for '${value}': ${isFocused}`)
        if (isFocused) {
       registerFocus(element);
    }
    return {
      update: (isFocused) => {
                console.log(`Updating for element`, element)
        if (isFocused) {
          registerFocus(element);
        }
        return null;
      },
      destroy: () => {
        return null;
      },
    };
  };
</script>


<input use:maybeRegisterFocus={isFocused} value={value} />

App.svelte:

<script>
import { Router, Route } from "svelte-navigator";
import Input from "./Input.svelte"
</script>

<Router>
<Route>
    <h1>
        The first input box shoudl be focused.
        <Input isFocused={true} value="First text box should be focused"/>
    <Input isFocused={false} value="Second text box should not be focused"/>

    </h1>
</Route>
</Router>
1 Answers

Wrapping the action is the correct approach, the only issue here is that useFocus has side effects. Essentially once you call that, you also have to use the action.

One way around this would be to create a wrapping component that either sets a context or passes on the action from useFocus to its slot.

E.g. using a context:

<Route>
    <FocusContext>
        <h1>
            Hello world
            <Input isFocused={true} value="First text box should be focused"/>
            <Input isFocused={false} value="Second text box should not be focused"/>
        </h1>
    </FocusContext>
</Route>
<!-- FocusContext -->
<script context="module">
    import { getContext } from 'svelte';
    export const getFocusContext = () => getContext('FocusContext');
</script>
<script>
    import { useFocus } from "svelte-navigator";
    import { setContext } from 'svelte';

    const focus = useFocus();
    setContext('FocusContext', focus);
</script>
 
<slot />
<!-- Input.svelte -->
<script>
    import { getFocusContext } from './FocusContext.svelte';

    export let isFocused;
    export let value;
    
    const focus = getFocusContext();
    const maybeFocus = node => isFocused && focus(node);
</script>

<input use:maybeFocus value={value} />

REPL

Related