vOn.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import {
  2. getCurrentInstance,
  3. DeprecationTypes,
  4. LegacyConfig,
  5. compatUtils,
  6. ComponentInternalInstance
  7. } from '@vue/runtime-core'
  8. import { hyphenate, isArray } from '@vue/shared'
  9. const systemModifiers = ['ctrl', 'shift', 'alt', 'meta']
  10. type KeyedEvent = KeyboardEvent | MouseEvent | TouchEvent
  11. const modifierGuards: Record<
  12. string,
  13. (e: Event, modifiers: string[]) => void | boolean
  14. > = {
  15. stop: e => e.stopPropagation(),
  16. prevent: e => e.preventDefault(),
  17. self: e => e.target !== e.currentTarget,
  18. ctrl: e => !(e as KeyedEvent).ctrlKey,
  19. shift: e => !(e as KeyedEvent).shiftKey,
  20. alt: e => !(e as KeyedEvent).altKey,
  21. meta: e => !(e as KeyedEvent).metaKey,
  22. left: e => 'button' in e && (e as MouseEvent).button !== 0,
  23. middle: e => 'button' in e && (e as MouseEvent).button !== 1,
  24. right: e => 'button' in e && (e as MouseEvent).button !== 2,
  25. exact: (e, modifiers) =>
  26. systemModifiers.some(m => (e as any)[`${m}Key`] && !modifiers.includes(m))
  27. }
  28. /**
  29. * @private
  30. */
  31. export const withModifiers = (fn: Function, modifiers: string[]) => {
  32. return (event: Event, ...args: unknown[]) => {
  33. for (let i = 0; i < modifiers.length; i++) {
  34. const guard = modifierGuards[modifiers[i]]
  35. if (guard && guard(event, modifiers)) return
  36. }
  37. return fn(event, ...args)
  38. }
  39. }
  40. // Kept for 2.x compat.
  41. // Note: IE11 compat for `spacebar` and `del` is removed for now.
  42. const keyNames: Record<string, string | string[]> = {
  43. esc: 'escape',
  44. space: ' ',
  45. up: 'arrow-up',
  46. left: 'arrow-left',
  47. right: 'arrow-right',
  48. down: 'arrow-down',
  49. delete: 'backspace'
  50. }
  51. /**
  52. * @private
  53. */
  54. export const withKeys = (fn: Function, modifiers: string[]) => {
  55. let globalKeyCodes: LegacyConfig['keyCodes']
  56. let instance: ComponentInternalInstance | null = null
  57. if (__COMPAT__) {
  58. instance = getCurrentInstance()
  59. if (
  60. compatUtils.isCompatEnabled(DeprecationTypes.CONFIG_KEY_CODES, instance)
  61. ) {
  62. if (instance) {
  63. globalKeyCodes = ((instance.appContext.config as any) as LegacyConfig)
  64. .keyCodes
  65. }
  66. }
  67. if (__DEV__ && modifiers.some(m => /^\d+$/.test(m))) {
  68. compatUtils.warnDeprecation(
  69. DeprecationTypes.V_ON_KEYCODE_MODIFIER,
  70. instance
  71. )
  72. }
  73. }
  74. return (event: KeyboardEvent) => {
  75. if (!('key' in event)) {
  76. return
  77. }
  78. const eventKey = hyphenate(event.key)
  79. if (modifiers.some(k => k === eventKey || keyNames[k] === eventKey)) {
  80. return fn(event)
  81. }
  82. if (__COMPAT__) {
  83. const keyCode = String(event.keyCode)
  84. if (
  85. compatUtils.isCompatEnabled(
  86. DeprecationTypes.V_ON_KEYCODE_MODIFIER,
  87. instance
  88. ) &&
  89. modifiers.some(mod => mod == keyCode)
  90. ) {
  91. return fn(event)
  92. }
  93. if (globalKeyCodes) {
  94. for (const mod of modifiers) {
  95. const codes = globalKeyCodes[mod]
  96. if (codes) {
  97. const matches = isArray(codes)
  98. ? codes.some(code => String(code) === keyCode)
  99. : String(codes) === keyCode
  100. if (matches) {
  101. return fn(event)
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. }