1
0
Fork 0

Allow to disable all hotkeys

Added angular2-hotkeys dependency inside PeerTube, to tweak some
settings

It will also allow us to support non latin keyboard in the future as we
can choose the "mouse trap" dependency
This commit is contained in:
Chocobozzz 2023-10-09 15:33:19 +02:00
parent e6b455b4ea
commit 50e415e12e
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
20 changed files with 332 additions and 141 deletions

View File

@ -195,7 +195,6 @@
"path-browserify",
"deep-merge",
"escape-string-regexp",
"mousetrap",
"is-plain-object",
"parse-srcset",
"deepmerge",

View File

@ -84,7 +84,6 @@
"@wdio/mocha-framework": "^8.10.4",
"@wdio/shared-store-service": "^8.10.5",
"@wdio/spec-reporter": "^8.10.5",
"angular2-hotkeys": "^13.1.0",
"angularx-qrcode": "16.0.0",
"babel-loader": "^9.1.0",
"bootstrap": "^5.1.3",
@ -126,6 +125,7 @@
"socket.io-client": "^4.5.4",
"stylelint": "^15.1.0",
"stylelint-config-sass-guidelines": "^10.0.0",
"tinykeys": "^2.1.0",
"ts-loader": "^9.3.0",
"ts-node": "^10.9.1",
"tslib": "^2.4.0",

View File

@ -1,9 +1,8 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Subscription } from 'rxjs'
import { catchError, distinctUntilChanged, map, switchMap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { AuthService, MarkdownService, Notifier, RestExtractor, ScreenService } from '@app/core'
import { AuthService, MarkdownService, Notifier, RestExtractor, ScreenService, Hotkey, HotkeysService } from '@app/core'
import { Account, ListOverflowItem, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
import { BlocklistService } from '@app/shared/shared-moderation'
import { SupportModalComponent } from '@app/shared/shared-support-modal'
@ -77,12 +76,12 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
})
this.hotkeys = [
new Hotkey('S', (event: KeyboardEvent): boolean => {
if (this.subscribeButton.subscribed) this.subscribeButton.unsubscribe()
new Hotkey('Shift+s', () => {
if (this.subscribeButton.isSubscribedToAll()) this.subscribeButton.unsubscribe()
else this.subscribeButton.subscribe()
return false
}, undefined, $localize`Subscribe to the account`)
}, $localize`Subscribe to the account`)
]
if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys)

View File

