1- import { cloneDeep , isEqual } from "lodash-es" ;
1+ import { cloneDeep , isEqual , sortBy } from "lodash-es" ;
22import { type ComponentPublicInstance , type DeepReadonly , type Directive , type Ref , computed , onScopeDispose , readonly , ref , shallowReadonly , shallowRef , watch , type ComputedGetter , type Component , type VNodeProps , type AllowedComponentProps , onBeforeUnmount , onMounted , toRaw , type FunctionDirective , effectScope , toRef } from "vue" ;
33import { shouldHandleGlobalShortcut , useDomEventListener , type AnyRef } from "./utils" ;
44
@@ -219,5 +219,42 @@ export function useKeyboardShortcut(el: Ref<HTMLElement | undefined>, key: AnyRe
219219}
220220
221221export const vKeyboardShortcut = vDirectiveWithScope < HTMLElement , string [ ] | string | undefined > ( ( el , binding ) => {
222- useKeyboardShortcut ( toRef ( el ) , binding . value ) ;
222+ const keys = Array . isArray ( binding . value ) ? binding . value : binding . value ? [ binding . value ] : [ ] ;
223+ useKeyboardShortcut ( toRef ( el ) , keys ) ;
224+
225+ // If the shortcut is a letter key and the letter is contained in the element text, wrap it in a <kbd> element to indicate the shortcut
226+ if ( ! el . querySelector ( "kbd" ) ) {
227+ const letterKeys = keys . flatMap ( ( k ) => k . length === 1 ? [ k . toLowerCase ( ) ] : [ ] ) ;
228+ if ( letterKeys . length > 0 ) {
229+ const nodeIterator = document . createNodeIterator ( el , NodeFilter . SHOW_TEXT ) ;
230+ let currentNode : Text | null ;
231+ while ( currentNode = nodeIterator . nextNode ( ) as Text | null ) {
232+ const node = currentNode ;
233+
234+ const lowerText = node . data . toLowerCase ( ) ;
235+ const positions = sortBy ( letterKeys . map ( ( k ) => [ k , lowerText . indexOf ( k ) ] as const ) . filter ( ( [ k , i ] ) => i !== - 1 ) , ( [ k , i ] ) => i ) ;
236+ if ( positions . length > 0 ) {
237+ const text = node . data ;
238+
239+ node . data = text . slice ( positions [ 0 ] [ 1 ] + 1 ) ;
240+
241+ const beforeNode = document . createTextNode ( text . slice ( 0 , positions [ 0 ] [ 1 ] ) ) ;
242+ node . parentNode ! . insertBefore ( beforeNode , node ) ;
243+
244+ const kbd = document . createElement ( "kbd" ) ;
245+ kbd . classList . add ( "fm-shortcut" ) ;
246+ kbd . appendChild ( document . createTextNode ( text . slice ( positions [ 0 ] [ 1 ] , positions [ 0 ] [ 1 ] + 1 ) ) ) ;
247+ node . parentNode ! . insertBefore ( kbd , node ) ;
248+
249+ onScopeDispose ( ( ) => {
250+ beforeNode . remove ( ) ;
251+ kbd . remove ( ) ;
252+ node . data = text ;
253+ } ) ;
254+
255+ break ;
256+ }
257+ }
258+ }
259+ }
223260} ) ;
0 commit comments