11import * as React from 'react' ;
22
33import { useSignal } from 'maverick.js/react' ;
4- import { uppercaseFirstChar } from 'maverick.js/std' ;
5- import { isTrackCaptionKind , type TooltipPlacement } from 'vidstack' ;
4+ import { isKeyboardClick , uppercaseFirstChar } from 'maverick.js/std' ;
5+ import { isTrackCaptionKind , type DefaultLayoutWord , type TooltipPlacement } from 'vidstack' ;
66
77import { useAudioOptions } from '../../../hooks/options/use-audio-options' ;
88import { useCaptionOptions } from '../../../hooks/options/use-caption-options' ;
@@ -694,16 +694,14 @@ export { DefaultSettingsMenu };
694694 * -----------------------------------------------------------------------------------------------*/
695695
696696function DefaultAccessibilitySubmenu ( ) {
697- const $hasCaptions = useMediaState ( 'hasCaptions' ) ,
698- label = useDefaultLayoutWord ( 'Accessibility' ) ,
697+ const label = useDefaultLayoutWord ( 'Accessibility' ) ,
699698 { icons : Icons } = useDefaultLayoutContext ( ) ;
700699
701- if ( ! $hasCaptions ) return null ;
702-
703700 return (
704701 < Menu . Root className = "vds-accessibility-menu vds-menu" >
705702 < DefaultSubmenuButton label = { label } Icon = { Icons . Menu . Accessibility } />
706703 < Menu . Content className = "vds-menu-items" >
704+ < DefaultMenuKeyboardAnimationCheckbox />
707705 < DefaultFontSubmenu />
708706 </ Menu . Content >
709707 </ Menu . Root >
@@ -712,6 +710,100 @@ function DefaultAccessibilitySubmenu() {
712710
713711DefaultAccessibilitySubmenu . displayName = 'DefaultAccessibilitySubmenu' ;
714712
713+ /* -------------------------------------------------------------------------------------------------
714+ * DefaultMenuKeyboardAnimationCheckbox
715+ * -----------------------------------------------------------------------------------------------*/
716+
717+ function DefaultMenuKeyboardAnimationCheckbox ( ) {
718+ const label = 'Keyboard Animations' ,
719+ key = 'vds-player::keyboard-animations' ,
720+ $viewType = useMediaState ( 'viewType' ) ,
721+ [ defaultChecked , setDefaultChecked ] = React . useState ( false ) ,
722+ { userPrefersKeyboardAnimations } = useDefaultLayoutContext ( ) ,
723+ translatedLabel = useDefaultLayoutWord ( label ) ;
724+
725+ React . useEffect ( ( ) => {
726+ const checked = ! ! ( localStorage . getItem ( key ) ?? true ) ;
727+ setDefaultChecked ( checked ) ;
728+ userPrefersKeyboardAnimations . set ( checked ) ;
729+ } , [ ] ) ;
730+
731+ if ( $viewType !== 'video' ) return null ;
732+
733+ function onChange ( checked : boolean ) {
734+ userPrefersKeyboardAnimations . set ( checked ) ;
735+ localStorage . setItem ( key , checked ? '1' : '' ) ;
736+ }
737+
738+ return (
739+ < div className = "vds-menu-item vds-menu-item-checkbox" >
740+ < div className = "vds-menu-checkbox-label" > { translatedLabel } </ div >
741+ < DefaultMenuCheckbox label = { label } defaultChecked = { defaultChecked } onChange = { onChange } />
742+ </ div >
743+ ) ;
744+ }
745+
746+ DefaultMenuKeyboardAnimationCheckbox . displayName = 'DefaultMenuKeyboardAnimationCheckbox' ;
747+
748+ /* -------------------------------------------------------------------------------------------------
749+ * DefaultMenuCheckbox
750+ * -----------------------------------------------------------------------------------------------*/
751+
752+ export interface DefaultMenuCheckboxProps {
753+ label : DefaultLayoutWord ;
754+ defaultChecked ?: boolean ;
755+ onChange ?( checked : boolean ) : void ;
756+ }
757+
758+ function DefaultMenuCheckbox ( {
759+ label,
760+ defaultChecked = false ,
761+ onChange,
762+ } : DefaultMenuCheckboxProps ) {
763+ const [ isChecked , setIsChecked ] = React . useState ( defaultChecked ) ,
764+ [ isActive , setIsActive ] = React . useState ( false ) ,
765+ [ isDirty , setIsDirty ] = React . useState ( false ) ,
766+ ariaLabel = useDefaultLayoutWord ( label ) ;
767+
768+ React . useEffect ( ( ) => {
769+ if ( isDirty ) return ;
770+ setIsChecked ( defaultChecked ) ;
771+ } , [ isDirty , defaultChecked ] ) ;
772+
773+ function onPress ( event ?: React . PointerEvent ) {
774+ if ( event ?. button === 1 ) return ;
775+ setIsChecked ( ! isChecked ) ;
776+ onChange ?.( ! isChecked ) ;
777+ setIsActive ( false ) ;
778+ setIsDirty ( true ) ;
779+ }
780+
781+ function onActive ( event : React . PointerEvent ) {
782+ if ( event . button !== 0 ) return ;
783+ setIsActive ( true ) ;
784+ }
785+
786+ function onKeyDown ( event : React . KeyboardEvent ) {
787+ if ( isKeyboardClick ( event . nativeEvent ) ) onPress ( ) ;
788+ }
789+
790+ return (
791+ < div
792+ className = "vds-menu-checkbox"
793+ role = "menuitemcheckbox"
794+ tabIndex = { 0 }
795+ aria-label = { ariaLabel }
796+ aria-checked = { isChecked ? 'true' : 'false' }
797+ data-active = { isActive ? '' : null }
798+ onPointerUp = { onPress }
799+ onPointerDown = { onActive }
800+ onKeyDown = { onKeyDown }
801+ />
802+ ) ;
803+ }
804+
805+ DefaultMenuCheckbox . displayName = 'DefaultMenuCheckbox' ;
806+
715807/* -------------------------------------------------------------------------------------------------
716808 * DefaultAudioSubmenu
717809 * -----------------------------------------------------------------------------------------------*/
0 commit comments