@ -1,7 +1,6 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Observable } from 'rxjs'
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'
import { Notifier, ScreenService } from '@app/core'
import { Notifier, ScreenService, Hotkey, HotkeysService } from '@app/core'
import { VideoDetails, VideoService } from '@app/shared/shared-main'
import { UserVideoRateType } from '@peertube/peertube-models'
@ -41,15 +40,15 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
if (this.isUserLoggedIn) {
this.hotkeys = [
new Hotkey('shift+l', () => {
new Hotkey('Shift+l', () => {
this.setLike()
return false
}, undefined, $localize`Like the video`),
}, $localize`Like the video`),
new Hotkey('shift+d', () => {
new Hotkey('Shift+d', () => {
this.setDislike()
return false
}, undefined, $localize`Dislike the video`)
}, $localize`Dislike the video`)
]
this.hotkeysService.add(this.hotkeys)

View File

@ -1,4 +1,3 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { forkJoin, map, Observable, of, Subscription, switchMap } from 'rxjs'
import { PlatformLocation } from '@angular/common'
import { Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
@ -13,6 +12,8 @@ import {
RestExtractor,
ScreenService,
ServerService,
Hotkey,
HotkeysService,
User,
UserService
} from '@app/core'
@ -866,33 +867,33 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.hotkeys = [
// These hotkeys are managed by the player
new Hotkey('f', e => e, undefined, $localize`Enter/exit fullscreen`),
new Hotkey('space', e => e, undefined, $localize`Play/Pause the video`),
new Hotkey('m', e => e, undefined, $localize`Mute/unmute the video`),
new Hotkey('f', e => e, $localize`Enter/exit fullscreen`),
new Hotkey('space', e => e, $localize`Play/Pause the video`),
new Hotkey('m', e => e, $localize`Mute/unmute the video`),
new Hotkey('up', e => e, undefined, $localize`Increase the volume`),
new Hotkey('down', e => e, undefined, $localize`Decrease the volume`),
new Hotkey('up', e => e, $localize`Increase the volume`),
new Hotkey('down', e => e, $localize`Decrease the volume`),
new Hotkey('t', e => {
this.theaterEnabled = !this.theaterEnabled
return false
}, undefined, $localize`Toggle theater mode`)
}, $localize`Toggle theater mode`)
]
if (!video.isLive) {
this.hotkeys = this.hotkeys.concat([
// These hotkeys are also managed by the player but only for VOD
new Hotkey('0-9', e => e, undefined, $localize`Skip to a percentage of the video: 0 is 0% and 9 is 90%`),
new Hotkey('0-9', e => e, $localize`Skip to a percentage of the video: 0 is 0% and 9 is 90%`),
new Hotkey('right', e => e, undefined, $localize`Seek the video forward`),
new Hotkey('left', e => e, undefined, $localize`Seek the video backward`),
new Hotkey('right', e => e, $localize`Seek the video forward`),
new Hotkey('left', e => e, $localize`Seek the video backward`),
new Hotkey('>', e => e, undefined, $localize`Increase playback rate`),
new Hotkey('<', e => e, undefined, $localize`Decrease playback rate`),
new Hotkey('>', e => e, $localize`Increase playback rate`),
new Hotkey('<', e => e, $localize`Decrease playback rate`),
new Hotkey(',', e => e, undefined, $localize`Navigate in the video to the previous frame`),
new Hotkey('.', e => e, undefined, $localize`Navigate in the video to the next frame`)
new Hotkey(',', e => e, $localize`Navigate in the video to the previous frame`),
new Hotkey('.', e => e, $localize`Navigate in the video to the next frame`)
])
}
@ -903,7 +904,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
else this.subscribeButton.subscribe()
return false
}, undefined, $localize`Subscribe to the account`)
}, $localize`Subscribe to the account`)
])
}

View File

@ -2,7 +2,7 @@
<a i18n class="visually-hidden-focusable skip-to-content" href="#content" (click)="$event.preventDefault(); mainContent.focus()">Skip to main content</a>
<my-hotkeys-cheatsheet (hotkeysModalStateChange)="onHotkeysModalStateChange($event)"></my-hotkeys-cheatsheet>
<my-hotkeys-cheat-sheet (hotkeysModalStateChange)="onHotkeysModalStateChange($event)"></my-hotkeys-cheat-sheet>
<div
class="peertube-container"

View File

