UNPKG

@kitn.ai/ui

Version:

Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.

2 lines (1 loc) 4.91 kB
import{g as k,p as C,s as L,h as j,l as P,i as I,c as g,F,z as V,S,n as M,a as D,b as U,t as x,f as $}from"./chunks/define-CNSKFZCd.js";import{c as z}from"./chunks/cn-CU7UAWzk.js";import{B as q}from"./chunks/button-DBDZebGr.js";import{T as A}from"./chunks/tooltip-Cft_Rxiw.js";function G(e={}){const s=e.mimeType??"audio/webm;codecs=opus",[o,h]=k(!1),[a,i]=k(null);let n,c=[],l;async function m(){i(null),c=[];try{const r=await navigator.mediaDevices.getUserMedia({audio:!0});return n=new MediaRecorder(r,{mimeType:s}),n.ondataavailable=u=>{u.data.size>0&&c.push(u.data)},n.onstop=()=>{const u=new Blob(c,{type:s});r.getTracks().forEach(t=>t.stop()),h(!1),l?.(u)},n.start(),h(!0),new Promise(u=>{l=u})}catch(r){throw i(r instanceof Error?r.message:"Microphone access denied"),h(!1),r}}function f(){n&&n.state==="recording"&&n.stop()}return C(()=>f()),{isRecording:o,error:a,start:m,stop:f}}function B(){if(typeof window>"u")return;const e=window;return e.SpeechRecognition??e.webkitSpeechRecognition}function H(e={}){const[s,o]=k(!1),[h,a]=k(null),i=B()!==void 0;let n,c,l="";function m(r={}){a(null),l="";const u=B();if(!u){const t="SpeechRecognition is not supported in this browser";return a(t),Promise.reject(new Error(t))}try{return n=new u,r.lang&&(n.lang=r.lang),n.interimResults=e.interim===!0,n.continuous=!1,n.onresult=t=>{var w;let v="";for(let b=t.resultIndex;b<t.results.length;b++){const T=t.results[b],R=((w=T[0])==null?void 0:w.transcript)??"";T.isFinal?l+=R:v+=R}v&&r.onInterim&&r.onInterim(v)},n.onerror=t=>{a(t.error??"Speech recognition error")},n.onend=()=>{o(!1),c?.(l),n=void 0},n.start(),o(!0),new Promise(t=>{c=t})}catch(t){throw a(t instanceof Error?t.message:"Speech recognition failed to start"),o(!1),t}}function f(){n&&s()&&n.stop()}return C(()=>{n&&n.abort()}),{isSupported:i,isListening:s,error:h,start:m,stop:f}}var J=x('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2 stroke-linecap=round stroke-linejoin=round><path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"></path><path d="M19 10v2a7 7 0 01-14 0v-2"></path><line x1=12 y1=19 x2=12 y2=23></line><line x1=8 y1=23 x2=16 y2=23>'),K=x('<svg width=14 height=14 viewBox="0 0 24 24"fill=currentColor><rect x=4 y=4 width=16 height=16 rx=2>'),N=x('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2 class=animate-spin><path d="M21 12a9 9 0 11-6.219-8.56">'),O=x("<div>"),W=x('<div class="absolute inset-0 animate-ping rounded-full border-2 border-red-400/30"style=animation-duration:2s>');function _(e){var s;const[o]=L(e,["onTranscribe","onTranscription","disabled","class"]),{isRecording:h,start:a,stop:i}=G(),n=H({interim:e.interim}),[c,l]=k(!1),m=()=>!e.hasTranscribe&&n.isSupported,f=()=>c()?"Transcribing...":r()?"Stop recording":"Voice input",r=()=>m()?n.isListening():h();async function u(){try{const d=await n.start({lang:e.lang,onInterim:e.interim?p=>{var y;return(y=e.onInterim)==null?void 0:y.call(e,p)}:void 0});d.trim()&&o.onTranscription(d.trim())}catch{}}async function t(){try{const d=await a();l(!0);try{const p=await o.onTranscribe(d);p.trim()&&o.onTranscription(p.trim())}finally{l(!1)}}catch{l(!1)}}function w(){m()?u():t()}function v(){m()?n.stop():i()}async function b(){r()?v():w()}j(P(r,d=>{var p;(p=e.onRecordingChange)==null||p.call(e,d)},{defer:!0})),(s=e.controllerRef)==null||s.call(e,{start:()=>{r()||w()},stop:()=>v()});const T=()=>J(),R=()=>K(),E=()=>N();return(()=>{var d=O();return I(d,g(S,{get when(){return r()},get children(){return g(F,{each:[0,1,2],children:p=>(()=>{var y=W();return V(y,"animation-delay",`${p*.3}s`),y})()})}}),null),I(d,g(A,{get content(){return f()},get children(){return g(q,{variant:"ghost",size:"icon-sm",get"aria-label"(){return f()},onClick:b,get disabled(){return o.disabled||c()},get class(){return z("relative z-10 rounded-full transition-all duration-300",r()&&"bg-destructive text-white hover:bg-destructive/80")},get children(){return[g(S,{get when(){return c()},get children(){return g(E,{})}}),g(S,{get when(){return M(()=>!c())()&&r()},get children(){return g(R,{})}}),g(S,{get when(){return M(()=>!c())()&&!r()},get children(){return g(T,{})}})]}})}}),null),D(()=>U(d,z("relative inline-flex items-center justify-center",o.class))),d})()}$("kai-voice-input",{transcribe:void 0,disabled:!1,recognitionLang:void 0,interim:!1},(e,{dispatch:s,flag:o,expose:h})=>{let a;return h({start:()=>a?.start(),stop:()=>a?.stop()}),g(_,{get disabled(){return o("disabled")},get hasTranscribe(){return typeof e.transcribe=="function"},get lang(){return e.recognitionLang},get interim(){return o("interim")},onTranscribe:async i=>(s("kai-audio-captured",{blob:i}),e.transcribe?e.transcribe(i):""),onTranscription:i=>s("kai-transcription",{text:i}),onInterim:i=>s("kai-transcript-interim",{text:i}),onRecordingChange:i=>s("kai-recording-change",{recording:i}),controllerRef:i=>a=i})});