Explorar el Código

fix: add state to pause existing audio for demo menus, add support fo… (#10428)

Joseph Campuzano hace 4 semanas
padre
commit
15801a01ba

+ 26 - 6
packages/app/src/components/settings-general.tsx

@@ -7,6 +7,26 @@ import { useSettings, monoFontFamily } from "@/context/settings"
 import { playSound, SOUND_OPTIONS } from "@/utils/sound"
 import { Link } from "./link"
 
+
+let demoSoundState = {
+  cleanup: undefined as (() => void) | undefined,
+  timeout: undefined as NodeJS.Timeout | undefined,
+}
+
+// To prevent audio from overlapping/playing very quickly when navigating the settings menus, 
+// delay the playback by 100ms during quick selection changes and pause existing sounds.
+const playDemoSound = (src: string) => {
+  if (demoSoundState.cleanup) {
+    demoSoundState.cleanup();
+  }
+
+  clearTimeout(demoSoundState.timeout)
+
+  demoSoundState.timeout = setTimeout(() => {
+    demoSoundState.cleanup = playSound(src)
+  }, 100)
+}
+
 export const SettingsGeneral: Component = () => {
   const theme = useTheme()
   const language = useLanguage()
@@ -211,12 +231,12 @@ export const SettingsGeneral: Component = () => {
                 label={(o) => language.t(o.label)}
                 onHighlight={(option) => {
                   if (!option) return
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 onSelect={(option) => {
                   if (!option) return
                   settings.sounds.setAgent(option.id)
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 variant="secondary"
                 size="small"
@@ -235,12 +255,12 @@ export const SettingsGeneral: Component = () => {
                 label={(o) => language.t(o.label)}
                 onHighlight={(option) => {
                   if (!option) return
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 onSelect={(option) => {
                   if (!option) return
                   settings.sounds.setPermissions(option.id)
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 variant="secondary"
                 size="small"
@@ -259,12 +279,12 @@ export const SettingsGeneral: Component = () => {
                 label={(o) => language.t(o.label)}
                 onHighlight={(option) => {
                   if (!option) return
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 onSelect={(option) => {
                   if (!option) return
                   settings.sounds.setErrors(option.id)
-                  playSound(option.src)
+                  playDemoSound(option.src)
                 }}
                 variant="secondary"
                 size="small"

+ 8 - 1
packages/app/src/utils/sound.ts

@@ -106,5 +106,12 @@ export function soundSrc(id: string | undefined) {
 export function playSound(src: string | undefined) {
   if (typeof Audio === "undefined") return
   if (!src) return
-  void new Audio(src).play().catch(() => undefined)
+  const audio = new Audio(src)
+  audio.play().catch(() => undefined)
+
+  // Return a cleanup function to pause the sound.
+  return () => {
+    audio.pause()
+    audio.currentTime = 0
+  }
 }

+ 1 - 0
packages/ui/src/components/select.tsx

@@ -105,6 +105,7 @@ export function Select<T>(props: SelectProps<T> & Omit<ButtonProps, "children">)
           }}
           onPointerEnter={() => move(itemProps.item.rawValue)}
           onPointerMove={() => move(itemProps.item.rawValue)}
+          onFocus={() => move(itemProps.item.rawValue)}
         >
           <Kobalte.ItemLabel data-slot="select-select-item-label">
             {local.children