@ -1,4 +1,3 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { delay, forkJoin } from 'rxjs'
import { filter, first, map } from 'rxjs/operators'
import { DOCUMENT, getLocaleDirection, PlatformLocation } from '@angular/common'
@ -15,7 +14,9 @@ import {
ServerService,
ThemeService,
User,
UserLocalStorageService
UserLocalStorageService,
Hotkey,
HotkeysService
} from '@app/core'
import { HooksService } from '@app/core/plugins/hooks.service'
import { PluginService } from '@app/core/plugins/plugin.service'
@ -313,40 +314,40 @@ export class AppComponent implements OnInit, AfterViewInit {
private initHotkeys () {
this.hotkeysService.add([
new Hotkey([ '/', 's' ], (event: KeyboardEvent): boolean => {
new Hotkey([ '/', 's' ], () => {
document.getElementById('search-video').focus()
return false
}, undefined, $localize`Focus the search bar`),
}, $localize`Focus the search bar`),
new Hotkey('b', (event: KeyboardEvent): boolean => {
new Hotkey('b', () => {
this.menu.toggleMenu()
return false
}, undefined, $localize`Toggle the left menu`),
}, $localize`Toggle the left menu`),
new Hotkey('g o', (event: KeyboardEvent): boolean => {
new Hotkey('g o', () => {
this.router.navigate([ '/videos/overview' ])
return false
}, undefined, $localize`Go to the discover videos page`),
}, $localize`Go to the discover videos page`),
new Hotkey('g t', (event: KeyboardEvent): boolean => {
new Hotkey('g t', () => {
this.router.navigate([ '/videos/trending' ])
return false
}, undefined, $localize`Go to the trending videos page`),
}, $localize`Go to the trending videos page`),
new Hotkey('g r', (event: KeyboardEvent): boolean => {
new Hotkey('g r', () => {
this.router.navigate([ '/videos/recently-added' ])
return false
}, undefined, $localize`Go to the recently added videos page`),
}, $localize`Go to the recently added videos page`),
new Hotkey('g l', (event: KeyboardEvent): boolean => {
new Hotkey('g l', () => {
this.router.navigate([ '/videos/local' ])
return false
}, undefined, $localize`Go to the local videos page`),
}, $localize`Go to the local videos page`),
new Hotkey('g u', (event: KeyboardEvent): boolean => {
new Hotkey('g u', () => {
this.router.navigate([ '/videos/upload' ])
return false
}, undefined, $localize`Go to the videos upload page`)
}, $localize`Go to the videos upload page`)
])
}

View File

@ -26,6 +26,7 @@ import { SharedGlobalIconModule } from './shared/shared-icons'
import { SharedInstanceModule } from './shared/shared-instance'
import { SharedMainModule } from './shared/shared-main'
import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings'
import { HotkeysCheatSheetComponent } from './hotkeys'
registerLocaleData(localeOc, 'oc')
@ -63,7 +64,9 @@ export function loadConfigFactory (server: ServerService, pluginService: PluginS
CustomModalComponent,
AdminWelcomeModalComponent,
InstanceConfigWarningModalComponent,
ConfirmComponent
ConfirmComponent,
HotkeysCheatSheetComponent
],
imports: [

View File

@ -1,4 +1,4 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Hotkey, HotkeysService } from '@app/core'
import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http'
@ -57,22 +57,22 @@ export class AuthService {
// Set HotKeys
this.hotkeys = [
new Hotkey('m s', (event: KeyboardEvent): boolean => {
new Hotkey('m s', e => {
this.router.navigate([ '/videos/subscriptions' ])
return false
}, undefined, $localize`Go to my subscriptions`),
new Hotkey('m v', (event: KeyboardEvent): boolean => {
}, $localize`Go to my subscriptions`),
new Hotkey('m v', e => {
this.router.navigate([ '/my-library/videos' ])
return false
}, undefined, $localize`Go to my videos`),
new Hotkey('m i', (event: KeyboardEvent): boolean => {
}, $localize`Go to my videos`),
new Hotkey('m i', e => {
this.router.navigate([ '/my-library/video-imports' ])
return false
}, undefined, $localize`Go to my imports`),
new Hotkey('m c', (event: KeyboardEvent): boolean => {
}, $localize`Go to my imports`),
new Hotkey('m c', e => {
this.router.navigate([ '/my-library/video-channels' ])
return false
}, undefined, $localize`Go to my channels`)
}, $localize`Go to my channels`)
]
}

View File

@ -1,4 +1,3 @@
import { HotkeyModule } from 'angular2-hotkeys'
import { MessageService } from 'primeng/api'
import { ToastModule } from 'primeng/toast'
import { CommonModule } from '@angular/common'
@ -8,7 +7,6 @@ import { PeerTubeSocket } from '@app/core/notification/peertube-socket.service'
import { HooksService, PluginService } from '@app/core/plugins'
import { AuthService } from './auth'
import { ConfirmService } from './confirm'
import { CheatSheetComponent } from './hotkeys'
import { MenuService } from './menu'
import { throwIfAlreadyLoaded } from './module-import-guard'
import { Notifier } from './notification'
@ -32,30 +30,23 @@ import { ServerService } from './server'
import { ThemeService } from './theme'
import { UserLocalStorageService, UserService } from './users'
import { LocalStorageService, ScreenService, SessionStorageService } from './wrappers'
import { HotkeysService } from './hotkeys'
@NgModule({
imports: [
CommonModule,
BrowserAnimationsModule,
ToastModule,
HotkeyModule.forRoot({
cheatSheetCloseEsc: true,
cheatSheetDescription: $localize`Show/hide this help menu`,
cheatSheetCloseEscDescription: $localize`Hide this help menu`
})
ToastModule
],
declarations: [
CheatSheetComponent,
HomepageRedirectComponent
],
exports: [
ToastModule,
CheatSheetComponent,
HomepageRedirectComponent
],
@ -97,7 +88,9 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra
ScrollService,
MetaService,
MetaGuard
MetaGuard,
HotkeysService
]
})
export class CoreModule {

View File

@ -0,0 +1,59 @@
// Thanks to https://github.com/brtnshrdr/angular2-hotkeys
import { arrayify } from '@peertube/peertube-core-utils'
export class Hotkey {
private formattedHotkey: string[]
static symbolize (combo: string): string {
const map: any = {
command: '\u2318', // ⌘
shift: '\u21E7', // ⇧
left: '\u2190', // ←
right: '\u2192', // →
up: '\u2191', // ↑
down: '\u2193', // ↓
return: '\u23CE', // ⏎
backspace: '\u232B' // ⌫
}
const comboSplit: string[] = combo.split('+')
for (let i = 0; i < comboSplit.length; i++) {
// try to resolve command / ctrl based on OS:
if (comboSplit[i] === 'mod') {
if (window.navigator?.platform.includes('Mac')) {
comboSplit[i] = 'command'
} else {
comboSplit[i] = 'ctrl'
}
}
comboSplit[i] = map[comboSplit[i]] || comboSplit[i]
}
return comboSplit.join(' + ')
}
constructor (
public combo: string | string[],
public callback: (event: KeyboardEvent, combo: string) => any | boolean,
public description?: string | Function
) {
this.combo = arrayify(combo)
this.description = description || ''
}
get formatted (): string[] {
if (!this.formattedHotkey) {
const sequence: string[] = [ ...this.combo ]
for (let i = 0; i < sequence.length; i++) {
sequence[i] = Hotkey.symbolize(sequence[i])
}
this.formattedHotkey = sequence
}
return this.formattedHotkey
}
}

View File

@ -1,53 +0,0 @@
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Subscription } from 'rxjs'
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
@Component({
selector: 'my-hotkeys-cheatsheet',
templateUrl: './hotkeys.component.html',
styleUrls: [ './hotkeys.component.scss' ]
})
export class CheatSheetComponent implements OnInit, OnDestroy {
@Input() title = $localize`Keyboard Shortcuts:`
@Output() hotkeysModalStateChange = new EventEmitter<boolean>()
helpVisible = false
subscription: Subscription
hotkeys: Hotkey[]
constructor (
private hotkeysService: HotkeysService
) {}
public ngOnInit (): void {
this.subscription = this.hotkeysService.cheatSheetToggle.subscribe((isOpen) => {
if (isOpen !== false) {
this.hotkeys = this.hotkeysService.hotkeys.filter(hotkey => hotkey.description)
}
if (isOpen === false) {
this.helpVisible = false
} else {
this.toggleHelpVisible()
}
this.hotkeysModalStateChange.emit(this.helpVisible)
})
}
public ngOnDestroy (): void {
if (this.subscription) {
this.subscription.unsubscribe()
}
}
public toggleCheatSheet (): void {
this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
}
public toggleHelpVisible (): void {
this.helpVisible = !this.helpVisible
}
}

