{"version":3,"file":"index.cjs","sources":["../src/providers/WebSpeechTTSProvider.ts","../src/providers/WebSpeechSTTProvider.ts","../src/factory.ts","../src/injectionKeys.ts","../src/composables/useSpeechSynthesis.ts","../src/composables/useSpeechRecognition.ts","../src/composables/useVoiceQueue.ts","../src/utils/sentenceBoundary.ts","../src/composables/useStreamingTTS.ts","../src/components/VueSpeechVoiceSelect.vue","../src/components/VueSpeechPlayer.vue","../src/components/VueSpeechRecorder.vue","../src/plugin.ts"],"sourcesContent":["import type { TTSProvider, SpeakOptions, VoiceInfo, SpeechError } from './types.js'\n\n// ─── WebSpeechTTSProvider ─────────────────────────────────────────────────────\n\nexport class WebSpeechTTSProvider implements TTSProvider {\n  readonly isSupported: boolean\n\n  private _startCbs: Array<() => void> = []\n  private _endCbs: Array<() => void> = []\n  private _errorCbs: Array<(err: SpeechError) => void> = []\n\n  /** Resolves with the array of available voices. Safe to call multiple times */\n  private _voicesPromise: Promise<VoiceInfo[]> | null = null\n\n  constructor() {\n    this.isSupported =\n      typeof window !== 'undefined' && 'speechSynthesis' in window\n  }\n\n  // ── Lifecycle hook registration ─────────────────────────────────────────────\n\n  onStart(cb: () => void): void {\n    this._startCbs.push(cb)\n  }\n\n  onEnd(cb: () => void): void {\n    this._endCbs.push(cb)\n  }\n\n  onError(cb: (err: SpeechError) => void): void {\n    this._errorCbs.push(cb)\n  }\n\n  private _emitStart(): void {\n    this._startCbs.forEach((cb) => cb())\n  }\n\n  private _emitEnd(): void {\n    this._endCbs.forEach((cb) => cb())\n  }\n\n  private _emitError(err: SpeechError): void {\n    this._errorCbs.forEach((cb) => cb(err))\n  }\n\n  // ── Core API ────────────────────────────────────────────────────────────────\n\n  speak(options: SpeakOptions): Promise<void> {\n    if (!this.isSupported) {\n      const err: SpeechError = {\n        code: 'NOT_SUPPORTED',\n        message: 'SpeechSynthesis is not available in this environment',\n      }\n      this._emitError(err)\n      return Promise.reject(err)\n    }\n\n    return new Promise<void>((resolve, reject) => {\n      // Cancel any in-progress utterance first\n      window.speechSynthesis.cancel()\n\n      const utterance = new SpeechSynthesisUtterance(options.text)\n\n      if (options.rate !== undefined) utterance.rate = options.rate\n      if (options.pitch !== undefined) utterance.pitch = options.pitch\n      if (options.volume !== undefined) utterance.volume = options.volume\n\n      if (options.voice) {\n        const nativeVoices = window.speechSynthesis.getVoices()\n        const match = nativeVoices.find((v) => v.voiceURI === options.voice!.id)\n        if (match) utterance.voice = match\n      }\n\n      utterance.onstart = () => {\n        this._emitStart()\n      }\n\n      utterance.onend = () => {\n        this._emitEnd()\n        resolve()\n      }\n\n      utterance.onerror = (event) => {\n        // 'interrupted' and 'canceled' are not real errors — they happen when\n        // stop() or cancel() is called intentionally\n        if (event.error === 'interrupted' || event.error === 'canceled') {\n          this._emitEnd()\n          resolve()\n          return\n        }\n\n        const err: SpeechError = {\n          code: 'UNKNOWN',\n          message: `SpeechSynthesisUtterance error: ${event.error}`,\n          cause: event,\n        }\n        this._emitError(err)\n        // Always emit onEnd after onError for consistency with AI providers\n        // (which emit onEnd in their finally block). This lets useVoiceQueue\n        // rely on a single onEnd hook for queue advancement across all providers.\n        this._emitEnd()\n        reject(err)\n      }\n\n      window.speechSynthesis.speak(utterance)\n    })\n  }\n\n  stop(): void {\n    if (this.isSupported) {\n      window.speechSynthesis.cancel()\n    }\n  }\n\n  pause(): void {\n    if (this.isSupported) {\n      window.speechSynthesis.pause()\n    }\n  }\n\n  resume(): void {\n    if (this.isSupported) {\n      window.speechSynthesis.resume()\n    }\n  }\n\n  // ── Voice loading (I-2.4: voiceschanged + 3s timeout fallback) ──────────────\n\n  getVoices(): Promise<VoiceInfo[]> {\n    if (!this.isSupported) return Promise.resolve([])\n\n    if (this._voicesPromise) return this._voicesPromise\n\n    this._voicesPromise = this._loadVoices()\n    return this._voicesPromise\n  }\n\n  private _loadVoices(): Promise<VoiceInfo[]> {\n    return new Promise<VoiceInfo[]>((resolve) => {\n      // Fast path: Chrome sometimes has voices already available\n      const immediate = window.speechSynthesis.getVoices()\n      if (immediate.length > 0) {\n        resolve(immediate.map(toVoiceInfo))\n        return\n      }\n\n      // Slow path: wait for voiceschanged (Chrome async load)\n      let resolved = false\n\n      const onVoicesChanged = () => {\n        if (resolved) return\n        resolved = true\n        window.speechSynthesis.removeEventListener('voiceschanged', onVoicesChanged)\n        resolve(window.speechSynthesis.getVoices().map(toVoiceInfo))\n      }\n\n      window.speechSynthesis.addEventListener('voiceschanged', onVoicesChanged)\n\n      // 3-second timeout fallback (Safari, Firefox where event may not fire)\n      setTimeout(() => {\n        if (resolved) return\n        resolved = true\n        window.speechSynthesis.removeEventListener('voiceschanged', onVoicesChanged)\n        resolve(window.speechSynthesis.getVoices().map(toVoiceInfo))\n      }, 3000)\n    })\n  }\n}\n\n// ─── Normalise SpeechSynthesisVoice → VoiceInfo ───────────────────────────────\n\nfunction toVoiceInfo(v: SpeechSynthesisVoice): VoiceInfo {\n  return {\n    id: v.voiceURI,\n    name: v.name,\n    lang: v.lang,\n    label: v.name,\n    default: v.default,\n  }\n}\n","import type { STTProvider, SpeechError } from './types.js'\n\n// ─── Local Web Speech API type declarations ───────────────────────────────────\n// TypeScript's DOM lib types for the Web Speech API are inconsistent across\n// compiler versions (SpeechRecognition / SpeechRecognitionEvent were removed or\n// renamed in TS 5.9). We define the minimum surface we need locally so the\n// provider compiles cleanly regardless of which lib version is installed.\n\ninterface _SpeechRecognitionAlternative {\n  readonly transcript: string\n  readonly confidence: number\n}\n\ninterface _SpeechRecognitionResult {\n  readonly isFinal: boolean\n  readonly length: number\n  [index: number]: _SpeechRecognitionAlternative\n}\n\ninterface _SpeechRecognitionResultList {\n  readonly length: number\n  [index: number]: _SpeechRecognitionResult\n}\n\ninterface _SpeechRecognitionResultEvent {\n  readonly resultIndex: number\n  readonly results: _SpeechRecognitionResultList\n}\n\ninterface _SpeechRecognitionErrorEvent {\n  readonly error: string\n  readonly message?: string\n}\n\ninterface _SpeechRecognitionInstance {\n  lang: string\n  interimResults: boolean\n  continuous: boolean\n  maxAlternatives: number\n  onresult: ((_: _SpeechRecognitionResultEvent) => void) | null\n  onerror: ((_: _SpeechRecognitionErrorEvent) => void) | null\n  onend: (() => void) | null\n  start(): void\n  stop(): void\n}\n\ninterface _SpeechRecognitionConstructor {\n  new(): _SpeechRecognitionInstance\n}\n\n// Extend Window with both standard and webkit-prefixed constructors\ndeclare global {\n  interface Window {\n    SpeechRecognition?: _SpeechRecognitionConstructor\n    webkitSpeechRecognition?: _SpeechRecognitionConstructor\n  }\n}\n\n// ─── WebSpeechSTTProvider ─────────────────────────────────────────────────────\n\nexport interface WebSpeechSTTOptions {\n  /** BCP-47 language code, e.g. 'en-US'. Defaults to browser UI lang */\n  lang?: string\n  /** Whether to return interim (non-final) results. Default: true */\n  interimResults?: boolean\n  /** Whether recognition continues after the first final result. Default: true */\n  continuous?: boolean\n  /** Maximum number of alternative transcripts per result. Default: 1 */\n  maxAlternatives?: number\n}\n\nexport class WebSpeechSTTProvider implements STTProvider {\n  readonly isSupported: boolean\n  readonly continuous: boolean\n\n  private _recognition: _SpeechRecognitionInstance | null = null\n  private _options: Required<WebSpeechSTTOptions>\n\n  private _transcriptCbs: Array<(transcript: string, confidence: number) => void> = []\n  private _finalCbs: Array<(transcript: string, confidence: number) => void> = []\n  private _endCbs: Array<() => void> = []\n  private _errorCbs: Array<(err: SpeechError) => void> = []\n\n  constructor(options: WebSpeechSTTOptions = {}) {\n    this._options = {\n      lang: options.lang ?? '',\n      interimResults: options.interimResults ?? true,\n      continuous: options.continuous ?? true,\n      maxAlternatives: options.maxAlternatives ?? 1,\n    }\n    this.continuous = this._options.continuous\n    this.isSupported =\n      typeof window !== 'undefined' &&\n      ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)\n  }\n\n  // ── Lifecycle hook registration ─────────────────────────────────────────────\n\n  onTranscript(cb: (transcript: string, confidence: number) => void): void {\n    this._transcriptCbs.push(cb)\n  }\n\n  onFinalTranscript(cb: (transcript: string, confidence: number) => void): void {\n    this._finalCbs.push(cb)\n  }\n\n  onEnd(cb: () => void): void {\n    this._endCbs.push(cb)\n  }\n\n  onError(cb: (err: SpeechError) => void): void {\n    this._errorCbs.push(cb)\n  }\n\n  // ── Core API ────────────────────────────────────────────────────────────────\n\n  start(): void {\n    if (!this.isSupported) {\n      this._emitError({\n        code: 'NOT_SUPPORTED',\n        message: 'SpeechRecognition is not available in this environment',\n      })\n      return\n    }\n\n    // Tear down any existing instance before creating a new one\n    this._teardown()\n\n    const SpeechRecognitionImpl =\n      window.SpeechRecognition ?? window.webkitSpeechRecognition!\n\n    const rec = new SpeechRecognitionImpl()\n    rec.lang = this._options.lang || navigator.language || 'en-US'\n    rec.interimResults = this._options.interimResults\n    rec.continuous = this._options.continuous\n    rec.maxAlternatives = this._options.maxAlternatives\n\n    rec.onresult = (event) => {\n      for (let i = event.resultIndex; i < event.results.length; i++) {\n        const result = event.results[i]\n        const transcript = result[0].transcript\n        const confidence = result[0].confidence\n\n        if (result.isFinal) {\n          this._finalCbs.forEach((cb) => cb(transcript, confidence))\n        } else {\n          this._transcriptCbs.forEach((cb) => cb(transcript, confidence))\n        }\n      }\n    }\n\n    rec.onerror = (event) => {\n      const code = mapSpeechRecognitionError(event.error)\n      this._emitError({\n        code,\n        message: `SpeechRecognition error: ${event.error}`,\n        cause: event,\n      })\n    }\n\n    rec.onend = () => {\n      this._endCbs.forEach((cb) => cb())\n    }\n\n    this._recognition = rec\n    rec.start()\n  }\n\n  stop(): void {\n    if (this._recognition) {\n      this._recognition.stop()\n      this._teardown()\n    }\n  }\n\n  // ── Internal helpers ────────────────────────────────────────────────────────\n\n  private _teardown(): void {\n    if (this._recognition) {\n      this._recognition.onresult = null\n      this._recognition.onerror = null\n      this._recognition.onend = null\n      this._recognition = null\n    }\n  }\n\n  private _emitError(err: SpeechError): void {\n    this._errorCbs.forEach((cb) => cb(err))\n  }\n}\n\n// ─── Map SpeechRecognitionError.error → SpeechErrorCode ──────────────────────\n\nfunction mapSpeechRecognitionError(\n  error: string,\n): import('./types.js').SpeechErrorCode {\n  switch (error) {\n    case 'not-allowed':\n    case 'service-not-allowed':\n      return 'PERMISSION_DENIED'\n    case 'network':\n      return 'NETWORK'\n    case 'no-speech':\n    case 'audio-capture':\n    case 'aborted':\n      return 'CANCELLED'\n    default:\n      return 'UNKNOWN'\n  }\n}\n","import type { TTSProvider, ProviderConfig } from './providers/types.js'\nimport { WebSpeechTTSProvider } from './providers/WebSpeechTTSProvider.js'\n\n/**\n * Factory — returns the correct `TTSProvider` for the given config.\n *\n * AI providers (openai, elevenlabs, azure) are loaded via dynamic import so\n * they are excluded from the bundle when not used (tree-shaking).\n */\nexport async function createVueSpeech(config: ProviderConfig): Promise<TTSProvider> {\n  switch (config.provider) {\n    case 'web':\n      return new WebSpeechTTSProvider()\n\n    case 'openai': {\n      const { OpenAIProvider } = await import('./providers/OpenAIProvider.js')\n      return new OpenAIProvider(config)\n    }\n\n    case 'elevenlabs': {\n      const { ElevenLabsProvider } = await import('./providers/ElevenLabsProvider.js')\n      return new ElevenLabsProvider(config)\n    }\n\n    case 'azure': {\n      const { AzureProvider } = await import('./providers/AzureProvider.js')\n      return new AzureProvider(config)\n    }\n\n    default: {\n      const _exhaustive: never = config\n      throw new Error(`Unknown provider: ${(_exhaustive as ProviderConfig).provider}`)\n    }\n  }\n}\n\n/**\n * Synchronous factory for the web provider only.\n * Used internally by composables as the no-config fallback (I-4.1).\n */\nexport function createWebSpeechProvider(): TTSProvider {\n  return new WebSpeechTTSProvider()\n}\n","import type { InjectionKey } from 'vue'\nimport type { TTSProvider } from './providers/types.js'\n\n/**\n * Vue injection key used by `app.provide()` (via the VueSpeech plugin)\n * and `inject()` (inside composables) to pass the active TTSProvider\n * down the component tree without prop-drilling.\n */\nexport const SPEECH_PROVIDER_KEY: InjectionKey<TTSProvider> = Symbol('VueSpeechProvider')\n","import {\n  ref,\n  shallowRef,\n  readonly,\n  inject,\n  onUnmounted,\n  type Ref,\n  type ShallowRef,\n} from 'vue'\nimport { SPEECH_PROVIDER_KEY } from '../injectionKeys.js'\nimport { createWebSpeechProvider } from '../factory.js'\nimport type { TTSProvider, SpeakOptions, VoiceInfo, SpeechError } from '../providers/types.js'\n\n// ─── Options & Return type ────────────────────────────────────────────────────\n\nexport interface UseSpeechSynthesisOptions {\n  /** Override the injected provider for this composable instance only */\n  provider?: TTSProvider\n  /** Initial speech rate (0.1–10, default 1) */\n  rate?: number\n  /** Initial pitch (0–2, default 1) */\n  pitch?: number\n  /** Initial volume (0–1, default 1) */\n  volume?: number\n}\n\nexport interface UseSpeechSynthesisReturn {\n  /** Whether the provider is available in this environment */\n  readonly isSupported: Readonly<ShallowRef<boolean>>\n  /** Whether speech is currently playing */\n  readonly isSpeaking: Readonly<ShallowRef<boolean>>\n  /** Whether speech is paused */\n  readonly isPaused: Readonly<ShallowRef<boolean>>\n  /** Voices available from the provider (loads async for AI providers) */\n  readonly voices: Readonly<Ref<readonly VoiceInfo[]>>\n  /** True while voices are being fetched */\n  readonly isLoadingVoices: Readonly<ShallowRef<boolean>>\n  /** Currently selected voice */\n  readonly selectedVoice: Ref<VoiceInfo | undefined>\n  /**\n   * Speech rate — changes apply to the **next** `speak()` call.\n   * (I-4.4: rate/pitch changes do NOT affect the current utterance)\n   */\n  readonly rate: Ref<number>\n  /** Pitch — changes apply to the **next** `speak()` call (I-4.4) */\n  readonly pitch: Ref<number>\n  /** Volume — changes apply to the **next** `speak()` call */\n  readonly volume: Ref<number>\n  /** Most recent error, cleared on next `speak()` */\n  readonly error: Readonly<ShallowRef<SpeechError | null>>\n  /** Speak text. Uses current `selectedVoice`, `rate`, `pitch`, `volume` */\n  speak(text: string, overrides?: Partial<SpeakOptions>): Promise<void>\n  /** Stop the current utterance immediately */\n  stop(): void\n  /** Pause (Web Speech only; no-op for AI providers) */\n  pause(): void\n  /** Resume (Web Speech only; no-op for AI providers) */\n  resume(): void\n  /** Reload the voice list */\n  loadVoices(): Promise<void>\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────────\n\nexport function useSpeechSynthesis(\n  options: UseSpeechSynthesisOptions = {},\n): UseSpeechSynthesisReturn {\n  // I-4.1: fall back to web provider when used outside app.use()\n  let provider = options.provider ?? inject(SPEECH_PROVIDER_KEY, null)\n  if (!provider) {\n    if (typeof window !== 'undefined') {\n      console.warn(\n        '[vue-text-to-speech] useSpeechSynthesis() was called without a provider. ' +\n          'Use app.use(VueSpeech, config) to configure a provider, or pass one via options.provider. ' +\n          'Falling back to WebSpeechTTSProvider.',\n      )\n    }\n    provider = createWebSpeechProvider()\n  }\n\n  const _provider: TTSProvider = provider\n\n  // ── Reactive state ──────────────────────────────────────────────────────────\n  const isSupported = shallowRef(_provider.isSupported)\n  const isSpeaking = shallowRef(false)\n  const isPaused = shallowRef(false)\n  const voices = shallowRef<VoiceInfo[]>([])\n  const isLoadingVoices = shallowRef(false)\n  const selectedVoice = ref<VoiceInfo | undefined>(undefined)\n  const rate = ref(options.rate ?? 1)\n  const pitch = ref(options.pitch ?? 1)\n  const volume = ref(options.volume ?? 1)\n  const error = shallowRef<SpeechError | null>(null)\n\n  // ── Wire provider lifecycle hooks ────────────────────────────────────────────\n  _provider.onStart(() => {\n    isSpeaking.value = true\n    isPaused.value = false\n  })\n\n  _provider.onEnd(() => {\n    isSpeaking.value = false\n    isPaused.value = false\n  })\n\n  _provider.onError((err) => {\n    error.value = err\n    isSpeaking.value = false\n    isPaused.value = false\n  })\n\n  // ── Load voices eagerly ──────────────────────────────────────────────────────\n  async function loadVoices(): Promise<void> {\n    isLoadingVoices.value = true\n    try {\n      voices.value = await _provider.getVoices()\n      if (voices.value.length > 0 && !selectedVoice.value) {\n        selectedVoice.value = voices.value.find((v) => v.default) ?? voices.value[0]\n      }\n    } catch (e) {\n      error.value = {\n        code: 'UNKNOWN',\n        message: 'Failed to load voices',\n        cause: e,\n      }\n    } finally {\n      isLoadingVoices.value = false\n    }\n  }\n\n  loadVoices()\n\n  // ── Public API ───────────────────────────────────────────────────────────────\n  async function speak(text: string, overrides: Partial<SpeakOptions> = {}): Promise<void> {\n    error.value = null\n    await _provider.speak({\n      text,\n      voice: overrides.voice ?? selectedVoice.value,\n      // I-4.4: rate/pitch/volume from Refs apply at the point speak() is called\n      rate: overrides.rate ?? rate.value,\n      pitch: overrides.pitch ?? pitch.value,\n      volume: overrides.volume ?? volume.value,\n    })\n  }\n\n  function stop(): void {\n    _provider.stop()\n    isSpeaking.value = false\n    isPaused.value = false\n  }\n\n  function pause(): void {\n    _provider.pause()\n    isPaused.value = true\n  }\n\n  function resume(): void {\n    _provider.resume()\n    isPaused.value = false\n  }\n\n  // ── Cleanup on component unmount (4.3) ──────────────────────────────────────\n  onUnmounted(() => {\n    _provider.stop()\n  })\n\n  return {\n    isSupported: readonly(isSupported),\n    isSpeaking: readonly(isSpeaking),\n    isPaused: readonly(isPaused),\n    voices: readonly(voices),\n    isLoadingVoices: readonly(isLoadingVoices),\n    selectedVoice,\n    rate,\n    pitch,\n    volume,\n    error: readonly(error),\n    speak,\n    stop,\n    pause,\n    resume,\n    loadVoices,\n  }\n}\n","import { ref, shallowRef, readonly, onUnmounted } from 'vue'\nimport { WebSpeechSTTProvider } from '../providers/WebSpeechSTTProvider.js'\nimport type { WebSpeechSTTOptions } from '../providers/WebSpeechSTTProvider.js'\nimport type { SpeechError } from '../providers/types.js'\n\n// ─── Options & Return type ────────────────────────────────────────────────────\n\nexport interface UseSpeechRecognitionOptions extends WebSpeechSTTOptions {}\n\nexport interface UseSpeechRecognitionReturn {\n  /** Whether SpeechRecognition is available in this environment */\n  readonly isSupported: ReturnType<typeof readonly<ReturnType<typeof shallowRef<boolean>>>>\n  /** Whether recognition is currently active */\n  readonly isListening: ReturnType<typeof readonly<ReturnType<typeof shallowRef<boolean>>>>\n  /** Live interim transcript (updates continuously while listening) */\n  readonly transcript: ReturnType<typeof readonly<ReturnType<typeof ref<string>>>>\n  /** Most recent committed final transcript */\n  readonly finalTranscript: ReturnType<typeof readonly<ReturnType<typeof ref<string>>>>\n  /** Confidence score of the last final result (0–1) */\n  readonly confidence: ReturnType<typeof readonly<ReturnType<typeof shallowRef<number>>>>\n  /** Active language code (BCP-47) */\n  readonly lang: string\n  /** Whether continuous recognition is enabled */\n  readonly continuous: boolean\n  /** Most recent error */\n  readonly error: ReturnType<typeof readonly<ReturnType<typeof shallowRef<SpeechError | null>>>>\n  /** Start listening */\n  start(): void\n  /** Stop listening */\n  stop(): void\n  /** Clear the transcript state */\n  resetTranscript(): void\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────────\n\n/**\n * Wraps the Web Speech Recognition API.\n *\n * I-4.3: This composable always creates its own `WebSpeechSTTProvider`.\n * It intentionally does NOT use the injected TTS provider from SPEECH_PROVIDER_KEY.\n */\nexport function useSpeechRecognition(\n  options: UseSpeechRecognitionOptions = {},\n): UseSpeechRecognitionReturn {\n  // Always create a fresh STT provider — never reuses the TTS injection (I-4.3)\n  const provider = new WebSpeechSTTProvider(options)\n\n  // ── Reactive state ──────────────────────────────────────────────────────────\n  const isSupported = shallowRef(provider.isSupported)\n  const isListening = shallowRef(false)\n  const transcript = ref('')\n  const finalTranscript = ref('')\n  const confidence = shallowRef(0)\n  const error = shallowRef<SpeechError | null>(null)\n\n  // ── Wire provider callbacks ──────────────────────────────────────────────────\n  provider.onTranscript((t, c) => {\n    transcript.value = t\n    confidence.value = c\n  })\n\n  provider.onFinalTranscript((t, c) => {\n    finalTranscript.value = t\n    transcript.value = ''   // clear interim — prevents duplicate display\n    confidence.value = c\n  })\n\n  provider.onError((err) => {\n    error.value = err\n    isListening.value = false\n  })\n\n  // When recognition ends unexpectedly (not via stop()), auto-restart if the\n  // user is still supposed to be listening. This prevents silent gaps caused\n  // by browser-side timeouts or network hiccups during a continuous session.\n  provider.onEnd(() => {\n    if (isListening.value) {\n      provider.start()\n    }\n  })\n\n  // ── Public API ───────────────────────────────────────────────────────────────\n  function start(): void {\n    error.value = null\n    transcript.value = ''\n    isListening.value = true\n    provider.start()\n  }\n\n  function stop(): void {\n    isListening.value = false  // set before provider.stop() so onEnd guard sees false\n    provider.stop()\n  }\n\n  function resetTranscript(): void {\n    transcript.value = ''\n    finalTranscript.value = ''\n    confidence.value = 0\n  }\n\n  // ── Cleanup on component unmount (4.5) ──────────────────────────────────────\n  onUnmounted(() => {\n    isListening.value = false  // prevent auto-restart before provider.stop()\n    provider.stop()\n  })\n\n  return {\n    isSupported: readonly(isSupported),\n    isListening: readonly(isListening),\n    transcript: readonly(transcript),\n    finalTranscript: readonly(finalTranscript),\n    confidence: readonly(confidence),\n    lang: options.lang ?? '',\n    continuous: options.continuous ?? false,\n    error: readonly(error),\n    start,\n    stop,\n    resetTranscript,\n  }\n}\n","import { ref, readonly, inject, onUnmounted } from 'vue'\nimport { SPEECH_PROVIDER_KEY } from '../injectionKeys.js'\nimport { createWebSpeechProvider } from '../factory.js'\nimport type { TTSProvider } from '../providers/types.js'\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface UseVoiceQueueOptions {\n  /** Override the injected provider for this queue instance */\n  provider?: TTSProvider\n}\n\nexport interface UseVoiceQueueReturn {\n  /** Items waiting to be spoken (does not include the currently-speaking item) */\n  readonly queue: ReturnType<typeof readonly<ReturnType<typeof ref<string[]>>>>\n  /** The text currently being spoken, or null if idle */\n  readonly currentItem: ReturnType<typeof readonly<ReturnType<typeof ref<string | null>>>>\n  /** Whether the queue is currently speaking something */\n  readonly isPlaying: ReturnType<typeof readonly<ReturnType<typeof ref<boolean>>>>\n  /** Add a text item to the end of the queue. Starts speaking immediately if idle */\n  enqueue(text: string): void\n  /**\n   * Manually pop the next item from the queue without speaking it.\n   * Useful for manual queue management; does NOT affect auto-advance behaviour.\n   */\n  dequeue(): string | undefined\n  /** Stop the current utterance and discard all pending items */\n  clear(): void\n  /**\n   * Stop the current utterance immediately.\n   * Auto-advance fires the next item via `onEnd`.\n   */\n  skip(): void\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────────\n\n/**\n * Reactive voice queue — auto-advances to the next item when each utterance ends.\n *\n * The queue relies on the provider's `onEnd` hook (added in Sprint 2, I-2.1)\n * to advance automatically. The `isPlaying` flag guards against double-advance\n * when multiple composables share the same provider instance.\n *\n * All providers (WebSpeech + AI) consistently emit `onEnd` after every speak()\n * call, whether it ended normally or via an error.\n */\nexport function useVoiceQueue(options: UseVoiceQueueOptions = {}): UseVoiceQueueReturn {\n  // I-5.3 / I-4.1 pattern: explicit > injected > fallback\n  let provider = options.provider ?? inject(SPEECH_PROVIDER_KEY, null)\n  if (!provider) {\n    provider = createWebSpeechProvider()\n  }\n  const _provider: TTSProvider = provider\n\n  // ── Reactive state ──────────────────────────────────────────────────────────\n  // Use ref (not shallowRef) so array mutations (push/splice) are tracked\n  const queue = ref<string[]>([])\n  const currentItem = ref<string | null>(null)\n  const isPlaying = ref(false)\n\n  // ── Internal advance function ────────────────────────────────────────────────\n  function advance(): void {\n    if (queue.value.length === 0) {\n      currentItem.value = null\n      isPlaying.value = false\n      return\n    }\n\n    const text = queue.value[0]\n    // Splice is reactive\n    queue.value.splice(0, 1)\n    currentItem.value = text\n    isPlaying.value = true\n\n    // Errors are swallowed here — all providers emit onEnd after errors,\n    // so the onEnd handler below will call advance() to keep the queue moving.\n    _provider.speak({ text }).catch(() => { /* onEnd handles advancement */ })\n  }\n\n  // ── Auto-advance via provider onEnd hook (D-7 / I-2.1) ──────────────────────\n  _provider.onEnd(() => {\n    if (!isPlaying.value) return  // not our speak — another composable spoke\n    advance()\n  })\n\n  // ── Public API ───────────────────────────────────────────────────────────────\n  function enqueue(text: string): void {\n    const trimmed = text.trim()\n    if (!trimmed) return\n    queue.value.push(trimmed)\n    if (!isPlaying.value) {\n      advance()\n    }\n  }\n\n  function dequeue(): string | undefined {\n    if (queue.value.length === 0) return undefined\n    const item = queue.value[0]\n    queue.value.splice(0, 1)\n    return item\n  }\n\n  function clear(): void {\n    queue.value.splice(0, queue.value.length)\n    currentItem.value = null\n    isPlaying.value = false\n    _provider.stop()\n  }\n\n  function skip(): void {\n    // stop() triggers onEnd (via interrupted/canceled) → advance() → next item\n    _provider.stop()\n  }\n\n  // ── Cleanup on unmount ────────────────────────────────────────────────────────\n  onUnmounted(() => {\n    clear()\n  })\n\n  return {\n    queue: readonly(queue),\n    currentItem: readonly(currentItem),\n    isPlaying: readonly(isPlaying),\n    enqueue,\n    dequeue,\n    clear,\n    skip,\n  }\n}\n","/**\n * Sentence boundary detection — Decision D-4, I-5.1.\n *\n * Uses `Intl.Segmenter` with `{ granularity: 'sentence' }`:\n *   - Browser-native & Node 16+ — zero bundle size\n *   - Handles abbreviations (Mr., Dr.), decimals ($3.50), URLs, markdown\n *   - Language-aware (detects locale automatically)\n *   - No regex required\n */\n\nlet _segmenter: Intl.Segmenter | null = null\n\nfunction getSegmenter(): Intl.Segmenter {\n  if (!_segmenter) {\n    _segmenter = new Intl.Segmenter(undefined, { granularity: 'sentence' })\n  }\n  return _segmenter\n}\n\n/**\n * Given a streaming text buffer, extract all **complete** sentences and\n * return the remaining partial sentence that has not ended yet.\n *\n * The last segment from `Intl.Segmenter` is treated as incomplete because\n * more tokens may still arrive. All earlier segments are complete.\n *\n * I-5.5: This function is called on each new token during streaming.\n * On natural stream end, the remaining buffer is spoken as-is.\n *\n * @param buffer  Accumulated token buffer\n * @returns       `{ sentences, remaining }` — sentences ready to speak, leftover\n */\nexport function extractCompleteSentences(buffer: string): {\n  sentences: string[]\n  remaining: string\n} {\n  if (!buffer.trim()) return { sentences: [], remaining: buffer }\n\n  const segments = [...getSegmenter().segment(buffer)]\n\n  if (segments.length <= 1) {\n    // Only one segment = incomplete sentence still forming\n    return { sentences: [], remaining: buffer }\n  }\n\n  // All segments except the last are safe to speak\n  const sentences = segments\n    .slice(0, -1)\n    .map((s) => s.segment.trim())\n    .filter((s) => s.length > 0)\n\n  const remaining = segments[segments.length - 1].segment\n\n  return { sentences, remaining }\n}\n\n/**\n * Split a **complete** text into all its sentences.\n * Use for pre-existing text — not for streaming buffers.\n */\nexport function splitSentences(text: string): string[] {\n  if (!text.trim()) return []\n  return [...getSegmenter().segment(text)]\n    .map((s) => s.segment.trim())\n    .filter((s) => s.length > 0)\n}\n","import { shallowRef, readonly, inject, onUnmounted } from 'vue'\nimport { SPEECH_PROVIDER_KEY } from '../injectionKeys.js'\nimport { createWebSpeechProvider } from '../factory.js'\nimport { useVoiceQueue } from './useVoiceQueue.js'\nimport { extractCompleteSentences } from '../utils/sentenceBoundary.js'\nimport type { TTSProvider } from '../providers/types.js'\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface UseStreamingTTSOptions {\n  /** Override the injected provider */\n  provider?: TTSProvider\n}\n\nexport interface UseStreamingTTSReturn {\n  /**\n   * Pipe an `AsyncIterable<string>` (e.g. an LLM token stream) through the\n   * sentence detector and into the voice queue.\n   *\n   * - Complete sentences are enqueued as they form.\n   * - If the stream ends without a final sentence boundary, the remaining\n   *   buffer is spoken as-is (I-5.5).\n   * - Returns a Promise that resolves when the stream is exhausted.\n   *   (It does NOT wait for all speech to finish.)\n   */\n  pipeStream(stream: AsyncIterable<string>): Promise<void>\n  /** Sentences waiting to be spoken */\n  readonly queue: ReturnType<typeof useVoiceQueue>['queue']\n  /** The sentence currently being spoken */\n  readonly currentItem: ReturnType<typeof useVoiceQueue>['currentItem']\n  /** Partial token buffer being accumulated (incomplete sentence) */\n  readonly currentChunk: ReturnType<typeof readonly<ReturnType<typeof shallowRef<string>>>>\n  /** Whether a stream is currently being piped */\n  readonly isStreaming: ReturnType<typeof readonly<ReturnType<typeof shallowRef<boolean>>>>\n  /**\n   * Stop the stream immediately and clear all pending speech.\n   *\n   * I-5.4: Uses `AbortController` — the async iterator exits on the next\n   * `signal.aborted` check. Consumer iterables should also accept an\n   * `AbortSignal` for full cancellation.\n   * I-5.5: Partial buffer is **discarded** on stop().\n   */\n  stop(): void\n}\n\n// ─── Composable ───────────────────────────────────────────────────────────────\n\nexport function useStreamingTTS(options: UseStreamingTTSOptions = {}): UseStreamingTTSReturn {\n  // I-5.3: inject > fallback\n  let provider = options.provider ?? inject(SPEECH_PROVIDER_KEY, null)\n  if (!provider) {\n    provider = createWebSpeechProvider()\n  }\n\n  // Internal voice queue — shares the same provider\n  const voiceQueue = useVoiceQueue({ provider })\n\n  // ── Streaming state ──────────────────────────────────────────────────────────\n  const isStreaming = shallowRef(false)\n  const currentChunk = shallowRef('')\n  let _controller: AbortController | null = null\n\n  // ── pipeStream ───────────────────────────────────────────────────────────────\n  async function pipeStream(stream: AsyncIterable<string>): Promise<void> {\n    // Abort any previous stream still in flight\n    _controller?.abort()\n    const controller = new AbortController()\n    _controller = controller\n\n    isStreaming.value = true\n    let buffer = ''\n    currentChunk.value = ''\n\n    try {\n      for await (const chunk of stream) {\n        // I-5.4: check abort on every token\n        if (controller.signal.aborted) break\n\n        buffer += chunk\n        currentChunk.value = buffer\n\n        // Extract complete sentences from the accumulated buffer\n        const { sentences, remaining } = extractCompleteSentences(buffer)\n        if (sentences.length > 0) {\n          buffer = remaining\n          currentChunk.value = remaining\n\n          for (const sentence of sentences) {\n            if (controller.signal.aborted) break\n            voiceQueue.enqueue(sentence)\n          }\n        }\n      }\n\n      // I-5.5: stream ended naturally — speak whatever remains in the buffer\n      if (!controller.signal.aborted && buffer.trim()) {\n        voiceQueue.enqueue(buffer.trim())\n        buffer = ''\n        currentChunk.value = ''\n      }\n    } finally {\n      if (controller === _controller) {\n        _controller = null\n      }\n      isStreaming.value = false\n      // I-5.5: on abort, discard partial buffer\n      if (controller.signal.aborted) {\n        currentChunk.value = ''\n      }\n    }\n  }\n\n  // ── stop ─────────────────────────────────────────────────────────────────────\n  function stop(): void {\n    _controller?.abort()\n    _controller = null\n    voiceQueue.clear()     // stops provider + empties pending queue\n    currentChunk.value = ''\n    isStreaming.value = false\n  }\n\n  // ── Cleanup on unmount ────────────────────────────────────────────────────────\n  onUnmounted(() => {\n    stop()\n  })\n\n  return {\n    pipeStream,\n    queue: voiceQueue.queue,\n    currentItem: voiceQueue.currentItem,\n    currentChunk: readonly(currentChunk),\n    isStreaming: readonly(isStreaming),\n    stop,\n  }\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { VoiceInfo } from '../providers/types.js'\n\n// ─── Props / Emits ────────────────────────────────────────────────────────────\nconst props = withDefaults(\n  defineProps<{\n    /** Voice list from useSpeechSynthesis().voices */\n    voices: readonly VoiceInfo[]\n    modelValue?: VoiceInfo\n    disabled?: boolean\n    /** Show loading spinner text while voices are being fetched */\n    loading?: boolean\n  }>(),\n  { disabled: false, loading: false },\n)\n\nconst emit = defineEmits<{\n  'update:modelValue': [voice: VoiceInfo | undefined]\n}>()\n\n// ─── Group voices by primary language using Intl.DisplayNames ─────────────────\n// Spec I-6.4: ISO language code labels — no emoji flags (inconsistent on Windows)\nfunction getLangLabel(lang: string): string {\n  try {\n    const dn = new Intl.DisplayNames(['en'], { type: 'language' })\n    return dn.of(lang) ?? lang\n  } catch {\n    return lang\n  }\n}\n\ninterface VoiceGroup {\n  key: string\n  label: string\n  voices: VoiceInfo[]\n}\n\nconst voiceGroups = computed<VoiceGroup[]>(() => {\n  const groups = new Map<string, VoiceGroup>()\n  for (const voice of props.voices) {\n    const key = voice.lang || 'other'\n    if (!groups.has(key)) {\n      groups.set(key, { key, label: getLangLabel(key), voices: [] })\n    }\n    groups.get(key)!.voices.push(voice)\n  }\n  return [...groups.values()].sort((a, b) => a.label.localeCompare(b.label))\n})\n\nfunction handleChange(event: Event) {\n  const voiceId = (event.target as HTMLSelectElement).value\n  const voice = props.voices.find((v) => v.id === voiceId)\n  emit('update:modelValue', voice)\n}\n</script>\n\n<template>\n  <select\n    class=\"vts-voice-select\"\n    :value=\"modelValue?.id ?? ''\"\n    :disabled=\"disabled || loading\"\n    aria-label=\"Select voice\"\n    @change=\"handleChange\"\n  >\n    <option v-if=\"loading\" value=\"\" disabled>Loading voices…</option>\n    <option v-else-if=\"voices.length === 0\" value=\"\" disabled>No voices available</option>\n    <template v-else>\n      <option v-if=\"!modelValue\" value=\"\" disabled>Select a voice</option>\n      <optgroup v-for=\"group in voiceGroups\" :key=\"group.key\" :label=\"group.label\">\n        <option v-for=\"voice in group.voices\" :key=\"voice.id\" :value=\"voice.id\">\n          {{ voice.label }}{{ voice.default ? ' ✓' : '' }}\n        </option>\n      </optgroup>\n    </template>\n  </select>\n</template>\n\n<style scoped>\n/*\n  CSS custom properties (Sprint 6 token set — I-6.1):\n    --vts-primary        #6366f1\n    --vts-primary-hover  #4f46e5\n    --vts-bg             #ffffff\n    --vts-border         #e5e7eb\n    --vts-text           #111827\n    --vts-text-muted     #6b7280\n    --vts-radius         8px\n    --vts-font           inherit\n    --vts-recording-color #ef4444\n*/\n\n.vts-voice-select {\n  font-family: var(--vts-font, inherit);\n  font-size: 0.875rem;\n  color: var(--vts-text, #111827);\n  background: var(--vts-bg, #ffffff);\n  border: 1px solid var(--vts-border, #e5e7eb);\n  border-radius: var(--vts-radius, 8px);\n  padding: 0.375rem 0.625rem;\n  width: 100%;\n  cursor: pointer;\n  appearance: auto;\n}\n\n.vts-voice-select:disabled {\n  opacity: 0.5;\n  cursor: not-allowed;\n}\n\n.vts-voice-select:focus-visible {\n  outline: 2px solid var(--vts-primary, #6366f1);\n  outline-offset: 2px;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { watch, onMounted } from 'vue'\nimport { useSpeechSynthesis } from '../composables/useSpeechSynthesis.js'\nimport VueSpeechVoiceSelect from './VueSpeechVoiceSelect.vue'\nimport type { SpeechError } from '../providers/types.js'\n\n// ─── Props / Emits ────────────────────────────────────────────────────────────\nconst props = withDefaults(\n  defineProps<{\n    /** The text to speak */\n    text: string\n    /** Start speaking automatically when the component mounts */\n    autoSpeak?: boolean\n    /** Show the voice selector row (default: true) */\n    showVoiceSelect?: boolean\n    /** Show the Rate slider (default: true) */\n    showRate?: boolean\n    /** Show the Pitch slider (default: true) */\n    showPitch?: boolean\n    /** Show the Volume slider (default: true) */\n    showVolume?: boolean\n  }>(),\n  {\n    autoSpeak: false,\n    showVoiceSelect: true,\n    showRate: true,\n    showPitch: true,\n    showVolume: true,\n  },\n)\n\nconst emit = defineEmits<{\n  /** Fired when the utterance starts */\n  start: []\n  /** Fired when the utterance ends (naturally or after stop) */\n  end: []\n  /** Fired when the utterance is paused */\n  pause: []\n  /** Fired when the utterance is resumed after a pause */\n  resume: []\n  /** Fired when the provider encounters an error */\n  error: [error: SpeechError]\n}>()\n\n// ─── Composable ───────────────────────────────────────────────────────────────\nconst {\n  isSupported,\n  isSpeaking,\n  isPaused,\n  voices,\n  isLoadingVoices,\n  selectedVoice,\n  rate,\n  pitch,\n  volume,\n  error,\n  speak,\n  stop,\n  pause,\n  resume,\n} = useSpeechSynthesis()\n\n// ─── Relay composable state → component emits ─────────────────────────────────\nwatch(isSpeaking, (val, prev) => {\n  if (val && !prev) emit('start')\n  if (!val && prev) emit('end')\n})\nwatch(isPaused, (val, prev) => {\n  if (val && !prev) emit('pause')\n  if (!val && prev) emit('resume')\n})\nwatch(error, (val) => {\n  if (val) emit('error', val)\n})\n\n// ─── Handlers ─────────────────────────────────────────────────────────────────\nfunction handlePlay() {\n  if (isPaused.value) {\n    resume()\n  } else {\n    speak(props.text)\n  }\n}\n\n/** Escape key stops playback from anywhere within the player */\nfunction handleKeydown(event: KeyboardEvent) {\n  if (event.key === 'Escape' && isSpeaking.value) {\n    stop()\n    event.preventDefault()\n  }\n}\n\nonMounted(() => {\n  if (props.autoSpeak) speak(props.text)\n})\n</script>\n\n<template>\n  <div\n    class=\"vts-player\"\n    :class=\"{\n      'vts-player--speaking': isSpeaking,\n      'vts-player--paused': isPaused,\n    }\"\n    @keydown=\"handleKeydown\"\n  >\n    <!-- Not supported banner -->\n    <p v-if=\"!isSupported\" class=\"vts-player__unsupported\" role=\"alert\">\n      Text-to-speech is not supported in this browser.\n    </p>\n\n    <template v-else>\n      <!-- Voice selector -->\n      <div v-if=\"props.showVoiceSelect\" class=\"vts-player__voice-row\">\n        <label class=\"vts-player__field-label\" for=\"vts-voice-select\">Voice</label>\n        <VueSpeechVoiceSelect\n          id=\"vts-voice-select\"\n          v-model=\"selectedVoice\"\n          :voices=\"voices\"\n          :loading=\"isLoadingVoices\"\n          :disabled=\"isSpeaking && !isPaused\"\n        />\n      </div>\n\n      <!-- Rate / Pitch / Volume sliders -->\n      <div v-if=\"props.showRate || props.showPitch || props.showVolume\" class=\"vts-player__sliders\">\n        <label v-if=\"props.showRate\" class=\"vts-player__slider-label\">\n          <span>Rate <span class=\"vts-player__slider-val\">{{ rate.toFixed(1) }}</span></span>\n          <input\n            type=\"range\"\n            v-model.number=\"rate\"\n            min=\"0.1\"\n            max=\"4\"\n            step=\"0.1\"\n            aria-label=\"Speech rate\"\n          />\n        </label>\n        <label v-if=\"props.showPitch\" class=\"vts-player__slider-label\">\n          <span>Pitch <span class=\"vts-player__slider-val\">{{ pitch.toFixed(1) }}</span></span>\n          <input\n            type=\"range\"\n            v-model.number=\"pitch\"\n            min=\"0\"\n            max=\"2\"\n            step=\"0.1\"\n            aria-label=\"Speech pitch\"\n          />\n        </label>\n        <label v-if=\"props.showVolume\" class=\"vts-player__slider-label\">\n          <span>Volume <span class=\"vts-player__slider-val\">{{ volume.toFixed(2) }}</span></span>\n          <input\n            type=\"range\"\n            v-model.number=\"volume\"\n            min=\"0\"\n            max=\"1\"\n            step=\"0.05\"\n            aria-label=\"Speech volume\"\n          />\n        </label>\n      </div>\n\n      <!-- Playback controls — full replacement via #controls, icon replacement via #*-icon -->\n      <div class=\"vts-player__controls\" role=\"group\" aria-label=\"Playback controls\">\n        <slot name=\"controls\">\n          <button\n            class=\"vts-btn vts-btn--primary\"\n            :disabled=\"isSpeaking && !isPaused\"\n            :aria-label=\"isPaused ? 'Resume' : 'Play'\"\n            @click=\"handlePlay\"\n          >\n            <slot name=\"play-icon\">{{ isPaused ? '▶ Resume' : '▶ Play' }}</slot>\n          </button>\n\n          <button\n            class=\"vts-btn\"\n            :disabled=\"!isSpeaking || isPaused\"\n            aria-label=\"Pause\"\n            @click=\"pause()\"\n          >\n            <slot name=\"pause-icon\">⏸ Pause</slot>\n          </button>\n\n          <button\n            class=\"vts-btn vts-btn--danger\"\n            :disabled=\"!isSpeaking\"\n            aria-label=\"Stop\"\n            @click=\"stop()\"\n          >\n            <slot name=\"stop-icon\">⏹ Stop</slot>\n          </button>\n        </slot>\n      </div>\n\n      <!-- Error display -->\n      <p v-if=\"error\" class=\"vts-player__error\" role=\"alert\">{{ error.message }}</p>\n    </template>\n  </div>\n</template>\n\n<style scoped>\n.vts-player {\n  font-family: var(--vts-font, inherit);\n  background: var(--vts-bg, #ffffff);\n  border: 1px solid var(--vts-border, #e5e7eb);\n  border-radius: var(--vts-radius, 8px);\n  padding: 1rem 1.25rem;\n  display: flex;\n  flex-direction: column;\n  gap: 0.875rem;\n  max-width: 480px;\n}\n\n.vts-player__unsupported {\n  color: var(--vts-text-muted, #6b7280);\n  font-size: 0.875rem;\n  margin: 0;\n}\n\n/* Voice row */\n.vts-player__voice-row {\n  display: flex;\n  flex-direction: column;\n  gap: 0.25rem;\n}\n\n.vts-player__field-label {\n  font-size: 0.75rem;\n  color: var(--vts-text-muted, #6b7280);\n  text-transform: uppercase;\n  letter-spacing: 0.04em;\n}\n\n/* Sliders */\n.vts-player__sliders {\n  display: flex;\n  flex-direction: column;\n  gap: 0.5rem;\n}\n\n.vts-player__slider-label {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 0.75rem;\n  font-size: 0.8125rem;\n  color: var(--vts-text, #111827);\n}\n\n.vts-player__slider-label > span {\n  min-width: 6rem;\n  display: flex;\n  justify-content: space-between;\n}\n\n.vts-player__slider-val {\n  color: var(--vts-text-muted, #6b7280);\n  font-variant-numeric: tabular-nums;\n  min-width: 2.5rem;\n  text-align: right;\n}\n\n.vts-player__slider-label input[type='range'] {\n  flex: 1;\n  accent-color: var(--vts-primary, #6366f1);\n}\n\n/* Controls */\n.vts-player__controls {\n  display: flex;\n  gap: 0.5rem;\n  flex-wrap: wrap;\n}\n\n/* Shared button base */\n.vts-btn {\n  font-family: var(--vts-font, inherit);\n  font-size: 0.875rem;\n  padding: 0.4rem 0.875rem;\n  border: 1px solid var(--vts-border, #e5e7eb);\n  border-radius: var(--vts-radius, 8px);\n  background: var(--vts-bg, #ffffff);\n  color: var(--vts-text, #111827);\n  cursor: pointer;\n  transition: background 0.15s, border-color 0.15s;\n}\n\n.vts-btn:hover:not(:disabled) {\n  border-color: var(--vts-primary, #6366f1);\n  color: var(--vts-primary, #6366f1);\n}\n\n.vts-btn--primary {\n  background: var(--vts-primary, #6366f1);\n  border-color: var(--vts-primary, #6366f1);\n  color: #fff;\n}\n\n.vts-btn--primary:hover:not(:disabled) {\n  background: var(--vts-primary-hover, #4f46e5);\n  border-color: var(--vts-primary-hover, #4f46e5);\n  color: #fff;\n}\n\n.vts-btn--danger:hover:not(:disabled) {\n  border-color: var(--vts-recording-color, #ef4444);\n  color: var(--vts-recording-color, #ef4444);\n}\n\n.vts-btn:disabled {\n  opacity: 0.4;\n  cursor: not-allowed;\n}\n\n.vts-btn:focus-visible {\n  outline: 2px solid var(--vts-primary, #6366f1);\n  outline-offset: 2px;\n}\n\n/* Error */\n.vts-player__error {\n  font-size: 0.8125rem;\n  color: var(--vts-recording-color, #ef4444);\n  margin: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { watch } from 'vue'\nimport { useSpeechRecognition } from '../composables/useSpeechRecognition.js'\nimport type { SpeechError } from '../providers/types.js'\n\n// ─── Props / Emits ────────────────────────────────────────────────────────────\nconst props = withDefaults(\n  defineProps<{\n    /** BCP-47 language code (e.g. 'en-US'). Defaults to browser UI language */\n    lang?: string\n    /** Keep recognizing after the first final result */\n    continuous?: boolean\n  }>(),\n  { continuous: false },\n)\n\nconst emit = defineEmits<{\n  /** Fired on each interim (non-final) transcript update */\n  transcript: [text: string, confidence: number]\n  /** Fired when a final transcript result is received */\n  'final-transcript': [text: string, confidence: number]\n  /** Fired on recognition error */\n  error: [error: SpeechError]\n}>()\n\n// ─── Composable ───────────────────────────────────────────────────────────────\nconst {\n  isSupported,\n  isListening,\n  transcript,\n  finalTranscript,\n  confidence,\n  error,\n  start,\n  stop,\n  resetTranscript,\n} = useSpeechRecognition({\n  lang: props.lang,\n  continuous: props.continuous,\n  interimResults: true,\n})\n\n// ─── Relay composable state → component emits ─────────────────────────────────\nwatch(transcript, (val) => {\n  if (val) emit('transcript', val, 0)\n})\nwatch(finalTranscript, (val) => {\n  if (val) emit('final-transcript', val, confidence.value ?? 0)\n})\nwatch(error, (val) => {\n  if (val) emit('error', val)\n})\n\n// ─── Handlers ─────────────────────────────────────────────────────────────────\nfunction toggleListening() {\n  if (isListening.value) {\n    stop()\n  } else {\n    resetTranscript()\n    start()\n  }\n}\n\n/** Escape stops recognition from anywhere within the recorder */\nfunction handleKeydown(event: KeyboardEvent) {\n  if (event.key === 'Escape' && isListening.value) {\n    stop()\n    event.preventDefault()\n  }\n}\n</script>\n\n<template>\n  <div class=\"vts-recorder\" @keydown=\"handleKeydown\">\n    <!-- Not supported banner -->\n    <p v-if=\"!isSupported\" class=\"vts-recorder__unsupported\" role=\"alert\">\n      Speech recognition is not supported in this browser.\n    </p>\n\n    <template v-else>\n      <!-- Mic button — aria-pressed reflects toggle state (I-6.3) -->\n      <div class=\"vts-recorder__controls\">\n        <button\n          class=\"vts-recorder__mic-btn\"\n          :class=\"{ 'vts-recorder__mic-btn--active': isListening }\"\n          :aria-pressed=\"isListening\"\n          :aria-label=\"isListening ? 'Stop recording' : 'Start recording'\"\n          @click=\"toggleListening\"\n        >\n          <slot name=\"mic-icon\">\n            <span class=\"vts-recorder__mic-icon\" aria-hidden=\"true\">🎤</span>\n          </slot>\n          <!-- Pulse ring — hidden from AT (cosmetic only) -->\n          <span v-if=\"isListening\" class=\"vts-recorder__pulse\" aria-hidden=\"true\" />\n        </button>\n\n        <span class=\"vts-recorder__status\">\n          {{ isListening ? 'Listening…' : 'Press to speak' }}\n        </span>\n      </div>\n\n      <!-- Transcript region — aria-live=\"polite\" so screen readers announce updates (I-6.5) -->\n      <div\n        class=\"vts-recorder__transcript\"\n        aria-live=\"polite\"\n        aria-atomic=\"false\"\n        aria-label=\"Transcript\"\n        role=\"status\"\n      >\n        <slot name=\"transcript\">\n          <span v-if=\"!finalTranscript && !transcript\" class=\"vts-recorder__placeholder\">\n            Transcript will appear here…\n          </span>\n          <template v-else>\n            <span class=\"vts-recorder__final\">{{ finalTranscript }}</span>\n            <span\n              v-if=\"transcript\"\n              class=\"vts-recorder__interim\"\n              aria-label=\"Interim result\"\n            >{{ transcript }}</span>\n          </template>\n        </slot>\n      </div>\n\n      <p v-if=\"error\" class=\"vts-recorder__error\" role=\"alert\">{{ error.message }}</p>\n    </template>\n  </div>\n</template>\n\n<style scoped>\n.vts-recorder {\n  font-family: var(--vts-font, inherit);\n  display: flex;\n  flex-direction: column;\n  gap: 0.875rem;\n  max-width: 480px;\n}\n\n.vts-recorder__unsupported {\n  color: var(--vts-text-muted, #6b7280);\n  font-size: 0.875rem;\n  margin: 0;\n}\n\n/* Controls row */\n.vts-recorder__controls {\n  display: flex;\n  align-items: center;\n  gap: 0.875rem;\n}\n\n/* Mic button */\n.vts-recorder__mic-btn {\n  position: relative;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  width: 3rem;\n  height: 3rem;\n  border-radius: 50%;\n  border: 2px solid var(--vts-border, #e5e7eb);\n  background: var(--vts-bg, #ffffff);\n  cursor: pointer;\n  font-size: 1.25rem;\n  flex-shrink: 0;\n  transition: border-color 0.2s, background 0.2s;\n}\n\n.vts-recorder__mic-btn:hover:not(:disabled) {\n  border-color: var(--vts-primary, #6366f1);\n}\n\n.vts-recorder__mic-btn--active {\n  background: var(--vts-recording-color, #ef4444);\n  border-color: var(--vts-recording-color, #ef4444);\n  color: #fff;\n}\n\n.vts-recorder__mic-btn:focus-visible {\n  outline: 2px solid var(--vts-primary, #6366f1);\n  outline-offset: 3px;\n}\n\n/* Pulse ring animation (active state) */\n.vts-recorder__pulse {\n  position: absolute;\n  inset: -6px;\n  border-radius: 50%;\n  border: 2px solid var(--vts-recording-color, #ef4444);\n  animation: vts-pulse 1.4s ease-out infinite;\n  pointer-events: none;\n}\n\n@keyframes vts-pulse {\n  0% { opacity: 0.8; transform: scale(1); }\n  100% { opacity: 0; transform: scale(1.5); }\n}\n\n/* Status text */\n.vts-recorder__status {\n  font-size: 0.875rem;\n  color: var(--vts-text-muted, #6b7280);\n}\n\n/* Transcript box */\n.vts-recorder__transcript {\n  background: var(--vts-bg, #ffffff);\n  border: 1px solid var(--vts-border, #e5e7eb);\n  border-radius: var(--vts-radius, 8px);\n  padding: 0.75rem 1rem;\n  min-height: 5rem;\n  font-size: 0.9375rem;\n  line-height: 1.6;\n  color: var(--vts-text, #111827);\n  word-break: break-word;\n}\n\n.vts-recorder__placeholder {\n  color: var(--vts-text-muted, #6b7280);\n  font-style: italic;\n}\n\n.vts-recorder__final {\n  color: var(--vts-text, #111827);\n}\n\n.vts-recorder__interim {\n  color: var(--vts-text-muted, #6b7280);\n  font-style: italic;\n}\n\n/* Error */\n.vts-recorder__error {\n  font-size: 0.8125rem;\n  color: var(--vts-recording-color, #ef4444);\n  margin: 0;\n}\n</style>\n","import type { App, Plugin } from 'vue'\nimport { WebSpeechTTSProvider } from './providers/WebSpeechTTSProvider.js'\nimport { createVueSpeech } from './factory.js'\nimport { SPEECH_PROVIDER_KEY } from './injectionKeys.js'\nimport type { ProviderConfig } from './providers/types.js'\nimport VueSpeechPlayer from './components/VueSpeechPlayer.vue'\nimport VueSpeechRecorder from './components/VueSpeechRecorder.vue'\nimport VueSpeechVoiceSelect from './components/VueSpeechVoiceSelect.vue'\n\nexport type VueSpeechOptions = ProviderConfig & {\n  /**\n   * When `true`, registers `VueSpeechPlayer`, `VueSpeechRecorder`, and\n   * `VueSpeechVoiceSelect` as global components.\n   *\n   * Default: `false` — import components individually for tree-shaking (I-7.3).\n   */\n  components?: boolean\n}\n\n/**\n * Vue 3 plugin. Provides a `TTSProvider` to all descendant components via\n * `SPEECH_PROVIDER_KEY`, allowing `useSpeechSynthesis()` to receive the\n * configured provider through Vue's injection system.\n *\n * @example\n * ```ts\n * // main.ts\n * import { createApp } from 'vue'\n * import { VueSpeech } from 'vue-text-to-speech'\n *\n * createApp(App)\n *   .use(VueSpeech, { provider: 'web' })\n *   .mount('#app')\n * ```\n */\nexport const VueSpeech: Plugin<VueSpeechOptions> = {\n  install(app: App, options: VueSpeechOptions = { provider: 'web' }) {\n    if (options.provider === 'web') {\n      // Synchronous path — WebSpeechTTSProvider is ready before first render\n      app.provide(SPEECH_PROVIDER_KEY, new WebSpeechTTSProvider())\n    } else {\n      // Async path — AI providers require dynamic imports\n      // The provider is available before any component renders in practice because\n      // app.mount() is called after app.use() in userland (separate microtask)\n      createVueSpeech(options as ProviderConfig)\n        .then((provider) => {\n          app.provide(SPEECH_PROVIDER_KEY, provider)\n        })\n        .catch((err: unknown) => {\n          console.error('[vue-text-to-speech] Failed to initialize provider:', err)\n        })\n    }\n\n    // Optionally register UI components globally (opt-in for rapid prototyping; I-7.3)\n    if (options.components === true) {\n      app.component('VueSpeechPlayer', VueSpeechPlayer)\n      app.component('VueSpeechRecorder', VueSpeechRecorder)\n      app.component('VueSpeechVoiceSelect', VueSpeechVoiceSelect)\n    }\n  },\n}\n"],"names":["inject","shallowRef","ref","onUnmounted","readonly","computed","_createElementBlock","_hoisted_2","_hoisted_3","_Fragment","_hoisted_4","_renderList","_openBlock","_toDisplayString","_hoisted_6","watch","onMounted","_unref","_hoisted_1","_createElementVNode","_createVNode","_hoisted_5","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_renderSlot","_normalizeClass"],"mappings":"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"}