ui icon indicating copy to clipboard operation
ui copied to clipboard

Add the ability to change shortcuts dynamically with defineShortcuts. E.g. customizable shortcuts

Open Jordan-Ellis opened this issue 1 year ago • 3 comments

A common paradigm for apps is the ability to customize certain shortcuts. It would be awesome if you could pass a reference to the defineShortcuts method so that you can change shortcuts on the fly.

From what I can tell from the docs, this currently isn't possible.

Here's a basic example

<template>
    <button @click="changeShortcut">Change shortcut to meta + j</button>
</template>

<script setup>
const customizedShortcuts = ref({
  meta_k: {
    usingInput: true,
    handler: () => {
      alert("shortcut triggered")
    }
  }
})

// Change the shortcut ref, updating the shortcut
function changeShortcut() {
    const shortcut = customizedShortcuts.value.meta_k

    delete customizedShortcuts.value.meta_k
    customizedShortcuts.value.meta_j = shortcut
}

defineShortcuts(customizedShortcuts)
</script>

Jordan-Ellis avatar Sep 16 '23 19:09 Jordan-Ellis

@Jordan-Ellis , try this code.

<script setup>
const customizedShortcuts = reactive({
  meta_k: {
    usingInput: true,
    handler: () => {
      console.log('shortcut triggered')
    }
  }
})

function changeShortcut () {
  const shortcut = customizedShortcuts.meta_k

  delete customizedShortcuts.meta_k
  customizedShortcuts.meta_j = shortcut
}

watch(customizedShortcuts, () => {
  console.log('customizedShortcuts changed')
  defineShortcuts(customizedShortcuts)
}, { deep: true, immediate: true })
</script>

Levy-from-Odessa avatar Sep 19 '23 18:09 Levy-from-Odessa

Hi @Jorda@Jordan-Ellis !

Thanks for the feedback, indeed it could be very helpful even if we didn't need it for now.

First, I would discourage playing with the ShortcutsConfig object as it has already been "consumed" to declare each shortcut and all events listeners are registered. Making a delete on a shortcut will not unregister it.

As a short term solution, I would invite you to take advantage of the whenever feature. In your case this would give:

<template>
  <div>
    <UButton label="Switch shortcut" @click="switchShortcut" />
  </div>
</template>

<script setup lang="ts">
defineShortcuts({
  meta_k: {
    usingInput: true,
    whenever: [() => !shortcutSwitched.value],
    handler: () => {
      console.log('shortcut meta_k triggered')
    }
  },
  meta_j: {
    usingInput: true,
    whenever: [() => shortcutSwitched.value],
    handler: () => {
      console.log('shortcut meta_j triggered')
    }
  }
})

const shortcutSwitched = ref(false)

function switchShortcut () {
  shortcutSwitched.value = !shortcutSwitched.value
}
</script>

But in a more long term, handling a Ref would be very convenient. I'll try to give it a shot and make a PR in the following days/weeks.

smarroufin avatar Sep 26 '23 09:09 smarroufin

Awesome! I'm glad to hear your considering it!

Jordan-Ellis avatar Oct 19 '23 23:10 Jordan-Ellis