View File

@ -0,0 +1,121 @@
// Thanks to https://github.com/brtnshrdr/angular2-hotkeys
import { Injectable } from '@angular/core'
import { Hotkey } from './hotkey.model'
import { Subject } from 'rxjs'
import { tinykeys } from 'tinykeys'
import debug from 'debug'
const debugLogger = debug('peertube:hotkeys')
@Injectable()
export class HotkeysService {
cheatSheetToggle = new Subject<boolean>()
private hotkeys: Hotkey[] = []
private preventIn = [ 'INPUT', 'SELECT', 'TEXTAREA' ]
private disabled = false
private removeTinyKeysStore = new Map<Hotkey, (() => void)[]>()
constructor () {
this.initCheatSheet()
}
private initCheatSheet () {
debugLogger('Init hotkeys')
this.add([
new Hotkey(
[ '?', 'Shift+?' ],
() => this.cheatSheetToggle.next(undefined),
$localize`Show / hide this help menu`
),
new Hotkey(
'escape',
() => this.cheatSheetToggle.next(false),
$localize`Hide this help menu`
)
])
}
add (hotkey: Hotkey): Hotkey
add (hotkey: Hotkey[]): Hotkey[]
add (hotkey: Hotkey | Hotkey[]): Hotkey[] | Hotkey {
if (Array.isArray(hotkey)) {
return hotkey.map(h => this.add(h))
}
this.remove(hotkey)
this.hotkeys.push(hotkey)
for (const combo of hotkey.combo) {
debugLogger('Adding hotkey ' + hotkey.formatted)
const removeTinyKey = tinykeys(window, {
[combo]: event => {
if (this.disabled) return
const target = event.target as Element
const nodeName: string = target.nodeName.toUpperCase()
if (this.preventIn.includes(nodeName)) {
return
}
const result = hotkey.callback.apply(this, [ event, combo ])
if (result === false) {
event.preventDefault()
event.stopPropagation()
}
}
})
if (!this.removeTinyKeysStore.has(hotkey)) {
this.removeTinyKeysStore.set(hotkey, [])
}
this.removeTinyKeysStore.get(hotkey).push(removeTinyKey)
}
return hotkey
}
remove (hotkey: Hotkey | Hotkey[]) {
if (Array.isArray(hotkey)) {
for (const h of hotkey) {
this.remove(h)
}
return
}
this.hotkeys = this.hotkeys.filter(h => h !== hotkey)
const removeHandlers = this.removeTinyKeysStore.get(hotkey)
if (removeHandlers) {
debugLogger('Removing hotkey ' + hotkey.formatted)
for (const removeHandler of removeHandlers) {
removeHandler()
}
}
this.removeTinyKeysStore.delete(hotkey)
}
getHotkeys () {
return this.hotkeys
}
disableHotkeys () {
this.disabled = true
}
enableHotkeys () {
this.disabled = false
}
}

View File

@ -1 +1,2 @@
export * from './hotkeys.component'
export * from './hotkey.model'
export * from './hotkeys.service'

View File

@ -2,6 +2,13 @@
<div class="cfp-hotkeys">
<h1 class="cfp-hotkeys-title">{{ title }}</h1>
<div class="d-flex justify-content-center m-3">
<my-peertube-checkbox
inputName="enable-hotkeys" [(ngModel)]="hotkeysEnabled" (ngModelChange)="onHotkeysEnabledChange()"
i18n-labelText labelText="Enable hotkeys in this web browser"
></my-peertube-checkbox>
</div>
<ul role="presentation">
<li *ngFor="let hotkey of hotkeys">
<div class="cfp-hotkeys-keys">

View File

@ -0,0 +1,74 @@
import { Subscription } from 'rxjs'
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
import { LocalStorageService, HotkeysService, Hotkey } from '@app/core'
@Component({
selector: 'my-hotkeys-cheat-sheet',
templateUrl: './hotkeys-cheat-sheet.component.html',
styleUrls: [ './hotkeys-cheat-sheet.component.scss' ]
})
export class HotkeysCheatSheetComponent implements OnInit, OnDestroy {
@Input() title = $localize`Keyboard Shortcuts`
@Output() hotkeysModalStateChange = new EventEmitter<boolean>()
hotkeysEnabled = true
helpVisible = false
subscription: Subscription
hotkeys: Hotkey[]
private readonly localStorageHotkeysDisabledKey = 'peertube-hotkeys-disabled'
constructor (
private hotkeysService: HotkeysService,
private localStorage: LocalStorageService
) {}
ngOnInit () {
if (this.localStorage.getItem(this.localStorageHotkeysDisabledKey) === 'true') {
this.hotkeysEnabled = false
this.hotkeysService.disableHotkeys()
}
this.subscription = this.hotkeysService.cheatSheetToggle.subscribe(isOpen => {
if (isOpen !== false) {
this.hotkeys = this.hotkeysService.getHotkeys().filter(hotkey => hotkey.description)
}
if (isOpen === false) {
this.helpVisible = false
} else {
this.toggleHelpVisible()
}
this.hotkeysModalStateChange.emit(this.helpVisible)
})
}
ngOnDestroy () {
if (this.subscription) {
this.subscription.unsubscribe()
}
}
toggleCheatSheet () {
this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
}
toggleHelpVisible () {
this.helpVisible = !this.helpVisible
}
onHotkeysEnabledChange () {
if (!this.hotkeysEnabled) {
this.localStorage.setItem(this.localStorageHotkeysDisabledKey, 'true')
this.hotkeysService.disableHotkeys()
return
}
this.hotkeysService.enableHotkeys()
this.localStorage.removeItem(this.localStorageHotkeysDisabledKey)
}
}

View File

@ -0,0 +1 @@
export * from './hotkeys-cheat-sheet.component'

View File

@ -1,4 +1,3 @@
import { HotkeysService } from 'angular2-hotkeys'
import * as debug from 'debug'
import { forkJoin, Subscription } from 'rxjs'
import { first, switchMap } from 'rxjs/operators'
@ -10,6 +9,7 @@ import {
AuthStatus,
AuthUser,
HooksService,
HotkeysService,
MenuSection,
MenuService,
RedirectService,

View File

@ -2460,11 +2460,6 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==
"@types/mousetrap@^1.6.9":
version "1.6.11"
resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.11.tgz#ef9620160fdcefcb85bccda8aaa3e84d7429376d"
integrity sha512-F0oAily9Q9QQpv9JKxKn0zMKfOo36KHCW7myYsmUyf2t0g+sBTbG3UleTPoguHdE1z3GLFr3p7/wiOio52QFjQ==
"@types/ms@*":
version "0.7.31"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
@ -3293,15 +3288,6 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
angular2-hotkeys@^13.1.0:
version "13.4.0"
resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-13.4.0.tgz#a96676466936556655cd64f92e1f5cd3aeac8e10"
integrity sha512-WvkouvdXtTYw3tpuaoEVF+ue41pvI2XSa8m4tVRPLzAblT/f7PG0uQO4npyjVw3oDIc7qnFkQR+oqGl1KM1eow==
dependencies:
"@types/mousetrap" "^1.6.9"
mousetrap "^1.6.5"
tslib "^2.3.1"
angularx-qrcode@16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/angularx-qrcode/-/angularx-qrcode-16.0.0.tgz#c637924b8d8f9cc344216caa80adf3810ccd5e5b"
@ -8186,11 +8172,6 @@ moment@^2.10.2:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
mousetrap@^1.6.5:
version "1.6.5"
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9"
integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==
mpd-parser@0.22.1, mpd-parser@^0.22.1:
version "0.22.1"
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.22.1.tgz#bc2bf7d3e56368e4b0121035b055675401871521"
@ -10789,6 +10770,11 @@ thunky@^1.0.2:
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
tinykeys@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-2.1.0.tgz#1341563e92a7fac9ca90053fddaf2b7553500298"
integrity sha512-/MESnqBD1xItZJn5oGQ4OsNORQgJfPP96XSGoyu4eLpwpL0ifO0SYR5OD76u0YMhMXsqkb0UqvI9+yXTh4xv8Q==
tmp@0.2.1, tmp@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"