@magicx-eng/ai-autocomplete-react 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-react";
|
|
|
41
41
|
function App() {
|
|
42
42
|
return (
|
|
43
43
|
<AIAutocomplete
|
|
44
|
-
apiConfig={{ apiKey: "your_api_key" }}
|
|
44
|
+
apiConfig={{ endpoint: "https://api.example.com/ac/suggest", apiKey: "your_api_key" }}
|
|
45
45
|
onSubmit={(result) => {
|
|
46
46
|
console.log(result.query); // "Create a email"
|
|
47
47
|
console.log(result.raw_query); // "Create a {{TASK_1}}"
|
|
@@ -73,7 +73,7 @@ function App() {
|
|
|
73
73
|
reset,
|
|
74
74
|
} = useAIAutocomplete({
|
|
75
75
|
onSubmit: (result) => handleMySubmit(result),
|
|
76
|
-
apiConfig: { apiKey: "your_api_key" },
|
|
76
|
+
apiConfig: { endpoint: "https://api.example.com/ac/suggest", apiKey: "your_api_key" },
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
return (
|
|
@@ -143,6 +143,7 @@ The full component. Owns the input, pills, dropdown, and keyboard navigation.
|
|
|
143
143
|
|
|
144
144
|
| Field | Type | Description |
|
|
145
145
|
|---|---|---|
|
|
146
|
+
| `endpoint?` | `string` | Full URL for the suggest endpoint (e.g. `"https://api.example.com/ac/suggest"`). Falls back to `MAGICX_API_ENDPOINT` env var, then `"/ac/suggest"`. |
|
|
146
147
|
| `apiKey?` | `string` | API key for Authorization header. Falls back to `MAGICX_AI_AUTOCOMPLETE_API_KEY` env var. |
|
|
147
148
|
| `authScheme?` | `"Bearer" \| "Basic"` | Auth header scheme. Default: `"Bearer"`. |
|
|
148
149
|
| `headers?` | `Record<string, string>` | Additional headers merged into every request. |
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var ye=Object.defineProperty;var Ze=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var ot=(e,o)=>{for(var t in o)ye(e,t,{get:o[t],enumerable:!0})},rt=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of et(o))!tt.call(e,r)&&r!==t&&ye(e,r,{get:()=>o[r],enumerable:!(n=Ze(o,r))||n.enumerable});return e};var nt=e=>rt(ye({},"__esModule",{value:!0}),e);var vt={};ot(vt,{AIAutocomplete:()=>qe,AIAutocompleteDropdown:()=>ne,useAIAutocomplete:()=>ce});module.exports=nt(vt);var D=require("react");var K={};var Se={};var _e={};var Y={};var re=require("react/jsx-runtime");function Te({option:e,isHighlighted:o,onSelect:t,onHighlight:n,id:r}){let a=[Y.item,o?Y.highlighted:"",e.is_tappable?Y.tappable:Y.nonTappable].filter(Boolean).join(" ");return(0,re.jsxs)("div",{id:r,role:"option","aria-selected":o,className:a,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&t(e),onKeyDown:i=>{e.is_tappable&&(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),t(e))},onMouseEnter:n,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&(0,re.jsx)("span",{className:Y.tag,children:e.tag})]})}var xe=require("react/jsx-runtime");function Me({options:e,activeIndex:o,onSelect:t,onHighlight:n,listboxId:r}){return(0,xe.jsx)("div",{className:_e.grid,children:e.map((a,i)=>(0,xe.jsx)(Te,{option:a,isHighlighted:i===o,onSelect:t,onHighlight:()=>n(i),id:`${r}-option-${i}`},a.text))})}var Pe=require("react/jsx-runtime");function ne({suggestions:e,activeIndex:o,onSelect:t,onHighlight:n,isOpen:r,id:a,className:i}){let m=e[0],g=r&&m&&m.options.length>0;return(0,Pe.jsx)("div",{id:a,role:"listbox",className:`${Se.dropdown} ${g?Se.visible:""} ${i??""}`,onMouseDown:h=>h.preventDefault(),children:m&&m.options.length>0&&(0,Pe.jsx)(Me,{options:m.options,activeIndex:o,onSelect:t,onHighlight:n,listboxId:a})})}var ae={};var ve=require("react/jsx-runtime");function ut(e){return e===0?.4:e===1?.3:.15}function Ee({pills:e,activePillIndex:o,onSelectPill:t}){return(0,ve.jsx)("span",{className:ae.list,children:e.map((n,r)=>(0,ve.jsx)("button",{type:"button",className:`${ae.pill} ${r===o?ae.active:""}`,style:{opacity:ut(r)},onClick:()=>t(r),children:n.text},`${n.type}-${n.text}`))})}var p=require("react");function se(e,o){let t=o.trimStart();if(!t)return e;let n=t.toLowerCase();return e.filter(r=>!r.is_tappable||r.text.toLowerCase().includes(n))}function Z(e,o){let t=o.trim();if(!t)return null;let n=t.toLowerCase();return e.find(r=>r.is_tappable&&r.text.toLowerCase()===n)??null}function Ue(e,o){let t=[],n=0;for(let a of o){let i=e.indexOf(a.text,n);i!==-1&&(i>n&&t.push({type:"text",value:e.slice(n,i)}),t.push({type:"completed",value:a.text,param:a}),n=i+a.text.length)}let r=e.slice(n);return r&&t.push({type:"text",value:r}),t}function Le(e,o){let t=[],n=[],r=0;for(let a of o){let i=e.indexOf(a.text,r);i===-1?n.push(a):(t.push(a),r=i+a.text.length)}return{valid:t,invalid:n}}var M=require("react");var pt="0.1.6",mt=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",Ne=!1;function dt(e){let o=e?.apiKey||process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!o&&!Ne&&(Ne=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),o}function ft(e){return e?.authScheme?e.authScheme:process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function gt(){return crypto.randomUUID()}function ht(e,o){return{placeholder:e.placeholder,type:e.type,...o&&{text:e.text},kind:e.kind}}async function De(e,o,t){let n=t?.apiConfig,r=dt(n),a=ft(n),i=!t?.maskCompletedText,m=o.find(c=>c.type==="contact"&&c.metadata?.contact_account_count)?.metadata?.contact_account_count,g=typeof m=="number"?m:void 0,h={data:{raw_query:e,completed_params:o.map(c=>ht(c,i)),...g!=null&&{contact_account_count:g}},meta:{request_id:gt(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:pt}},d={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo",...n?.headers};r&&(d.Authorization=a==="Basic"?`Basic ${btoa(r)}`:`Bearer ${r}`);let b=await fetch(mt,{method:"POST",headers:d,body:JSON.stringify(h),signal:t?.signal});if(!b.ok)throw new Error(`API error: ${b.status} ${b.statusText}`);return b.json()}function J(e,o){let t=e,n={},r=[];for(let a of o){let i=(n[a.type]??0)+1;n[a.type]=i;let g=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,h=t.indexOf(a.text);h!==-1&&(t=t.slice(0,h)+g+t.slice(h+a.text.length)),r.push({...a,placeholder:g})}return{rawQuery:t,completedParams:r}}function $e(e,o){return o?e.map(t=>{let n=o[t.type];if(!n)return t;let r=n("");if(r.length===0)return t;let a=new Set(r.map(m=>m.text)),i=(t.options??[]).filter(m=>!a.has(m.text));return{...t,options:[...r,...i]}}):e}var bt=100,yt=300,St=2;function Fe({textRef:e,suggestionsRef:o,filterBaseRef:t,maskCompletedTextRef:n,apiConfigRef:r,optionOverridesRef:a,onErrorRef:i,setCompletedParams:m,setSuggestions:g,setActiveDropdownIndex:h}){let[d,b]=(0,M.useState)(!1),[c,S]=(0,M.useState)(null),[O,y]=(0,M.useState)(!1),C=(0,M.useRef)(0),L=(0,M.useRef)(null),f=(0,M.useRef)(""),l=(0,M.useCallback)(async(s,u)=>{L.current?.abort();let P=new AbortController;L.current=P;let I=++C.current,R=e.current.length;o.current.some(k=>k.type!=="placeholder")||b(!0),S(null);try{let k=await De(s,u,{maskCompletedText:n.current,signal:P.signal,apiConfig:r.current});if(I!==C.current)return;let $=$e(k.data.suggestions??[],a.current);y(k.data.is_ready??!1),f.current=s;let B=k.data.input??[],E=B[B.length-1],U=e.current;if(E?.state==="in_progress"){let j=U.toLowerCase().lastIndexOf(E.text.toLowerCase());j!==-1?t.current=j:t.current=R}else t.current=R;let F=$.filter(j=>j.type!=="placeholder")[0];if(F){let j=U.slice(t.current),_=Z(F.options,j);_&&(m(z=>[...z,{id:crypto.randomUUID(),placeholder:"",type:F.type,text:_.text,kind:_.kind,suggestionType:F.type,suggestionPlaceholder:F.text,options:F.options,metadata:_.metadata}]),$=$.filter(z=>z!==F))}g($),b(!1),h(-1)}catch(k){if(I===C.current){let $=k instanceof Error?k:new Error(String(k));S($),b(!1),i.current?.($)}}},[e,o,t,n,r,a,i,m,g,h]);return(0,M.useEffect)(()=>(l("",[]),()=>{L.current?.abort()}),[l]),{doFetch:l,isLoading:d,error:c,isReady:O,lastRawQueryRef:f}}function Ke({text:e,completedParams:o,doFetch:t,filterBaseRef:n,skipNextFetchRef:r,suggestionsRef:a,lastRawQueryRef:i}){let m=(0,M.useRef)(null),g=(0,M.useRef)(null),h=(0,M.useRef)(!0);(0,M.useEffect)(()=>{m.current&&clearTimeout(m.current),g.current&&clearTimeout(g.current);let d=b=>{if(r.current)return r.current=!1,!1;if(!e&&o.length===0)return h.current?(t("",[]),!0):(h.current=!0,!1);let c=e.slice(n.current),y=a.current.filter(R=>R.type!=="placeholder")[0],L=(y?se(y.options,c):[]).filter(R=>R.is_tappable),f=y?Z(y.options,c)!==null:!1,l=c.trim().length>0;if(L.length>0&&!f&&l)return!1;let{rawQuery:s,completedParams:u}=J(e,o),P=s.length<i.current.length,I=Math.abs(s.length-i.current.length);return P||I>=b?(t(s,u),!0):!1};return m.current=setTimeout(()=>{d(St)&&g.current&&clearTimeout(g.current)},bt),g.current=setTimeout(()=>d(1),yt),()=>{m.current&&clearTimeout(m.current),g.current&&clearTimeout(g.current)}},[e,o,t,n,r,a,i])}var Ae=require("react");function je({activeDropdownIndex:e,setActiveDropdownIndex:o,filteredOptions:t,selectOption:n,onSubmitRef:r,text:a,completedParams:i,isDropdownOpen:m,hasPlaceholder:g,placeholderText:h,suggestions:d,filterBaseRef:b,columns:c,setText:S,setCompletedParams:O,setSuggestions:y}){let C=(0,Ae.useCallback)(()=>{let f=t.map((s,u)=>s.is_tappable?u:-1).filter(s=>s!==-1),l=Array.from({length:c},()=>[]);for(let s of f)l[s%c].push(s);return l.flat()},[t,c]);return{handleKeyDown:(0,Ae.useCallback)(f=>{let l=C();switch(f.key){case"ArrowDown":{if(f.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s<l.length-1?s+1:0;o(l[u]);break}case"ArrowUp":{if(f.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s>0?s-1:l.length-1;o(l[u]);break}case"ArrowRight":{if(e<0)break;if(e%c<c-1){let u=e+1;u<t.length&&t[u]?.is_tappable&&(f.preventDefault(),o(u))}break}case"ArrowLeft":{if(e<0)break;if(e%c>0){let s=e-1;s>=0&&t[s]?.is_tappable&&(f.preventDefault(),o(s))}break}case"Enter":{if(f.preventDefault(),e>=0&&t[e]?.is_tappable)n(t[e]);else if(r.current){let{rawQuery:s,completedParams:u}=J(a,i),P={query:a.trim(),raw_query:s,completed_params:u};r.current(P)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)f.preventDefault(),n(t[e]);else if(m){let s=t.find(u=>u.is_tappable);s&&(f.preventDefault(),n(s))}else if(!a&&g){f.preventDefault();let s=d.find(u=>u.type==="placeholder");s?(S(h),b.current=h.length,O(u=>[...u,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:h,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),y(u=>u.filter(P=>P!==s))):(S(h),b.current=h.length)}break}case"Escape":o(-1);break}},[e,c,i,t,b,C,g,m,r,h,n,o,O,y,S,d,a]),getTappableIndices:C}}var ie=require("react");function ze({completedParams:e,suggestions:o,setCompletedParams:t,setSuggestions:n,setActiveDropdownIndex:r,filterBaseRef:a,pillTappedRef:i}){let m=(0,ie.useCallback)(d=>{let b=o.filter(y=>y.type!=="placeholder");if(d<0||d>=b.length)return;let c=b[d],S=b.filter((y,C)=>C!==d),O=o.filter(y=>y.type==="placeholder");n([...O,c,...S]),i.current=!0,r(-1)},[o,n,r,i]),g=(0,ie.useCallback)(()=>{if(e.length===0)return;let d=e[e.length-1],b={type:d.suggestionType,text:d.suggestionPlaceholder,required:!0,options:d.options};t(c=>c.slice(0,-1)),n(c=>[b,...c]),r(-1)},[e,t,n,r]),h=(0,ie.useCallback)(d=>{let b={type:d.suggestionType,text:d.suggestionPlaceholder,required:!0,options:d.options};return{apply:c=>{c(S=>{let O=0;for(let y of e){let C=S.indexOf(y.text,O);if(C!==-1){if(y.id===d.id){let L=S.slice(0,C),f=S.slice(C+d.text.length),l=(L+f).replace(/ {2,}/g," ");return a.current=Math.min(a.current,l.length),l}O=C+y.text.length}}return S}),t(S=>S.filter(O=>O.id!==d.id)),n(S=>[b,...S]),r(-1),i.current=!0}}},[e,t,n,r,a,i]);return{setActivePill:m,removeLastParam:g,reEditParam:h}}var xt=0;function Pt(){let e=(0,p.useRef)(null);return e.current===null&&(e.current=`:ac-${++xt}:`),e.current}function ce({onSubmit:e,onError:o,optionOverrides:t,maskCompletedText:n,placeholder:r,apiConfig:a,columns:i=2,eagerSuggestions:m=!0,value:g,completedParams:h,onChange:d,onParamsChange:b}){let c=g!==void 0,S=h!==void 0,[O,y]=(0,p.useState)(""),[C,L]=(0,p.useState)([]),[f,l]=(0,p.useState)([]),[s,u]=(0,p.useState)(-1),P=c?g:O,I=S?h:C,R=(0,p.useRef)(e);R.current=e;let H=(0,p.useRef)(d);H.current=d;let k=(0,p.useRef)(b);k.current=b;let $=(0,p.useRef)(g);$.current=g;let B=(0,p.useRef)(h);B.current=h;let E=(0,p.useCallback)(x=>{if(typeof x=="function")if(c){let A=x($.current??"");H.current?.(A)}else y(A=>{let Q=x(A);return H.current?.(Q),Q});else c||y(x),H.current?.(x)},[c]),U=(0,p.useCallback)(x=>{if(typeof x=="function")if(S){let A=x(B.current??[]);k.current?.(A)}else L(A=>{let Q=x(A);return k.current?.(Q),Q});else S||L(x),k.current?.(x)},[S]),W=(0,p.useRef)(o);W.current=o;let F=(0,p.useRef)(t);F.current=t;let j=(0,p.useRef)(n);j.current=n;let _=(0,p.useRef)(a);_.current=a;let z=(0,p.useRef)(P);z.current=P;let le=(0,p.useRef)(f);le.current=f;let q=(0,p.useRef)(0),ee=(0,p.useRef)(!1),Ce=(0,p.useRef)(!1),ue=Pt(),{doFetch:pe,isLoading:ke,error:Be,isReady:Qe,lastRawQueryRef:me}=Fe({textRef:z,suggestionsRef:le,filterBaseRef:q,maskCompletedTextRef:j,apiConfigRef:_,optionOverridesRef:F,onErrorRef:W,setCompletedParams:U,setSuggestions:l,setActiveDropdownIndex:u});Ke({text:P,completedParams:I,doFetch:pe,filterBaseRef:q,skipNextFetchRef:Ce,suggestionsRef:le,lastRawQueryRef:me});let He=(0,p.useMemo)(()=>Ue(P,I),[P,I]);q.current=Math.min(q.current,P.length);let de=P.slice(q.current),fe=(0,p.useMemo)(()=>f.filter(A=>A.type==="placeholder").map(A=>A.text).join(" ")||r||"",[f,r]),te=(0,p.useMemo)(()=>f.filter(x=>x.type!=="placeholder"),[f]),v=te[0],we=v?t?.[v.type]:void 0,Oe=v?we?we(de.trim()):v.options??[]:[],ge=(0,p.useMemo)(()=>se(Oe,de),[Oe,de]),Ie=fe.length>0,he=!ke&&ge.length>0&&(!!P||ee.current||!Ie),Re=(0,p.useCallback)(x=>{if(!v)return;let A={id:crypto.randomUUID(),placeholder:"",type:v.type,text:x.text,kind:x.kind,suggestionType:v.type,suggestionPlaceholder:v.text,options:v.options,metadata:x.metadata},Q=q.current,N=z.current.slice(0,Q);if(N.length>0&&!N.endsWith(" ")){let T=N.split(/\s+/).pop()??"";T&&x.text.toLowerCase().startsWith(T.toLowerCase())&&(N=N.slice(0,N.length-T.length))}let be=N.length>0&&N[N.length-1]!==" ",G=N+(be?" ":"")+x.text+" ";E(G),q.current=G.length,U(T=>[...T,A]),ee.current=!1,u(-1);let V=te.length-1;m&&V>0?(l(T=>T.filter(X=>X!==v)),Ce.current=!0):l(T=>T.filter(X=>X.type==="placeholder"))},[v,te,m,E,U]),Ve=(0,p.useCallback)(x=>{let A=x.target.value,N=A.length>0&&!x.nativeEvent?.isComposing&&A[0]!==A[0].toUpperCase()?A[0].toUpperCase()+A.slice(1):A;E(N),ee.current=!1,u(-1);let{valid:be,invalid:G}=Le(N,I);if(G.length>0){U(()=>be);for(let V of G)l(T=>[{type:V.suggestionType,text:V.suggestionPlaceholder,required:!0,options:V.options},...T])}if(v&&G.length===0){let V=N.slice(q.current),T=Z(v.options,V);T&&(U(X=>[...X,{id:crypto.randomUUID(),placeholder:"",type:v.type,text:T.text,kind:T.kind,suggestionType:v.type,suggestionPlaceholder:v.text,options:v.options,metadata:T.metadata}]),l(X=>X.filter(Je=>Je!==v)))}},[I,v,E,U]),{handleKeyDown:Xe}=je({activeDropdownIndex:s,setActiveDropdownIndex:u,filteredOptions:ge,selectOption:Re,onSubmitRef:R,text:P,completedParams:I,isDropdownOpen:he,hasPlaceholder:Ie,placeholderText:fe,suggestions:f,filterBaseRef:q,columns:i,setText:E,setCompletedParams:U,setSuggestions:l}),oe=ze({completedParams:I,suggestions:f,setCompletedParams:U,setSuggestions:l,setActiveDropdownIndex:u,filterBaseRef:q,pillTappedRef:ee}),We=(0,p.useCallback)(x=>{oe.reEditParam(x).apply(E)},[oe,E]),Ge=(0,p.useCallback)(()=>{E(""),U(()=>[]),l([]),u(-1),q.current=0,me.current="",pe("",[])},[pe,E,U,me]),Ye=s>=0?`${ue}-option-${s}`:void 0;return{completedParams:I,suggestionPills:te,setActivePill:oe.setActivePill,removeLastParam:oe.removeLastParam,reEditParam:We,segments:He,suggestions:f,activeIndex:s,isReady:Qe,isLoading:ke,error:Be,inputProps:{value:P,placeholder:fe||void 0,onChange:Ve,onKeyDown:Xe,role:"combobox","aria-expanded":he,"aria-activedescendant":Ye,"aria-autocomplete":"list","aria-controls":ue},reset:Ge,dropdownProps:{suggestions:v?[{...v,options:ge}]:[],activeIndex:s,onSelect:Re,onHighlight:u,isOpen:he,id:ue}}}var w=require("react/jsx-runtime"),qe=(0,D.forwardRef)(function({onSubmit:o,onError:t,optionOverrides:n,maskCompletedText:r,placeholder:a,className:i,apiConfig:m,columns:g,eagerSuggestions:h,value:d,completedParams:b,onChange:c,onParamsChange:S},O){let y=(0,D.useRef)(null),[C,L]=(0,D.useState)(!1),f=(0,D.useRef)(()=>{}),l=(0,D.useRef)(void 0);(0,D.useEffect)(()=>(y.current?.focus(),()=>clearTimeout(l.current)),[]);let{completedParams:s,suggestionPills:u,setActivePill:P,segments:I,inputProps:R,dropdownProps:H,reset:k}=ce({onSubmit:_=>f.current(_),onError:t,optionOverrides:n,maskCompletedText:r,placeholder:a,apiConfig:m,columns:g,eagerSuggestions:h,value:d,completedParams:b,onChange:c,onParamsChange:S});(0,D.useImperativeHandle)(O,()=>({focus:()=>y.current?.focus(),reset:k}),[k]);let $=()=>{y.current?.focus()},B=!!R.value||s.length>0,E=(0,D.useCallback)(()=>{if(!B)return;let{rawQuery:_,completedParams:z}=J(R.value,s);o({query:R.value.trim(),raw_query:_,completed_params:z}),k(),L(!0),clearTimeout(l.current),l.current=setTimeout(()=>L(!1),3e3)},[B,R.value,s,o,k]);f.current=E;let{onChange:U,placeholder:W,...F}=R,j=!R.value;return(0,w.jsxs)("div",{className:`${K.container} ${i??""}`,children:[(0,w.jsx)("div",{className:`${K.checkmark} ${C?K.checkmarkVisible:""}`,children:(0,w.jsxs)("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[(0,w.jsx)("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),(0,w.jsx)("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:K.checkmarkPath})]})}),(0,w.jsx)(ne,{...H}),(0,w.jsxs)("div",{className:K.inputWrapper,onClick:$,children:[(0,w.jsxs)("div",{className:K.editorArea,children:[(0,w.jsxs)("div",{className:K.sizerContent,"aria-hidden":"true",children:[j&&W?(0,w.jsxs)("span",{className:K.placeholderText,children:[W," "]}):(0,w.jsxs)("span",{className:K.sizerText,children:[I.map((_,z)=>(0,w.jsx)("span",{children:_.value},`${z}-${_.type}`)),I.length===0&&"\xA0"]})," ",(0,w.jsx)(Ee,{pills:u,activePillIndex:0,onSelectPill:P})]}),(0,w.jsx)("textarea",{ref:y,className:K.textarea,rows:1,onChange:U,...F})]}),(0,w.jsx)("button",{type:"button",className:K.submitButton,disabled:!B,onClick:_=>{_.stopPropagation(),E()},"aria-label":"Submit",children:(0,w.jsx)("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:(0,w.jsx)("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});0&&(module.exports={AIAutocomplete,AIAutocompleteDropdown,useAIAutocomplete});
|
|
1
|
+
"use strict";var ye=Object.defineProperty;var Ze=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var ot=(e,o)=>{for(var t in o)ye(e,t,{get:o[t],enumerable:!0})},rt=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of et(o))!tt.call(e,r)&&r!==t&&ye(e,r,{get:()=>o[r],enumerable:!(n=Ze(o,r))||n.enumerable});return e};var nt=e=>rt(ye({},"__esModule",{value:!0}),e);var vt={};ot(vt,{AIAutocomplete:()=>qe,AIAutocompleteDropdown:()=>ne,useAIAutocomplete:()=>ce});module.exports=nt(vt);var D=require("react");var K={};var Se={};var _e={};var Y={};var re=require("react/jsx-runtime");function Te({option:e,isHighlighted:o,onSelect:t,onHighlight:n,id:r}){let a=[Y.item,o?Y.highlighted:"",e.is_tappable?Y.tappable:Y.nonTappable].filter(Boolean).join(" ");return(0,re.jsxs)("div",{id:r,role:"option","aria-selected":o,className:a,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&t(e),onKeyDown:i=>{e.is_tappable&&(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),t(e))},onMouseEnter:n,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&(0,re.jsx)("span",{className:Y.tag,children:e.tag})]})}var xe=require("react/jsx-runtime");function Ee({options:e,activeIndex:o,onSelect:t,onHighlight:n,listboxId:r}){return(0,xe.jsx)("div",{className:_e.grid,children:e.map((a,i)=>(0,xe.jsx)(Te,{option:a,isHighlighted:i===o,onSelect:t,onHighlight:()=>n(i),id:`${r}-option-${i}`},a.text))})}var Pe=require("react/jsx-runtime");function ne({suggestions:e,activeIndex:o,onSelect:t,onHighlight:n,isOpen:r,id:a,className:i}){let m=e[0],g=r&&m&&m.options.length>0;return(0,Pe.jsx)("div",{id:a,role:"listbox",className:`${Se.dropdown} ${g?Se.visible:""} ${i??""}`,onMouseDown:h=>h.preventDefault(),children:m&&m.options.length>0&&(0,Pe.jsx)(Ee,{options:m.options,activeIndex:o,onSelect:t,onHighlight:n,listboxId:a})})}var ae={};var ve=require("react/jsx-runtime");function ut(e){return e===0?.4:e===1?.3:.15}function Me({pills:e,activePillIndex:o,onSelectPill:t}){return(0,ve.jsx)("span",{className:ae.list,children:e.map((n,r)=>(0,ve.jsx)("button",{type:"button",className:`${ae.pill} ${r===o?ae.active:""}`,style:{opacity:ut(r)},onClick:()=>t(r),children:n.text},`${n.type}-${n.text}`))})}var p=require("react");function se(e,o){let t=o.trimStart();if(!t)return e;let n=t.toLowerCase();return e.filter(r=>!r.is_tappable||r.text.toLowerCase().includes(n))}function Z(e,o){let t=o.trim();if(!t)return null;let n=t.toLowerCase();return e.find(r=>r.is_tappable&&r.text.toLowerCase()===n)??null}function Ue(e,o){let t=[],n=0;for(let a of o){let i=e.indexOf(a.text,n);i!==-1&&(i>n&&t.push({type:"text",value:e.slice(n,i)}),t.push({type:"completed",value:a.text,param:a}),n=i+a.text.length)}let r=e.slice(n);return r&&t.push({type:"text",value:r}),t}function Le(e,o){let t=[],n=[],r=0;for(let a of o){let i=e.indexOf(a.text,r);i===-1?n.push(a):(t.push(a),r=i+a.text.length)}return{valid:t,invalid:n}}var E=require("react");var pt="0.1.7",mt="/ac/suggest",Ne=!1;function dt(e){let o=e?.apiKey||""||"";return!o&&!Ne&&(Ne=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),o}function ft(e){return e?.authScheme?e.authScheme:""==="Basic"?"Basic":"Bearer"}function gt(){return crypto.randomUUID()}function ht(e,o){return{placeholder:e.placeholder,type:e.type,...o&&{text:e.text},kind:e.kind}}async function De(e,o,t){let n=t?.apiConfig,r=dt(n),a=ft(n),i=!t?.maskCompletedText,m=o.find(c=>c.type==="contact"&&c.metadata?.contact_account_count)?.metadata?.contact_account_count,g=typeof m=="number"?m:void 0,h={data:{raw_query:e,completed_params:o.map(c=>ht(c,i)),...g!=null&&{contact_account_count:g}},meta:{request_id:gt(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:pt}},d={"Content-Type":"application/json","X-App-Identifier":"active-campaign-demo",...n?.headers};r&&(d.Authorization=a==="Basic"?`Basic ${btoa(r)}`:`Bearer ${r}`);let b=await fetch(n?.endpoint||mt,{method:"POST",headers:d,body:JSON.stringify(h),signal:t?.signal});if(!b.ok)throw new Error(`API error: ${b.status} ${b.statusText}`);return b.json()}function J(e,o){let t=e,n={},r=[];for(let a of o){let i=(n[a.type]??0)+1;n[a.type]=i;let g=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,h=t.indexOf(a.text);h!==-1&&(t=t.slice(0,h)+g+t.slice(h+a.text.length)),r.push({...a,placeholder:g})}return{rawQuery:t,completedParams:r}}function Fe(e,o){return o?e.map(t=>{let n=o[t.type];if(!n)return t;let r=n("");if(r.length===0)return t;let a=new Set(r.map(m=>m.text)),i=(t.options??[]).filter(m=>!a.has(m.text));return{...t,options:[...r,...i]}}):e}var bt=100,yt=300,St=2;function $e({textRef:e,suggestionsRef:o,filterBaseRef:t,maskCompletedTextRef:n,apiConfigRef:r,optionOverridesRef:a,onErrorRef:i,setCompletedParams:m,setSuggestions:g,setActiveDropdownIndex:h}){let[d,b]=(0,E.useState)(!1),[c,S]=(0,E.useState)(null),[O,y]=(0,E.useState)(!1),C=(0,E.useRef)(0),L=(0,E.useRef)(null),f=(0,E.useRef)(""),l=(0,E.useCallback)(async(s,u)=>{L.current?.abort();let P=new AbortController;L.current=P;let I=++C.current,R=e.current.length;o.current.some(k=>k.type!=="placeholder")||b(!0),S(null);try{let k=await De(s,u,{maskCompletedText:n.current,signal:P.signal,apiConfig:r.current});if(I!==C.current)return;let F=Fe(k.data.suggestions??[],a.current);y(k.data.is_ready??!1),f.current=s;let B=k.data.input??[],M=B[B.length-1],U=e.current;if(M?.state==="in_progress"){let j=U.toLowerCase().lastIndexOf(M.text.toLowerCase());j!==-1?t.current=j:t.current=R}else t.current=R;let $=F.filter(j=>j.type!=="placeholder")[0];if($){let j=U.slice(t.current),_=Z($.options,j);_&&(m(z=>[...z,{id:crypto.randomUUID(),placeholder:"",type:$.type,text:_.text,kind:_.kind,suggestionType:$.type,suggestionPlaceholder:$.text,options:$.options,metadata:_.metadata}]),F=F.filter(z=>z!==$))}g(F),b(!1),h(-1)}catch(k){if(I===C.current){let F=k instanceof Error?k:new Error(String(k));S(F),b(!1),i.current?.(F)}}},[e,o,t,n,r,a,i,m,g,h]);return(0,E.useEffect)(()=>(l("",[]),()=>{L.current?.abort()}),[l]),{doFetch:l,isLoading:d,error:c,isReady:O,lastRawQueryRef:f}}function Ke({text:e,completedParams:o,doFetch:t,filterBaseRef:n,skipNextFetchRef:r,suggestionsRef:a,lastRawQueryRef:i}){let m=(0,E.useRef)(null),g=(0,E.useRef)(null),h=(0,E.useRef)(!0);(0,E.useEffect)(()=>{m.current&&clearTimeout(m.current),g.current&&clearTimeout(g.current);let d=b=>{if(r.current)return r.current=!1,!1;if(!e&&o.length===0)return h.current?(t("",[]),!0):(h.current=!0,!1);let c=e.slice(n.current),y=a.current.filter(R=>R.type!=="placeholder")[0],L=(y?se(y.options,c):[]).filter(R=>R.is_tappable),f=y?Z(y.options,c)!==null:!1,l=c.trim().length>0;if(L.length>0&&!f&&l)return!1;let{rawQuery:s,completedParams:u}=J(e,o),P=s.length<i.current.length,I=Math.abs(s.length-i.current.length);return P||I>=b?(t(s,u),!0):!1};return m.current=setTimeout(()=>{d(St)&&g.current&&clearTimeout(g.current)},bt),g.current=setTimeout(()=>d(1),yt),()=>{m.current&&clearTimeout(m.current),g.current&&clearTimeout(g.current)}},[e,o,t,n,r,a,i])}var Ae=require("react");function je({activeDropdownIndex:e,setActiveDropdownIndex:o,filteredOptions:t,selectOption:n,onSubmitRef:r,text:a,completedParams:i,isDropdownOpen:m,hasPlaceholder:g,placeholderText:h,suggestions:d,filterBaseRef:b,columns:c,setText:S,setCompletedParams:O,setSuggestions:y}){let C=(0,Ae.useCallback)(()=>{let f=t.map((s,u)=>s.is_tappable?u:-1).filter(s=>s!==-1),l=Array.from({length:c},()=>[]);for(let s of f)l[s%c].push(s);return l.flat()},[t,c]);return{handleKeyDown:(0,Ae.useCallback)(f=>{let l=C();switch(f.key){case"ArrowDown":{if(f.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s<l.length-1?s+1:0;o(l[u]);break}case"ArrowUp":{if(f.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s>0?s-1:l.length-1;o(l[u]);break}case"ArrowRight":{if(e<0)break;if(e%c<c-1){let u=e+1;u<t.length&&t[u]?.is_tappable&&(f.preventDefault(),o(u))}break}case"ArrowLeft":{if(e<0)break;if(e%c>0){let s=e-1;s>=0&&t[s]?.is_tappable&&(f.preventDefault(),o(s))}break}case"Enter":{if(f.preventDefault(),e>=0&&t[e]?.is_tappable)n(t[e]);else if(r.current){let{rawQuery:s,completedParams:u}=J(a,i),P={query:a.trim(),raw_query:s,completed_params:u};r.current(P)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)f.preventDefault(),n(t[e]);else if(m){let s=t.find(u=>u.is_tappable);s&&(f.preventDefault(),n(s))}else if(!a&&g){f.preventDefault();let s=d.find(u=>u.type==="placeholder");s?(S(h),b.current=h.length,O(u=>[...u,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:h,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),y(u=>u.filter(P=>P!==s))):(S(h),b.current=h.length)}break}case"Escape":o(-1);break}},[e,c,i,t,b,C,g,m,r,h,n,o,O,y,S,d,a]),getTappableIndices:C}}var ie=require("react");function ze({completedParams:e,suggestions:o,setCompletedParams:t,setSuggestions:n,setActiveDropdownIndex:r,filterBaseRef:a,pillTappedRef:i}){let m=(0,ie.useCallback)(d=>{let b=o.filter(y=>y.type!=="placeholder");if(d<0||d>=b.length)return;let c=b[d],S=b.filter((y,C)=>C!==d),O=o.filter(y=>y.type==="placeholder");n([...O,c,...S]),i.current=!0,r(-1)},[o,n,r,i]),g=(0,ie.useCallback)(()=>{if(e.length===0)return;let d=e[e.length-1],b={type:d.suggestionType,text:d.suggestionPlaceholder,required:!0,options:d.options};t(c=>c.slice(0,-1)),n(c=>[b,...c]),r(-1)},[e,t,n,r]),h=(0,ie.useCallback)(d=>{let b={type:d.suggestionType,text:d.suggestionPlaceholder,required:!0,options:d.options};return{apply:c=>{c(S=>{let O=0;for(let y of e){let C=S.indexOf(y.text,O);if(C!==-1){if(y.id===d.id){let L=S.slice(0,C),f=S.slice(C+d.text.length),l=(L+f).replace(/ {2,}/g," ");return a.current=Math.min(a.current,l.length),l}O=C+y.text.length}}return S}),t(S=>S.filter(O=>O.id!==d.id)),n(S=>[b,...S]),r(-1),i.current=!0}}},[e,t,n,r,a,i]);return{setActivePill:m,removeLastParam:g,reEditParam:h}}var xt=0;function Pt(){let e=(0,p.useRef)(null);return e.current===null&&(e.current=`:ac-${++xt}:`),e.current}function ce({onSubmit:e,onError:o,optionOverrides:t,maskCompletedText:n,placeholder:r,apiConfig:a,columns:i=2,eagerSuggestions:m=!0,value:g,completedParams:h,onChange:d,onParamsChange:b}){let c=g!==void 0,S=h!==void 0,[O,y]=(0,p.useState)(""),[C,L]=(0,p.useState)([]),[f,l]=(0,p.useState)([]),[s,u]=(0,p.useState)(-1),P=c?g:O,I=S?h:C,R=(0,p.useRef)(e);R.current=e;let H=(0,p.useRef)(d);H.current=d;let k=(0,p.useRef)(b);k.current=b;let F=(0,p.useRef)(g);F.current=g;let B=(0,p.useRef)(h);B.current=h;let M=(0,p.useCallback)(x=>{if(typeof x=="function")if(c){let A=x(F.current??"");H.current?.(A)}else y(A=>{let Q=x(A);return H.current?.(Q),Q});else c||y(x),H.current?.(x)},[c]),U=(0,p.useCallback)(x=>{if(typeof x=="function")if(S){let A=x(B.current??[]);k.current?.(A)}else L(A=>{let Q=x(A);return k.current?.(Q),Q});else S||L(x),k.current?.(x)},[S]),W=(0,p.useRef)(o);W.current=o;let $=(0,p.useRef)(t);$.current=t;let j=(0,p.useRef)(n);j.current=n;let _=(0,p.useRef)(a);_.current=a;let z=(0,p.useRef)(P);z.current=P;let le=(0,p.useRef)(f);le.current=f;let q=(0,p.useRef)(0),ee=(0,p.useRef)(!1),Ce=(0,p.useRef)(!1),ue=Pt(),{doFetch:pe,isLoading:ke,error:Be,isReady:Qe,lastRawQueryRef:me}=$e({textRef:z,suggestionsRef:le,filterBaseRef:q,maskCompletedTextRef:j,apiConfigRef:_,optionOverridesRef:$,onErrorRef:W,setCompletedParams:U,setSuggestions:l,setActiveDropdownIndex:u});Ke({text:P,completedParams:I,doFetch:pe,filterBaseRef:q,skipNextFetchRef:Ce,suggestionsRef:le,lastRawQueryRef:me});let He=(0,p.useMemo)(()=>Ue(P,I),[P,I]);q.current=Math.min(q.current,P.length);let de=P.slice(q.current),fe=(0,p.useMemo)(()=>f.filter(A=>A.type==="placeholder").map(A=>A.text).join(" ")||r||"",[f,r]),te=(0,p.useMemo)(()=>f.filter(x=>x.type!=="placeholder"),[f]),v=te[0],we=v?t?.[v.type]:void 0,Oe=v?we?we(de.trim()):v.options??[]:[],ge=(0,p.useMemo)(()=>se(Oe,de),[Oe,de]),Ie=fe.length>0,he=!ke&&ge.length>0&&(!!P||ee.current||!Ie),Re=(0,p.useCallback)(x=>{if(!v)return;let A={id:crypto.randomUUID(),placeholder:"",type:v.type,text:x.text,kind:x.kind,suggestionType:v.type,suggestionPlaceholder:v.text,options:v.options,metadata:x.metadata},Q=q.current,N=z.current.slice(0,Q);if(N.length>0&&!N.endsWith(" ")){let T=N.split(/\s+/).pop()??"";T&&x.text.toLowerCase().startsWith(T.toLowerCase())&&(N=N.slice(0,N.length-T.length))}let be=N.length>0&&N[N.length-1]!==" ",G=N+(be?" ":"")+x.text+" ";M(G),q.current=G.length,U(T=>[...T,A]),ee.current=!1,u(-1);let V=te.length-1;m&&V>0?(l(T=>T.filter(X=>X!==v)),Ce.current=!0):l(T=>T.filter(X=>X.type==="placeholder"))},[v,te,m,M,U]),Ve=(0,p.useCallback)(x=>{let A=x.target.value,N=A.length>0&&!x.nativeEvent?.isComposing&&A[0]!==A[0].toUpperCase()?A[0].toUpperCase()+A.slice(1):A;M(N),ee.current=!1,u(-1);let{valid:be,invalid:G}=Le(N,I);if(G.length>0){U(()=>be);for(let V of G)l(T=>[{type:V.suggestionType,text:V.suggestionPlaceholder,required:!0,options:V.options},...T])}if(v&&G.length===0){let V=N.slice(q.current),T=Z(v.options,V);T&&(U(X=>[...X,{id:crypto.randomUUID(),placeholder:"",type:v.type,text:T.text,kind:T.kind,suggestionType:v.type,suggestionPlaceholder:v.text,options:v.options,metadata:T.metadata}]),l(X=>X.filter(Je=>Je!==v)))}},[I,v,M,U]),{handleKeyDown:Xe}=je({activeDropdownIndex:s,setActiveDropdownIndex:u,filteredOptions:ge,selectOption:Re,onSubmitRef:R,text:P,completedParams:I,isDropdownOpen:he,hasPlaceholder:Ie,placeholderText:fe,suggestions:f,filterBaseRef:q,columns:i,setText:M,setCompletedParams:U,setSuggestions:l}),oe=ze({completedParams:I,suggestions:f,setCompletedParams:U,setSuggestions:l,setActiveDropdownIndex:u,filterBaseRef:q,pillTappedRef:ee}),We=(0,p.useCallback)(x=>{oe.reEditParam(x).apply(M)},[oe,M]),Ge=(0,p.useCallback)(()=>{M(""),U(()=>[]),l([]),u(-1),q.current=0,me.current="",pe("",[])},[pe,M,U,me]),Ye=s>=0?`${ue}-option-${s}`:void 0;return{completedParams:I,suggestionPills:te,setActivePill:oe.setActivePill,removeLastParam:oe.removeLastParam,reEditParam:We,segments:He,suggestions:f,activeIndex:s,isReady:Qe,isLoading:ke,error:Be,inputProps:{value:P,placeholder:fe||void 0,onChange:Ve,onKeyDown:Xe,role:"combobox","aria-expanded":he,"aria-activedescendant":Ye,"aria-autocomplete":"list","aria-controls":ue},reset:Ge,dropdownProps:{suggestions:v?[{...v,options:ge}]:[],activeIndex:s,onSelect:Re,onHighlight:u,isOpen:he,id:ue}}}var w=require("react/jsx-runtime"),qe=(0,D.forwardRef)(function({onSubmit:o,onError:t,optionOverrides:n,maskCompletedText:r,placeholder:a,className:i,apiConfig:m,columns:g,eagerSuggestions:h,value:d,completedParams:b,onChange:c,onParamsChange:S},O){let y=(0,D.useRef)(null),[C,L]=(0,D.useState)(!1),f=(0,D.useRef)(()=>{}),l=(0,D.useRef)(void 0);(0,D.useEffect)(()=>(y.current?.focus(),()=>clearTimeout(l.current)),[]);let{completedParams:s,suggestionPills:u,setActivePill:P,segments:I,inputProps:R,dropdownProps:H,reset:k}=ce({onSubmit:_=>f.current(_),onError:t,optionOverrides:n,maskCompletedText:r,placeholder:a,apiConfig:m,columns:g,eagerSuggestions:h,value:d,completedParams:b,onChange:c,onParamsChange:S});(0,D.useImperativeHandle)(O,()=>({focus:()=>y.current?.focus(),reset:k}),[k]);let F=()=>{y.current?.focus()},B=!!R.value||s.length>0,M=(0,D.useCallback)(()=>{if(!B)return;let{rawQuery:_,completedParams:z}=J(R.value,s);o({query:R.value.trim(),raw_query:_,completed_params:z}),k(),L(!0),clearTimeout(l.current),l.current=setTimeout(()=>L(!1),3e3)},[B,R.value,s,o,k]);f.current=M;let{onChange:U,placeholder:W,...$}=R,j=!R.value;return(0,w.jsxs)("div",{className:`${K.container} ${i??""}`,children:[(0,w.jsx)("div",{className:`${K.checkmark} ${C?K.checkmarkVisible:""}`,children:(0,w.jsxs)("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[(0,w.jsx)("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),(0,w.jsx)("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:K.checkmarkPath})]})}),(0,w.jsx)(ne,{...H}),(0,w.jsxs)("div",{className:K.inputWrapper,onClick:F,children:[(0,w.jsxs)("div",{className:K.editorArea,children:[(0,w.jsxs)("div",{className:K.sizerContent,"aria-hidden":"true",children:[j&&W?(0,w.jsxs)("span",{className:K.placeholderText,children:[W," "]}):(0,w.jsxs)("span",{className:K.sizerText,children:[I.map((_,z)=>(0,w.jsx)("span",{children:_.value},`${z}-${_.type}`)),I.length===0&&"\xA0"]})," ",(0,w.jsx)(Me,{pills:u,activePillIndex:0,onSelectPill:P})]}),(0,w.jsx)("textarea",{ref:y,className:K.textarea,rows:1,onChange:U,...$})]}),(0,w.jsx)("button",{type:"button",className:K.submitButton,disabled:!B,onClick:_=>{_.stopPropagation(),M()},"aria-label":"Submit",children:(0,w.jsx)("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:(0,w.jsx)("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});0&&(module.exports={AIAutocomplete,AIAutocompleteDropdown,useAIAutocomplete});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/filtering.ts","../src/utils/segments.ts","../src/hooks/useAutocompleteFetch.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/hooks/useAutocompleteKeyboard.ts","../src/hooks/useAutocompletePills.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps, AutocompleteResult } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n },\n ref,\n ) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n // Render-phase ref assignment — matches the pattern in useAIAutocomplete.ts\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const checkmarkTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n textareaRef.current?.focus();\n return () => clearTimeout(checkmarkTimerRef.current);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => textareaRef.current?.focus(),\n reset,\n }),\n [reset],\n );\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n clearTimeout(checkmarkTimerRef.current);\n checkmarkTimerRef.current = setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg\n width=\"72\"\n height=\"72\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Success\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList pills={suggestionPills} activePillIndex={0} onSelectPill={setActivePill} />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n );\n },\n);\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--ac-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--ac-color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--ac-color-text-default, #fff);\n caret-color: var(--ac-color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--ac-color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--ac-color-text-default, #fff);\n color: var(--ac-color-bg-default, #000);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--ac-color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.visible {\n opacity: 1;\n pointer-events: auto;\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--ac-color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--ac-color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--ac-color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const hasOptions = isOpen && activeSuggestion && activeSuggestion.options.length > 0;\n\n return (\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${hasOptions ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeSuggestion && activeSuggestion.options.length > 0 && (\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n />\n )}\n </div>\n );\n}\n",".list {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--ac-color-background-supportive, #313255);\n color: var(--ac-color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n}\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { type ChangeEvent, useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { useAutocompleteFetch, useDebouncedFetch } from \"./useAutocompleteFetch\";\nimport { useAutocompleteKeyboard } from \"./useAutocompleteKeyboard\";\nimport { useAutocompletePills } from \"./useAutocompletePills\";\n\nlet idCounter = 0;\nfunction useStableId(): string {\n const id = useRef<string | null>(null);\n if (id.current === null) {\n id.current = `:ac-${++idCounter}:`;\n }\n return id.current;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n eagerSuggestions = true,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Controlled / uncontrolled state ===\n const isTextControlled = controlledValue !== undefined;\n const isParamsControlled = controlledParams !== undefined;\n\n const [internalText, setInternalText] = useState(\"\");\n const [internalCompletedParams, setInternalCompletedParams] = useState<CompletedParamState[]>([]);\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const text = isTextControlled ? controlledValue : internalText;\n const completedParams = isParamsControlled ? controlledParams : internalCompletedParams;\n\n // === Refs — must be before setText/setCompletedParams which read them ===\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const controlledValueRef = useRef(controlledValue);\n controlledValueRef.current = controlledValue;\n const controlledParamsRef = useRef(controlledParams);\n controlledParamsRef.current = controlledParams;\n\n // Stable setText that reads controlled value + callback via refs (no stale closures)\n const setText = useCallback(\n (value: string | ((prev: string) => string)) => {\n if (typeof value === \"function\") {\n if (isTextControlled) {\n const newVal = value(controlledValueRef.current ?? \"\");\n onChangeRef.current?.(newVal);\n } else {\n setInternalText((prev) => {\n const newVal = value(prev);\n onChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isTextControlled) setInternalText(value);\n onChangeRef.current?.(value);\n }\n },\n [isTextControlled],\n );\n\n // Stable setCompletedParams — same ref pattern\n const setCompletedParams = useCallback(\n (value: CompletedParamState[] | ((prev: CompletedParamState[]) => CompletedParamState[])) => {\n if (typeof value === \"function\") {\n if (isParamsControlled) {\n const newVal = value(controlledParamsRef.current ?? []);\n onParamsChangeRef.current?.(newVal);\n } else {\n setInternalCompletedParams((prev) => {\n const newVal = value(prev);\n onParamsChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isParamsControlled) setInternalCompletedParams(value);\n onParamsChangeRef.current?.(value);\n }\n },\n [isParamsControlled],\n );\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const apiConfigRef = useRef(apiConfig);\n apiConfigRef.current = apiConfig;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useStableId();\n\n // === Fetch ===\n const { doFetch, isLoading, error, isReady, lastRawQueryRef } = useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n });\n\n useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n });\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n\n const placeholderText = useMemo(() => {\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n return serverPlaceholder || customPlaceholder || \"\";\n }, [suggestions, customPlaceholder]);\n const actionableSuggestions = useMemo(\n () => suggestions.filter((s) => s.type !== \"placeholder\"),\n [suggestions],\n );\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = useMemo(\n () => filterOptions(baseOptions, filterQuery),\n [baseOptions, filterQuery],\n );\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Option selection ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n const base = filterBaseRef.current;\n let prefix = textRef.current.slice(0, base);\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (eagerSuggestions && remainingActionable > 0) {\n // Keep cached suggestions visible and skip the fetch\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n skipNextFetchRef.current = true;\n } else {\n // Clear all suggestions and let the debounced fetch bring fresh ones\n setSuggestions((prev) => prev.filter((s) => s.type === \"placeholder\"));\n }\n },\n [activeSuggestion, actionableSuggestions, eagerSuggestions, setText, setCompletedParams],\n );\n\n // === Text change handler ===\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(() => valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion, setText, setCompletedParams],\n );\n\n // === Keyboard ===\n const { handleKeyDown } = useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n });\n\n // === Pills ===\n const pills = useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n });\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n pills.reEditParam(param).apply(setText);\n },\n [pills, setText],\n );\n\n // === Reset ===\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams(() => []);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch, setText, setCompletedParams, lastRawQueryRef]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: pills.setActivePill,\n removeLastParam: pills.removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[],\n query: string,\n): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import { type MutableRefObject, useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { applyOptionOverrides } from \"../utils/overrides\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\ninterface UseAutocompleteFetchOptions {\n textRef: MutableRefObject<string>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n filterBaseRef: MutableRefObject<number>;\n maskCompletedTextRef: MutableRefObject<boolean | undefined>;\n apiConfigRef: MutableRefObject<APIConfig | undefined>;\n optionOverridesRef: MutableRefObject<OptionOverrides | undefined>;\n onErrorRef: MutableRefObject<((error: Error) => void) | undefined>;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n}\n\ninterface UseAutocompleteFetchReturn {\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n isReady: boolean;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n}: UseAutocompleteFetchOptions): UseAutocompleteFetchReturn {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n\n const doFetch = useCallback(\n async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n const textAtRequest = textRef.current.length;\n\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n apiConfig: apiConfigRef.current,\n });\n\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = textAtRequest;\n }\n } else {\n filterBaseRef.current = textAtRequest;\n }\n\n // Check if the user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n setError(caughtError);\n setIsLoading(false);\n onErrorRef.current?.(caughtError);\n }\n }\n },\n [\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n ],\n );\n\n // Mount fetch\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n return { doFetch, isLoading, error, isReady, lastRawQueryRef };\n}\n\ninterface UseDebouncedFetchOptions {\n text: string;\n completedParams: CompletedParamState[];\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n filterBaseRef: MutableRefObject<number>;\n skipNextFetchRef: MutableRefObject<boolean>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n}: UseDebouncedFetchOptions): void {\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n const attemptFetch = (minDiff: number): boolean => {\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s: Suggestion) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n ]);\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst API_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/api/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(config?: APIConfig): string {\n const key = config?.apiKey || process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(config?: APIConfig): \"Bearer\" | \"Basic\" {\n if (config?.authScheme) return config.authScheme;\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: {\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options?.apiConfig;\n const apiKey = getApiKey(apiConfig);\n const authScheme = getAuthScheme(apiConfig);\n const includeText = !options?.maskCompletedText;\n\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n ...apiConfig?.headers,\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(API_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import { type KeyboardEvent, type MutableRefObject, useCallback } from \"react\";\nimport type {\n AutocompleteResult,\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\ninterface UseAutocompleteKeyboardOptions {\n activeDropdownIndex: number;\n setActiveDropdownIndex: (index: number) => void;\n filteredOptions: SuggestionOption[];\n selectOption: (option: SuggestionOption) => void;\n onSubmitRef: MutableRefObject<((result: AutocompleteResult) => void) | undefined>;\n text: string;\n completedParams: CompletedParamState[];\n isDropdownOpen: boolean;\n hasPlaceholder: boolean;\n placeholderText: string;\n suggestions: Suggestion[];\n filterBaseRef: MutableRefObject<number>;\n columns: number;\n setText: (value: string) => void;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: (prev: Suggestion[]) => Suggestion[]) => void;\n}\n\nexport function useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n}: UseAutocompleteKeyboardOptions) {\n const getTappableIndices = useCallback(() => {\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n // Column-first ordering: all column-0 items, then column-1, etc.\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }, [filteredOptions, columns]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n const col = activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns > 0) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n const result: AutocompleteResult = {\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n };\n onSubmitRef.current(result);\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n } else {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n columns,\n completedParams,\n filteredOptions,\n filterBaseRef,\n getTappableIndices,\n hasPlaceholder,\n isDropdownOpen,\n onSubmitRef,\n placeholderText,\n selectOption,\n setActiveDropdownIndex,\n setCompletedParams,\n setSuggestions,\n setText,\n suggestions,\n text,\n ],\n );\n\n return { handleKeyDown, getTappableIndices };\n}\n","import { type MutableRefObject, useCallback } from \"react\";\nimport type { CompletedParamState, Suggestion } from \"../types\";\n\ninterface UseAutocompletePillsOptions {\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n filterBaseRef: MutableRefObject<number>;\n pillTappedRef: MutableRefObject<boolean>;\n}\n\nexport function useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n}: UseAutocompletePillsOptions) {\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions, setSuggestions, setActiveDropdownIndex, pillTappedRef],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams, setCompletedParams, setSuggestions, setActiveDropdownIndex]);\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n return {\n apply: (setText: (fn: (prev: string) => string) => void) => {\n setText((prev) => {\n let pos = 0;\n for (const p of completedParams) {\n const idx = prev.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === param.id) {\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n }\n pos = idx + p.text.length;\n }\n return prev;\n });\n setCompletedParams((prev) => prev.filter((p) => p.id !== param.id));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n },\n };\n },\n [\n completedParams,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n ],\n );\n\n return { setActivePill, removeLastParam, reEditParam };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","SuggestionItem","import_jsx_runtime","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","activeSuggestion","hasOptions","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","import_jsx_runtime","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","import_react","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","import_react","SDK_VERSION","API_ENDPOINT","hasWarnedMissingKey","getApiKey","config","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiConfig","apiKey","authScheme","rawCount","p","contactAccountCount","body","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","useAutocompleteFetch","textRef","suggestionsRef","filterBaseRef","maskCompletedTextRef","apiConfigRef","optionOverridesRef","onErrorRef","setCompletedParams","setSuggestions","setActiveDropdownIndex","isLoading","setIsLoading","error","setError","isReady","setIsReady","fetchVersionRef","abortRef","lastRawQueryRef","doFetch","rawQuery","completed","controller","version","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","inProgressIdx","active","query","match","findExactMatch","prev","err","caughtError","useDebouncedFetch","text","completedParams","skipNextFetchRef","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","import_react","useAutocompleteKeyboard","activeDropdownIndex","setActiveDropdownIndex","filteredOptions","selectOption","onSubmitRef","text","completedParams","isDropdownOpen","hasPlaceholder","placeholderText","suggestions","filterBaseRef","columns","setText","setCompletedParams","setSuggestions","getTappableIndices","tappable","o","i","buckets","e","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","result","firstTappable","placeholderSuggestion","s","prev","import_react","useAutocompletePills","completedParams","suggestions","setCompletedParams","setSuggestions","setActiveDropdownIndex","filterBaseRef","pillTappedRef","setActivePill","index","actionable","s","moved","rest","_","i","placeholders","removeLastParam","lastParam","restoredSuggestion","prev","reEditParam","param","setText","pos","p","idx","before","after","cleaned","idCounter","useStableId","id","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","eagerSuggestions","controlledValue","controlledParams","onChangeProp","onParamsChange","isTextControlled","isParamsControlled","internalText","setInternalText","internalCompletedParams","setInternalCompletedParams","suggestions","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","text","completedParams","onSubmitRef","onChangeRef","onParamsChangeRef","controlledValueRef","controlledParamsRef","setText","value","newVal","prev","setCompletedParams","onErrorRef","optionOverridesRef","maskCompletedTextRef","apiConfigRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","isLoading","error","isReady","lastRawQueryRef","useAutocompleteFetch","useDebouncedFetch","segments","deriveSegments","filterQuery","placeholderText","s","actionableSuggestions","activeSuggestion","overrideFn","baseOptions","filteredOptions","filterOptions","hasPlaceholder","isDropdownOpen","selectOption","option","completed","base","prefix","lastWord","needsSpace","newText","remainingActionable","handleChange","e","raw","newValue","valid","invalid","reconcileParams","param","newFilterQuery","match","findExactMatch","handleKeyDown","useAutocompleteKeyboard","pills","useAutocompletePills","reEditParam","reset","activeDescendantId","import_jsx_runtime","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","placeholder","className","apiConfig","columns","eagerSuggestions","value","controlledParams","onChangeProp","onParamsChange","ref","textareaRef","showCheckmark","setShowCheckmark","handleSubmitRef","checkmarkTimerRef","completedParams","suggestionPills","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","result","handleContainerClick","canSubmit","handleSubmit","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/filtering.ts","../src/utils/segments.ts","../src/hooks/useAutocompleteFetch.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/hooks/useAutocompleteKeyboard.ts","../src/hooks/useAutocompletePills.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps, AutocompleteResult } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n },\n ref,\n ) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n // Render-phase ref assignment — matches the pattern in useAIAutocomplete.ts\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const checkmarkTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n textareaRef.current?.focus();\n return () => clearTimeout(checkmarkTimerRef.current);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => textareaRef.current?.focus(),\n reset,\n }),\n [reset],\n );\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n clearTimeout(checkmarkTimerRef.current);\n checkmarkTimerRef.current = setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg\n width=\"72\"\n height=\"72\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Success\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList pills={suggestionPills} activePillIndex={0} onSelectPill={setActivePill} />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n );\n },\n);\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--ac-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--ac-color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--ac-color-text-default, #fff);\n caret-color: var(--ac-color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--ac-color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--ac-color-text-default, #fff);\n color: var(--ac-color-bg-default, #000);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--ac-color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.visible {\n opacity: 1;\n pointer-events: auto;\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--ac-color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--ac-color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--ac-color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const hasOptions = isOpen && activeSuggestion && activeSuggestion.options.length > 0;\n\n return (\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${hasOptions ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeSuggestion && activeSuggestion.options.length > 0 && (\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n />\n )}\n </div>\n );\n}\n",".list {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--ac-color-background-supportive, #313255);\n color: var(--ac-color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n}\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { type ChangeEvent, useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { useAutocompleteFetch, useDebouncedFetch } from \"./useAutocompleteFetch\";\nimport { useAutocompleteKeyboard } from \"./useAutocompleteKeyboard\";\nimport { useAutocompletePills } from \"./useAutocompletePills\";\n\nlet idCounter = 0;\nfunction useStableId(): string {\n const id = useRef<string | null>(null);\n if (id.current === null) {\n id.current = `:ac-${++idCounter}:`;\n }\n return id.current;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n eagerSuggestions = true,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Controlled / uncontrolled state ===\n const isTextControlled = controlledValue !== undefined;\n const isParamsControlled = controlledParams !== undefined;\n\n const [internalText, setInternalText] = useState(\"\");\n const [internalCompletedParams, setInternalCompletedParams] = useState<CompletedParamState[]>([]);\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const text = isTextControlled ? controlledValue : internalText;\n const completedParams = isParamsControlled ? controlledParams : internalCompletedParams;\n\n // === Refs — must be before setText/setCompletedParams which read them ===\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const controlledValueRef = useRef(controlledValue);\n controlledValueRef.current = controlledValue;\n const controlledParamsRef = useRef(controlledParams);\n controlledParamsRef.current = controlledParams;\n\n // Stable setText that reads controlled value + callback via refs (no stale closures)\n const setText = useCallback(\n (value: string | ((prev: string) => string)) => {\n if (typeof value === \"function\") {\n if (isTextControlled) {\n const newVal = value(controlledValueRef.current ?? \"\");\n onChangeRef.current?.(newVal);\n } else {\n setInternalText((prev) => {\n const newVal = value(prev);\n onChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isTextControlled) setInternalText(value);\n onChangeRef.current?.(value);\n }\n },\n [isTextControlled],\n );\n\n // Stable setCompletedParams — same ref pattern\n const setCompletedParams = useCallback(\n (value: CompletedParamState[] | ((prev: CompletedParamState[]) => CompletedParamState[])) => {\n if (typeof value === \"function\") {\n if (isParamsControlled) {\n const newVal = value(controlledParamsRef.current ?? []);\n onParamsChangeRef.current?.(newVal);\n } else {\n setInternalCompletedParams((prev) => {\n const newVal = value(prev);\n onParamsChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isParamsControlled) setInternalCompletedParams(value);\n onParamsChangeRef.current?.(value);\n }\n },\n [isParamsControlled],\n );\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const apiConfigRef = useRef(apiConfig);\n apiConfigRef.current = apiConfig;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useStableId();\n\n // === Fetch ===\n const { doFetch, isLoading, error, isReady, lastRawQueryRef } = useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n });\n\n useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n });\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n\n const placeholderText = useMemo(() => {\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n return serverPlaceholder || customPlaceholder || \"\";\n }, [suggestions, customPlaceholder]);\n const actionableSuggestions = useMemo(\n () => suggestions.filter((s) => s.type !== \"placeholder\"),\n [suggestions],\n );\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = useMemo(\n () => filterOptions(baseOptions, filterQuery),\n [baseOptions, filterQuery],\n );\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Option selection ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n const base = filterBaseRef.current;\n let prefix = textRef.current.slice(0, base);\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (eagerSuggestions && remainingActionable > 0) {\n // Keep cached suggestions visible and skip the fetch\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n skipNextFetchRef.current = true;\n } else {\n // Clear all suggestions and let the debounced fetch bring fresh ones\n setSuggestions((prev) => prev.filter((s) => s.type === \"placeholder\"));\n }\n },\n [activeSuggestion, actionableSuggestions, eagerSuggestions, setText, setCompletedParams],\n );\n\n // === Text change handler ===\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(() => valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion, setText, setCompletedParams],\n );\n\n // === Keyboard ===\n const { handleKeyDown } = useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n });\n\n // === Pills ===\n const pills = useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n });\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n pills.reEditParam(param).apply(setText);\n },\n [pills, setText],\n );\n\n // === Reset ===\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams(() => []);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch, setText, setCompletedParams, lastRawQueryRef]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: pills.setActivePill,\n removeLastParam: pills.removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[],\n query: string,\n): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import { type MutableRefObject, useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { applyOptionOverrides } from \"../utils/overrides\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\ninterface UseAutocompleteFetchOptions {\n textRef: MutableRefObject<string>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n filterBaseRef: MutableRefObject<number>;\n maskCompletedTextRef: MutableRefObject<boolean | undefined>;\n apiConfigRef: MutableRefObject<APIConfig | undefined>;\n optionOverridesRef: MutableRefObject<OptionOverrides | undefined>;\n onErrorRef: MutableRefObject<((error: Error) => void) | undefined>;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n}\n\ninterface UseAutocompleteFetchReturn {\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n isReady: boolean;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n}: UseAutocompleteFetchOptions): UseAutocompleteFetchReturn {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n\n const doFetch = useCallback(\n async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n const textAtRequest = textRef.current.length;\n\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n apiConfig: apiConfigRef.current,\n });\n\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = textAtRequest;\n }\n } else {\n filterBaseRef.current = textAtRequest;\n }\n\n // Check if the user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n setError(caughtError);\n setIsLoading(false);\n onErrorRef.current?.(caughtError);\n }\n }\n },\n [\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n ],\n );\n\n // Mount fetch\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n return { doFetch, isLoading, error, isReady, lastRawQueryRef };\n}\n\ninterface UseDebouncedFetchOptions {\n text: string;\n completedParams: CompletedParamState[];\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n filterBaseRef: MutableRefObject<number>;\n skipNextFetchRef: MutableRefObject<boolean>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n}: UseDebouncedFetchOptions): void {\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n const attemptFetch = (minDiff: number): boolean => {\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s: Suggestion) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n ]);\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst DEFAULT_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/ac/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(config?: APIConfig): string {\n const key = config?.apiKey || process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(config?: APIConfig): \"Bearer\" | \"Basic\" {\n if (config?.authScheme) return config.authScheme;\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: {\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options?.apiConfig;\n const apiKey = getApiKey(apiConfig);\n const authScheme = getAuthScheme(apiConfig);\n const includeText = !options?.maskCompletedText;\n\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n ...apiConfig?.headers,\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(apiConfig?.endpoint || DEFAULT_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import { type KeyboardEvent, type MutableRefObject, useCallback } from \"react\";\nimport type {\n AutocompleteResult,\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\ninterface UseAutocompleteKeyboardOptions {\n activeDropdownIndex: number;\n setActiveDropdownIndex: (index: number) => void;\n filteredOptions: SuggestionOption[];\n selectOption: (option: SuggestionOption) => void;\n onSubmitRef: MutableRefObject<((result: AutocompleteResult) => void) | undefined>;\n text: string;\n completedParams: CompletedParamState[];\n isDropdownOpen: boolean;\n hasPlaceholder: boolean;\n placeholderText: string;\n suggestions: Suggestion[];\n filterBaseRef: MutableRefObject<number>;\n columns: number;\n setText: (value: string) => void;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: (prev: Suggestion[]) => Suggestion[]) => void;\n}\n\nexport function useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n}: UseAutocompleteKeyboardOptions) {\n const getTappableIndices = useCallback(() => {\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n // Column-first ordering: all column-0 items, then column-1, etc.\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }, [filteredOptions, columns]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n const col = activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns > 0) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n const result: AutocompleteResult = {\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n };\n onSubmitRef.current(result);\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n } else {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n columns,\n completedParams,\n filteredOptions,\n filterBaseRef,\n getTappableIndices,\n hasPlaceholder,\n isDropdownOpen,\n onSubmitRef,\n placeholderText,\n selectOption,\n setActiveDropdownIndex,\n setCompletedParams,\n setSuggestions,\n setText,\n suggestions,\n text,\n ],\n );\n\n return { handleKeyDown, getTappableIndices };\n}\n","import { type MutableRefObject, useCallback } from \"react\";\nimport type { CompletedParamState, Suggestion } from \"../types\";\n\ninterface UseAutocompletePillsOptions {\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n filterBaseRef: MutableRefObject<number>;\n pillTappedRef: MutableRefObject<boolean>;\n}\n\nexport function useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n}: UseAutocompletePillsOptions) {\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions, setSuggestions, setActiveDropdownIndex, pillTappedRef],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams, setCompletedParams, setSuggestions, setActiveDropdownIndex]);\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n return {\n apply: (setText: (fn: (prev: string) => string) => void) => {\n setText((prev) => {\n let pos = 0;\n for (const p of completedParams) {\n const idx = prev.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === param.id) {\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n }\n pos = idx + p.text.length;\n }\n return prev;\n });\n setCompletedParams((prev) => prev.filter((p) => p.id !== param.id));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n },\n };\n },\n [\n completedParams,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n ],\n );\n\n return { setActivePill, removeLastParam, reEditParam };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","SuggestionItem","import_jsx_runtime","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","activeSuggestion","hasOptions","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","import_jsx_runtime","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","import_react","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","import_react","SDK_VERSION","DEFAULT_ENDPOINT","hasWarnedMissingKey","getApiKey","config","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiConfig","apiKey","authScheme","rawCount","p","contactAccountCount","body","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","useAutocompleteFetch","textRef","suggestionsRef","filterBaseRef","maskCompletedTextRef","apiConfigRef","optionOverridesRef","onErrorRef","setCompletedParams","setSuggestions","setActiveDropdownIndex","isLoading","setIsLoading","error","setError","isReady","setIsReady","fetchVersionRef","abortRef","lastRawQueryRef","doFetch","rawQuery","completed","controller","version","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","inProgressIdx","active","query","match","findExactMatch","prev","err","caughtError","useDebouncedFetch","text","completedParams","skipNextFetchRef","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","import_react","useAutocompleteKeyboard","activeDropdownIndex","setActiveDropdownIndex","filteredOptions","selectOption","onSubmitRef","text","completedParams","isDropdownOpen","hasPlaceholder","placeholderText","suggestions","filterBaseRef","columns","setText","setCompletedParams","setSuggestions","getTappableIndices","tappable","o","i","buckets","e","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","result","firstTappable","placeholderSuggestion","s","prev","import_react","useAutocompletePills","completedParams","suggestions","setCompletedParams","setSuggestions","setActiveDropdownIndex","filterBaseRef","pillTappedRef","setActivePill","index","actionable","s","moved","rest","_","i","placeholders","removeLastParam","lastParam","restoredSuggestion","prev","reEditParam","param","setText","pos","p","idx","before","after","cleaned","idCounter","useStableId","id","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","eagerSuggestions","controlledValue","controlledParams","onChangeProp","onParamsChange","isTextControlled","isParamsControlled","internalText","setInternalText","internalCompletedParams","setInternalCompletedParams","suggestions","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","text","completedParams","onSubmitRef","onChangeRef","onParamsChangeRef","controlledValueRef","controlledParamsRef","setText","value","newVal","prev","setCompletedParams","onErrorRef","optionOverridesRef","maskCompletedTextRef","apiConfigRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","isLoading","error","isReady","lastRawQueryRef","useAutocompleteFetch","useDebouncedFetch","segments","deriveSegments","filterQuery","placeholderText","s","actionableSuggestions","activeSuggestion","overrideFn","baseOptions","filteredOptions","filterOptions","hasPlaceholder","isDropdownOpen","selectOption","option","completed","base","prefix","lastWord","needsSpace","newText","remainingActionable","handleChange","e","raw","newValue","valid","invalid","reconcileParams","param","newFilterQuery","match","findExactMatch","handleKeyDown","useAutocompleteKeyboard","pills","useAutocompletePills","reEditParam","reset","activeDescendantId","import_jsx_runtime","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","placeholder","className","apiConfig","columns","eagerSuggestions","value","controlledParams","onChangeProp","onParamsChange","ref","textareaRef","showCheckmark","setShowCheckmark","handleSubmitRef","checkmarkTimerRef","completedParams","suggestionPills","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","result","handleContainerClick","canSubmit","handleSubmit","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{forwardRef as vt,useCallback as At,useEffect as Ct,useImperativeHandle as kt,useRef as ve,useState as wt}from"react";var D={};var be={};var Re={};var G={};import{jsx as st,jsxs as it}from"react/jsx-runtime";function _e({option:e,isHighlighted:n,onSelect:t,onHighlight:o,id:r}){let a=[G.item,n?G.highlighted:"",e.is_tappable?G.tappable:G.nonTappable].filter(Boolean).join(" ");return it("div",{id:r,role:"option","aria-selected":n,className:a,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&t(e),onKeyDown:i=>{e.is_tappable&&(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),t(e))},onMouseEnter:o,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&st("span",{className:G.tag,children:e.tag})]})}import{jsx as Te}from"react/jsx-runtime";function Me({options:e,activeIndex:n,onSelect:t,onHighlight:o,listboxId:r}){return Te("div",{className:Re.grid,children:e.map((a,i)=>Te(_e,{option:a,isHighlighted:i===n,onSelect:t,onHighlight:()=>o(i),id:`${r}-option-${i}`},a.text))})}import{jsx as Ee}from"react/jsx-runtime";function ye({suggestions:e,activeIndex:n,onSelect:t,onHighlight:o,isOpen:r,id:a,className:i}){let p=e[0],f=r&&p&&p.options.length>0;return Ee("div",{id:a,role:"listbox",className:`${be.dropdown} ${f?be.visible:""} ${i??""}`,onMouseDown:g=>g.preventDefault(),children:p&&p.options.length>0&&Ee(Me,{options:p.options,activeIndex:n,onSelect:t,onHighlight:o,listboxId:a})})}var ne={};import{jsx as Ue}from"react/jsx-runtime";function lt(e){return e===0?.4:e===1?.3:.15}function Le({pills:e,activePillIndex:n,onSelectPill:t}){return Ue("span",{className:ne.list,children:e.map((o,r)=>Ue("button",{type:"button",className:`${ne.pill} ${r===n?ne.active:""}`,style:{opacity:lt(r)},onClick:()=>t(r),children:o.text},`${o.type}-${o.text}`))})}import{useCallback as Z,useMemo as se,useRef as M,useState as ie}from"react";function ae(e,n){let t=n.trimStart();if(!t)return e;let o=t.toLowerCase();return e.filter(r=>!r.is_tappable||r.text.toLowerCase().includes(o))}function ee(e,n){let t=n.trim();if(!t)return null;let o=t.toLowerCase();return e.find(r=>r.is_tappable&&r.text.toLowerCase()===o)??null}function Ne(e,n){let t=[],o=0;for(let a of n){let i=e.indexOf(a.text,o);i!==-1&&(i>o&&t.push({type:"text",value:e.slice(o,i)}),t.push({type:"completed",value:a.text,param:a}),o=i+a.text.length)}let r=e.slice(o);return r&&t.push({type:"text",value:r}),t}function De(e,n){let t=[],o=[],r=0;for(let a of n){let i=e.indexOf(a.text,r);i===-1?o.push(a):(t.push(a),r=i+a.text.length)}return{valid:t,invalid:o}}import{useCallback as ht,useEffect as je,useRef as J,useState as Se}from"react";var ut="0.1.6",pt=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",$e=!1;function mt(e){let n=e?.apiKey||process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!n&&!$e&&($e=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),n}function dt(e){return e?.authScheme?e.authScheme:process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function ft(){return crypto.randomUUID()}function gt(e,n){return{placeholder:e.placeholder,type:e.type,...n&&{text:e.text},kind:e.kind}}async function Fe(e,n,t){let o=t?.apiConfig,r=mt(o),a=dt(o),i=!t?.maskCompletedText,p=n.find(c=>c.type==="contact"&&c.metadata?.contact_account_count)?.metadata?.contact_account_count,f=typeof p=="number"?p:void 0,g={data:{raw_query:e,completed_params:n.map(c=>gt(c,i)),...f!=null&&{contact_account_count:f}},meta:{request_id:ft(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:ut}},m={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo",...o?.headers};r&&(m.Authorization=a==="Basic"?`Basic ${btoa(r)}`:`Bearer ${r}`);let h=await fetch(pt,{method:"POST",headers:m,body:JSON.stringify(g),signal:t?.signal});if(!h.ok)throw new Error(`API error: ${h.status} ${h.statusText}`);return h.json()}function Y(e,n){let t=e,o={},r=[];for(let a of n){let i=(o[a.type]??0)+1;o[a.type]=i;let f=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,g=t.indexOf(a.text);g!==-1&&(t=t.slice(0,g)+f+t.slice(g+a.text.length)),r.push({...a,placeholder:f})}return{rawQuery:t,completedParams:r}}function Ke(e,n){return n?e.map(t=>{let o=n[t.type];if(!o)return t;let r=o("");if(r.length===0)return t;let a=new Set(r.map(p=>p.text)),i=(t.options??[]).filter(p=>!a.has(p.text));return{...t,options:[...r,...i]}}):e}var bt=100,yt=300,St=2;function ze({textRef:e,suggestionsRef:n,filterBaseRef:t,maskCompletedTextRef:o,apiConfigRef:r,optionOverridesRef:a,onErrorRef:i,setCompletedParams:p,setSuggestions:f,setActiveDropdownIndex:g}){let[m,h]=Se(!1),[c,y]=Se(null),[k,b]=Se(!1),A=J(0),E=J(null),d=J(""),l=ht(async(s,u)=>{E.current?.abort();let x=new AbortController;E.current=x;let w=++A.current,O=e.current.length;n.current.some(C=>C.type!=="placeholder")||h(!0),y(null);try{let C=await Fe(s,u,{maskCompletedText:o.current,signal:x.signal,apiConfig:r.current});if(w!==A.current)return;let L=Ke(C.data.suggestions??[],a.current);b(C.data.is_ready??!1),d.current=s;let z=C.data.input??[],_=z[z.length-1],T=e.current;if(_?.state==="in_progress"){let $=T.toLowerCase().lastIndexOf(_.text.toLowerCase());$!==-1?t.current=$:t.current=O}else t.current=O;let N=L.filter($=>$.type!=="placeholder")[0];if(N){let $=T.slice(t.current),I=ee(N.options,$);I&&(p(F=>[...F,{id:crypto.randomUUID(),placeholder:"",type:N.type,text:I.text,kind:I.kind,suggestionType:N.type,suggestionPlaceholder:N.text,options:N.options,metadata:I.metadata}]),L=L.filter(F=>F!==N))}f(L),h(!1),g(-1)}catch(C){if(w===A.current){let L=C instanceof Error?C:new Error(String(C));y(L),h(!1),i.current?.(L)}}},[e,n,t,o,r,a,i,p,f,g]);return je(()=>(l("",[]),()=>{E.current?.abort()}),[l]),{doFetch:l,isLoading:m,error:c,isReady:k,lastRawQueryRef:d}}function qe({text:e,completedParams:n,doFetch:t,filterBaseRef:o,skipNextFetchRef:r,suggestionsRef:a,lastRawQueryRef:i}){let p=J(null),f=J(null),g=J(!0);je(()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current);let m=h=>{if(r.current)return r.current=!1,!1;if(!e&&n.length===0)return g.current?(t("",[]),!0):(g.current=!0,!1);let c=e.slice(o.current),b=a.current.filter(O=>O.type!=="placeholder")[0],E=(b?ae(b.options,c):[]).filter(O=>O.is_tappable),d=b?ee(b.options,c)!==null:!1,l=c.trim().length>0;if(E.length>0&&!d&&l)return!1;let{rawQuery:s,completedParams:u}=Y(e,n),x=s.length<i.current.length,w=Math.abs(s.length-i.current.length);return x||w>=h?(t(s,u),!0):!1};return p.current=setTimeout(()=>{m(St)&&f.current&&clearTimeout(f.current)},bt),f.current=setTimeout(()=>m(1),yt),()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current)}},[e,n,t,o,r,a,i])}import{useCallback as Be}from"react";function Qe({activeDropdownIndex:e,setActiveDropdownIndex:n,filteredOptions:t,selectOption:o,onSubmitRef:r,text:a,completedParams:i,isDropdownOpen:p,hasPlaceholder:f,placeholderText:g,suggestions:m,filterBaseRef:h,columns:c,setText:y,setCompletedParams:k,setSuggestions:b}){let A=Be(()=>{let d=t.map((s,u)=>s.is_tappable?u:-1).filter(s=>s!==-1),l=Array.from({length:c},()=>[]);for(let s of d)l[s%c].push(s);return l.flat()},[t,c]);return{handleKeyDown:Be(d=>{let l=A();switch(d.key){case"ArrowDown":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s<l.length-1?s+1:0;n(l[u]);break}case"ArrowUp":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s>0?s-1:l.length-1;n(l[u]);break}case"ArrowRight":{if(e<0)break;if(e%c<c-1){let u=e+1;u<t.length&&t[u]?.is_tappable&&(d.preventDefault(),n(u))}break}case"ArrowLeft":{if(e<0)break;if(e%c>0){let s=e-1;s>=0&&t[s]?.is_tappable&&(d.preventDefault(),n(s))}break}case"Enter":{if(d.preventDefault(),e>=0&&t[e]?.is_tappable)o(t[e]);else if(r.current){let{rawQuery:s,completedParams:u}=Y(a,i),x={query:a.trim(),raw_query:s,completed_params:u};r.current(x)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)d.preventDefault(),o(t[e]);else if(p){let s=t.find(u=>u.is_tappable);s&&(d.preventDefault(),o(s))}else if(!a&&f){d.preventDefault();let s=m.find(u=>u.type==="placeholder");s?(y(g),h.current=g.length,k(u=>[...u,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:g,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),b(u=>u.filter(x=>x!==s))):(y(g),h.current=g.length)}break}case"Escape":n(-1);break}},[e,c,i,t,h,A,f,p,r,g,o,n,k,b,y,m,a]),getTappableIndices:A}}import{useCallback as xe}from"react";function He({completedParams:e,suggestions:n,setCompletedParams:t,setSuggestions:o,setActiveDropdownIndex:r,filterBaseRef:a,pillTappedRef:i}){let p=xe(m=>{let h=n.filter(b=>b.type!=="placeholder");if(m<0||m>=h.length)return;let c=h[m],y=h.filter((b,A)=>A!==m),k=n.filter(b=>b.type==="placeholder");o([...k,c,...y]),i.current=!0,r(-1)},[n,o,r,i]),f=xe(()=>{if(e.length===0)return;let m=e[e.length-1],h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};t(c=>c.slice(0,-1)),o(c=>[h,...c]),r(-1)},[e,t,o,r]),g=xe(m=>{let h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};return{apply:c=>{c(y=>{let k=0;for(let b of e){let A=y.indexOf(b.text,k);if(A!==-1){if(b.id===m.id){let E=y.slice(0,A),d=y.slice(A+m.text.length),l=(E+d).replace(/ {2,}/g," ");return a.current=Math.min(a.current,l.length),l}k=A+b.text.length}}return y}),t(y=>y.filter(k=>k.id!==m.id)),o(y=>[h,...y]),r(-1),i.current=!0}}},[e,t,o,r,a,i]);return{setActivePill:p,removeLastParam:f,reEditParam:g}}var xt=0;function Pt(){let e=M(null);return e.current===null&&(e.current=`:ac-${++xt}:`),e.current}function Pe({onSubmit:e,onError:n,optionOverrides:t,maskCompletedText:o,placeholder:r,apiConfig:a,columns:i=2,eagerSuggestions:p=!0,value:f,completedParams:g,onChange:m,onParamsChange:h}){let c=f!==void 0,y=g!==void 0,[k,b]=ie(""),[A,E]=ie([]),[d,l]=ie([]),[s,u]=ie(-1),x=c?f:k,w=y?g:A,O=M(e);O.current=e;let B=M(m);B.current=m;let C=M(h);C.current=h;let L=M(f);L.current=f;let z=M(g);z.current=g;let _=Z(S=>{if(typeof S=="function")if(c){let v=S(L.current??"");B.current?.(v)}else b(v=>{let q=S(v);return B.current?.(q),q});else c||b(S),B.current?.(S)},[c]),T=Z(S=>{if(typeof S=="function")if(y){let v=S(z.current??[]);C.current?.(v)}else E(v=>{let q=S(v);return C.current?.(q),q});else y||E(S),C.current?.(S)},[y]),X=M(n);X.current=n;let N=M(t);N.current=t;let $=M(o);$.current=o;let I=M(a);I.current=a;let F=M(x);F.current=x;let ce=M(d);ce.current=d;let K=M(0),te=M(!1),Ae=M(!1),le=Pt(),{doFetch:ue,isLoading:Ce,error:Ve,isReady:Xe,lastRawQueryRef:pe}=ze({textRef:F,suggestionsRef:ce,filterBaseRef:K,maskCompletedTextRef:$,apiConfigRef:I,optionOverridesRef:N,onErrorRef:X,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u});qe({text:x,completedParams:w,doFetch:ue,filterBaseRef:K,skipNextFetchRef:Ae,suggestionsRef:ce,lastRawQueryRef:pe});let We=se(()=>Ne(x,w),[x,w]);K.current=Math.min(K.current,x.length);let me=x.slice(K.current),de=se(()=>d.filter(v=>v.type==="placeholder").map(v=>v.text).join(" ")||r||"",[d,r]),oe=se(()=>d.filter(S=>S.type!=="placeholder"),[d]),P=oe[0],ke=P?t?.[P.type]:void 0,we=P?ke?ke(me.trim()):P.options??[]:[],fe=se(()=>ae(we,me),[we,me]),Oe=de.length>0,ge=!Ce&&fe.length>0&&(!!x||te.current||!Oe),Ie=Z(S=>{if(!P)return;let v={id:crypto.randomUUID(),placeholder:"",type:P.type,text:S.text,kind:S.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:S.metadata},q=K.current,U=F.current.slice(0,q);if(U.length>0&&!U.endsWith(" ")){let R=U.split(/\s+/).pop()??"";R&&S.text.toLowerCase().startsWith(R.toLowerCase())&&(U=U.slice(0,U.length-R.length))}let he=U.length>0&&U[U.length-1]!==" ",W=U+(he?" ":"")+S.text+" ";_(W),K.current=W.length,T(R=>[...R,v]),te.current=!1,u(-1);let Q=oe.length-1;p&&Q>0?(l(R=>R.filter(H=>H!==P)),Ae.current=!0):l(R=>R.filter(H=>H.type==="placeholder"))},[P,oe,p,_,T]),Ge=Z(S=>{let v=S.target.value,U=v.length>0&&!S.nativeEvent?.isComposing&&v[0]!==v[0].toUpperCase()?v[0].toUpperCase()+v.slice(1):v;_(U),te.current=!1,u(-1);let{valid:he,invalid:W}=De(U,w);if(W.length>0){T(()=>he);for(let Q of W)l(R=>[{type:Q.suggestionType,text:Q.suggestionPlaceholder,required:!0,options:Q.options},...R])}if(P&&W.length===0){let Q=U.slice(K.current),R=ee(P.options,Q);R&&(T(H=>[...H,{id:crypto.randomUUID(),placeholder:"",type:P.type,text:R.text,kind:R.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:R.metadata}]),l(H=>H.filter(tt=>tt!==P)))}},[w,P,_,T]),{handleKeyDown:Ye}=Qe({activeDropdownIndex:s,setActiveDropdownIndex:u,filteredOptions:fe,selectOption:Ie,onSubmitRef:O,text:x,completedParams:w,isDropdownOpen:ge,hasPlaceholder:Oe,placeholderText:de,suggestions:d,filterBaseRef:K,columns:i,setText:_,setCompletedParams:T,setSuggestions:l}),re=He({completedParams:w,suggestions:d,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u,filterBaseRef:K,pillTappedRef:te}),Je=Z(S=>{re.reEditParam(S).apply(_)},[re,_]),Ze=Z(()=>{_(""),T(()=>[]),l([]),u(-1),K.current=0,pe.current="",ue("",[])},[ue,_,T,pe]),et=s>=0?`${le}-option-${s}`:void 0;return{completedParams:w,suggestionPills:oe,setActivePill:re.setActivePill,removeLastParam:re.removeLastParam,reEditParam:Je,segments:We,suggestions:d,activeIndex:s,isReady:Xe,isLoading:Ce,error:Ve,inputProps:{value:x,placeholder:de||void 0,onChange:Ge,onKeyDown:Ye,role:"combobox","aria-expanded":ge,"aria-activedescendant":et,"aria-autocomplete":"list","aria-controls":le},reset:Ze,dropdownProps:{suggestions:P?[{...P,options:fe}]:[],activeIndex:s,onSelect:Ie,onHighlight:u,isOpen:ge,id:le}}}import{jsx as j,jsxs as V}from"react/jsx-runtime";var Ot=vt(function({onSubmit:n,onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,className:i,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y},k){let b=ve(null),[A,E]=wt(!1),d=ve(()=>{}),l=ve(void 0);Ct(()=>(b.current?.focus(),()=>clearTimeout(l.current)),[]);let{completedParams:s,suggestionPills:u,setActivePill:x,segments:w,inputProps:O,dropdownProps:B,reset:C}=Pe({onSubmit:I=>d.current(I),onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y});kt(k,()=>({focus:()=>b.current?.focus(),reset:C}),[C]);let L=()=>{b.current?.focus()},z=!!O.value||s.length>0,_=At(()=>{if(!z)return;let{rawQuery:I,completedParams:F}=Y(O.value,s);n({query:O.value.trim(),raw_query:I,completed_params:F}),C(),E(!0),clearTimeout(l.current),l.current=setTimeout(()=>E(!1),3e3)},[z,O.value,s,n,C]);d.current=_;let{onChange:T,placeholder:X,...N}=O,$=!O.value;return V("div",{className:`${D.container} ${i??""}`,children:[j("div",{className:`${D.checkmark} ${A?D.checkmarkVisible:""}`,children:V("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[j("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),j("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:D.checkmarkPath})]})}),j(ye,{...B}),V("div",{className:D.inputWrapper,onClick:L,children:[V("div",{className:D.editorArea,children:[V("div",{className:D.sizerContent,"aria-hidden":"true",children:[$&&X?V("span",{className:D.placeholderText,children:[X," "]}):V("span",{className:D.sizerText,children:[w.map((I,F)=>j("span",{children:I.value},`${F}-${I.type}`)),w.length===0&&"\xA0"]})," ",j(Le,{pills:u,activePillIndex:0,onSelectPill:x})]}),j("textarea",{ref:b,className:D.textarea,rows:1,onChange:T,...N})]}),j("button",{type:"button",className:D.submitButton,disabled:!z,onClick:I=>{I.stopPropagation(),_()},"aria-label":"Submit",children:j("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:j("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});export{Ot as AIAutocomplete,ye as AIAutocompleteDropdown,Pe as useAIAutocomplete};
|
|
1
|
+
import{forwardRef as vt,useCallback as At,useEffect as Ct,useImperativeHandle as kt,useRef as ve,useState as wt}from"react";var D={};var be={};var Re={};var G={};import{jsx as st,jsxs as it}from"react/jsx-runtime";function _e({option:e,isHighlighted:n,onSelect:t,onHighlight:o,id:r}){let a=[G.item,n?G.highlighted:"",e.is_tappable?G.tappable:G.nonTappable].filter(Boolean).join(" ");return it("div",{id:r,role:"option","aria-selected":n,className:a,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&t(e),onKeyDown:i=>{e.is_tappable&&(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),t(e))},onMouseEnter:o,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&st("span",{className:G.tag,children:e.tag})]})}import{jsx as Te}from"react/jsx-runtime";function Ee({options:e,activeIndex:n,onSelect:t,onHighlight:o,listboxId:r}){return Te("div",{className:Re.grid,children:e.map((a,i)=>Te(_e,{option:a,isHighlighted:i===n,onSelect:t,onHighlight:()=>o(i),id:`${r}-option-${i}`},a.text))})}import{jsx as Me}from"react/jsx-runtime";function ye({suggestions:e,activeIndex:n,onSelect:t,onHighlight:o,isOpen:r,id:a,className:i}){let p=e[0],f=r&&p&&p.options.length>0;return Me("div",{id:a,role:"listbox",className:`${be.dropdown} ${f?be.visible:""} ${i??""}`,onMouseDown:g=>g.preventDefault(),children:p&&p.options.length>0&&Me(Ee,{options:p.options,activeIndex:n,onSelect:t,onHighlight:o,listboxId:a})})}var ne={};import{jsx as Ue}from"react/jsx-runtime";function lt(e){return e===0?.4:e===1?.3:.15}function Le({pills:e,activePillIndex:n,onSelectPill:t}){return Ue("span",{className:ne.list,children:e.map((o,r)=>Ue("button",{type:"button",className:`${ne.pill} ${r===n?ne.active:""}`,style:{opacity:lt(r)},onClick:()=>t(r),children:o.text},`${o.type}-${o.text}`))})}import{useCallback as Z,useMemo as se,useRef as E,useState as ie}from"react";function ae(e,n){let t=n.trimStart();if(!t)return e;let o=t.toLowerCase();return e.filter(r=>!r.is_tappable||r.text.toLowerCase().includes(o))}function ee(e,n){let t=n.trim();if(!t)return null;let o=t.toLowerCase();return e.find(r=>r.is_tappable&&r.text.toLowerCase()===o)??null}function Ne(e,n){let t=[],o=0;for(let a of n){let i=e.indexOf(a.text,o);i!==-1&&(i>o&&t.push({type:"text",value:e.slice(o,i)}),t.push({type:"completed",value:a.text,param:a}),o=i+a.text.length)}let r=e.slice(o);return r&&t.push({type:"text",value:r}),t}function De(e,n){let t=[],o=[],r=0;for(let a of n){let i=e.indexOf(a.text,r);i===-1?o.push(a):(t.push(a),r=i+a.text.length)}return{valid:t,invalid:o}}import{useCallback as ht,useEffect as je,useRef as J,useState as Se}from"react";var ut="0.1.7",pt="/ac/suggest",Fe=!1;function mt(e){let n=e?.apiKey||""||"";return!n&&!Fe&&(Fe=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),n}function dt(e){return e?.authScheme?e.authScheme:""==="Basic"?"Basic":"Bearer"}function ft(){return crypto.randomUUID()}function gt(e,n){return{placeholder:e.placeholder,type:e.type,...n&&{text:e.text},kind:e.kind}}async function $e(e,n,t){let o=t?.apiConfig,r=mt(o),a=dt(o),i=!t?.maskCompletedText,p=n.find(c=>c.type==="contact"&&c.metadata?.contact_account_count)?.metadata?.contact_account_count,f=typeof p=="number"?p:void 0,g={data:{raw_query:e,completed_params:n.map(c=>gt(c,i)),...f!=null&&{contact_account_count:f}},meta:{request_id:ft(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:ut}},m={"Content-Type":"application/json","X-App-Identifier":"active-campaign-demo",...o?.headers};r&&(m.Authorization=a==="Basic"?`Basic ${btoa(r)}`:`Bearer ${r}`);let h=await fetch(o?.endpoint||pt,{method:"POST",headers:m,body:JSON.stringify(g),signal:t?.signal});if(!h.ok)throw new Error(`API error: ${h.status} ${h.statusText}`);return h.json()}function Y(e,n){let t=e,o={},r=[];for(let a of n){let i=(o[a.type]??0)+1;o[a.type]=i;let f=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,g=t.indexOf(a.text);g!==-1&&(t=t.slice(0,g)+f+t.slice(g+a.text.length)),r.push({...a,placeholder:f})}return{rawQuery:t,completedParams:r}}function Ke(e,n){return n?e.map(t=>{let o=n[t.type];if(!o)return t;let r=o("");if(r.length===0)return t;let a=new Set(r.map(p=>p.text)),i=(t.options??[]).filter(p=>!a.has(p.text));return{...t,options:[...r,...i]}}):e}var bt=100,yt=300,St=2;function ze({textRef:e,suggestionsRef:n,filterBaseRef:t,maskCompletedTextRef:o,apiConfigRef:r,optionOverridesRef:a,onErrorRef:i,setCompletedParams:p,setSuggestions:f,setActiveDropdownIndex:g}){let[m,h]=Se(!1),[c,y]=Se(null),[k,b]=Se(!1),A=J(0),M=J(null),d=J(""),l=ht(async(s,u)=>{M.current?.abort();let x=new AbortController;M.current=x;let w=++A.current,O=e.current.length;n.current.some(C=>C.type!=="placeholder")||h(!0),y(null);try{let C=await $e(s,u,{maskCompletedText:o.current,signal:x.signal,apiConfig:r.current});if(w!==A.current)return;let L=Ke(C.data.suggestions??[],a.current);b(C.data.is_ready??!1),d.current=s;let z=C.data.input??[],_=z[z.length-1],T=e.current;if(_?.state==="in_progress"){let F=T.toLowerCase().lastIndexOf(_.text.toLowerCase());F!==-1?t.current=F:t.current=O}else t.current=O;let N=L.filter(F=>F.type!=="placeholder")[0];if(N){let F=T.slice(t.current),I=ee(N.options,F);I&&(p($=>[...$,{id:crypto.randomUUID(),placeholder:"",type:N.type,text:I.text,kind:I.kind,suggestionType:N.type,suggestionPlaceholder:N.text,options:N.options,metadata:I.metadata}]),L=L.filter($=>$!==N))}f(L),h(!1),g(-1)}catch(C){if(w===A.current){let L=C instanceof Error?C:new Error(String(C));y(L),h(!1),i.current?.(L)}}},[e,n,t,o,r,a,i,p,f,g]);return je(()=>(l("",[]),()=>{M.current?.abort()}),[l]),{doFetch:l,isLoading:m,error:c,isReady:k,lastRawQueryRef:d}}function qe({text:e,completedParams:n,doFetch:t,filterBaseRef:o,skipNextFetchRef:r,suggestionsRef:a,lastRawQueryRef:i}){let p=J(null),f=J(null),g=J(!0);je(()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current);let m=h=>{if(r.current)return r.current=!1,!1;if(!e&&n.length===0)return g.current?(t("",[]),!0):(g.current=!0,!1);let c=e.slice(o.current),b=a.current.filter(O=>O.type!=="placeholder")[0],M=(b?ae(b.options,c):[]).filter(O=>O.is_tappable),d=b?ee(b.options,c)!==null:!1,l=c.trim().length>0;if(M.length>0&&!d&&l)return!1;let{rawQuery:s,completedParams:u}=Y(e,n),x=s.length<i.current.length,w=Math.abs(s.length-i.current.length);return x||w>=h?(t(s,u),!0):!1};return p.current=setTimeout(()=>{m(St)&&f.current&&clearTimeout(f.current)},bt),f.current=setTimeout(()=>m(1),yt),()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current)}},[e,n,t,o,r,a,i])}import{useCallback as Be}from"react";function Qe({activeDropdownIndex:e,setActiveDropdownIndex:n,filteredOptions:t,selectOption:o,onSubmitRef:r,text:a,completedParams:i,isDropdownOpen:p,hasPlaceholder:f,placeholderText:g,suggestions:m,filterBaseRef:h,columns:c,setText:y,setCompletedParams:k,setSuggestions:b}){let A=Be(()=>{let d=t.map((s,u)=>s.is_tappable?u:-1).filter(s=>s!==-1),l=Array.from({length:c},()=>[]);for(let s of d)l[s%c].push(s);return l.flat()},[t,c]);return{handleKeyDown:Be(d=>{let l=A();switch(d.key){case"ArrowDown":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s<l.length-1?s+1:0;n(l[u]);break}case"ArrowUp":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s>0?s-1:l.length-1;n(l[u]);break}case"ArrowRight":{if(e<0)break;if(e%c<c-1){let u=e+1;u<t.length&&t[u]?.is_tappable&&(d.preventDefault(),n(u))}break}case"ArrowLeft":{if(e<0)break;if(e%c>0){let s=e-1;s>=0&&t[s]?.is_tappable&&(d.preventDefault(),n(s))}break}case"Enter":{if(d.preventDefault(),e>=0&&t[e]?.is_tappable)o(t[e]);else if(r.current){let{rawQuery:s,completedParams:u}=Y(a,i),x={query:a.trim(),raw_query:s,completed_params:u};r.current(x)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)d.preventDefault(),o(t[e]);else if(p){let s=t.find(u=>u.is_tappable);s&&(d.preventDefault(),o(s))}else if(!a&&f){d.preventDefault();let s=m.find(u=>u.type==="placeholder");s?(y(g),h.current=g.length,k(u=>[...u,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:g,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),b(u=>u.filter(x=>x!==s))):(y(g),h.current=g.length)}break}case"Escape":n(-1);break}},[e,c,i,t,h,A,f,p,r,g,o,n,k,b,y,m,a]),getTappableIndices:A}}import{useCallback as xe}from"react";function He({completedParams:e,suggestions:n,setCompletedParams:t,setSuggestions:o,setActiveDropdownIndex:r,filterBaseRef:a,pillTappedRef:i}){let p=xe(m=>{let h=n.filter(b=>b.type!=="placeholder");if(m<0||m>=h.length)return;let c=h[m],y=h.filter((b,A)=>A!==m),k=n.filter(b=>b.type==="placeholder");o([...k,c,...y]),i.current=!0,r(-1)},[n,o,r,i]),f=xe(()=>{if(e.length===0)return;let m=e[e.length-1],h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};t(c=>c.slice(0,-1)),o(c=>[h,...c]),r(-1)},[e,t,o,r]),g=xe(m=>{let h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};return{apply:c=>{c(y=>{let k=0;for(let b of e){let A=y.indexOf(b.text,k);if(A!==-1){if(b.id===m.id){let M=y.slice(0,A),d=y.slice(A+m.text.length),l=(M+d).replace(/ {2,}/g," ");return a.current=Math.min(a.current,l.length),l}k=A+b.text.length}}return y}),t(y=>y.filter(k=>k.id!==m.id)),o(y=>[h,...y]),r(-1),i.current=!0}}},[e,t,o,r,a,i]);return{setActivePill:p,removeLastParam:f,reEditParam:g}}var xt=0;function Pt(){let e=E(null);return e.current===null&&(e.current=`:ac-${++xt}:`),e.current}function Pe({onSubmit:e,onError:n,optionOverrides:t,maskCompletedText:o,placeholder:r,apiConfig:a,columns:i=2,eagerSuggestions:p=!0,value:f,completedParams:g,onChange:m,onParamsChange:h}){let c=f!==void 0,y=g!==void 0,[k,b]=ie(""),[A,M]=ie([]),[d,l]=ie([]),[s,u]=ie(-1),x=c?f:k,w=y?g:A,O=E(e);O.current=e;let B=E(m);B.current=m;let C=E(h);C.current=h;let L=E(f);L.current=f;let z=E(g);z.current=g;let _=Z(S=>{if(typeof S=="function")if(c){let v=S(L.current??"");B.current?.(v)}else b(v=>{let q=S(v);return B.current?.(q),q});else c||b(S),B.current?.(S)},[c]),T=Z(S=>{if(typeof S=="function")if(y){let v=S(z.current??[]);C.current?.(v)}else M(v=>{let q=S(v);return C.current?.(q),q});else y||M(S),C.current?.(S)},[y]),X=E(n);X.current=n;let N=E(t);N.current=t;let F=E(o);F.current=o;let I=E(a);I.current=a;let $=E(x);$.current=x;let ce=E(d);ce.current=d;let K=E(0),te=E(!1),Ae=E(!1),le=Pt(),{doFetch:ue,isLoading:Ce,error:Ve,isReady:Xe,lastRawQueryRef:pe}=ze({textRef:$,suggestionsRef:ce,filterBaseRef:K,maskCompletedTextRef:F,apiConfigRef:I,optionOverridesRef:N,onErrorRef:X,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u});qe({text:x,completedParams:w,doFetch:ue,filterBaseRef:K,skipNextFetchRef:Ae,suggestionsRef:ce,lastRawQueryRef:pe});let We=se(()=>Ne(x,w),[x,w]);K.current=Math.min(K.current,x.length);let me=x.slice(K.current),de=se(()=>d.filter(v=>v.type==="placeholder").map(v=>v.text).join(" ")||r||"",[d,r]),oe=se(()=>d.filter(S=>S.type!=="placeholder"),[d]),P=oe[0],ke=P?t?.[P.type]:void 0,we=P?ke?ke(me.trim()):P.options??[]:[],fe=se(()=>ae(we,me),[we,me]),Oe=de.length>0,ge=!Ce&&fe.length>0&&(!!x||te.current||!Oe),Ie=Z(S=>{if(!P)return;let v={id:crypto.randomUUID(),placeholder:"",type:P.type,text:S.text,kind:S.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:S.metadata},q=K.current,U=$.current.slice(0,q);if(U.length>0&&!U.endsWith(" ")){let R=U.split(/\s+/).pop()??"";R&&S.text.toLowerCase().startsWith(R.toLowerCase())&&(U=U.slice(0,U.length-R.length))}let he=U.length>0&&U[U.length-1]!==" ",W=U+(he?" ":"")+S.text+" ";_(W),K.current=W.length,T(R=>[...R,v]),te.current=!1,u(-1);let Q=oe.length-1;p&&Q>0?(l(R=>R.filter(H=>H!==P)),Ae.current=!0):l(R=>R.filter(H=>H.type==="placeholder"))},[P,oe,p,_,T]),Ge=Z(S=>{let v=S.target.value,U=v.length>0&&!S.nativeEvent?.isComposing&&v[0]!==v[0].toUpperCase()?v[0].toUpperCase()+v.slice(1):v;_(U),te.current=!1,u(-1);let{valid:he,invalid:W}=De(U,w);if(W.length>0){T(()=>he);for(let Q of W)l(R=>[{type:Q.suggestionType,text:Q.suggestionPlaceholder,required:!0,options:Q.options},...R])}if(P&&W.length===0){let Q=U.slice(K.current),R=ee(P.options,Q);R&&(T(H=>[...H,{id:crypto.randomUUID(),placeholder:"",type:P.type,text:R.text,kind:R.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:R.metadata}]),l(H=>H.filter(tt=>tt!==P)))}},[w,P,_,T]),{handleKeyDown:Ye}=Qe({activeDropdownIndex:s,setActiveDropdownIndex:u,filteredOptions:fe,selectOption:Ie,onSubmitRef:O,text:x,completedParams:w,isDropdownOpen:ge,hasPlaceholder:Oe,placeholderText:de,suggestions:d,filterBaseRef:K,columns:i,setText:_,setCompletedParams:T,setSuggestions:l}),re=He({completedParams:w,suggestions:d,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u,filterBaseRef:K,pillTappedRef:te}),Je=Z(S=>{re.reEditParam(S).apply(_)},[re,_]),Ze=Z(()=>{_(""),T(()=>[]),l([]),u(-1),K.current=0,pe.current="",ue("",[])},[ue,_,T,pe]),et=s>=0?`${le}-option-${s}`:void 0;return{completedParams:w,suggestionPills:oe,setActivePill:re.setActivePill,removeLastParam:re.removeLastParam,reEditParam:Je,segments:We,suggestions:d,activeIndex:s,isReady:Xe,isLoading:Ce,error:Ve,inputProps:{value:x,placeholder:de||void 0,onChange:Ge,onKeyDown:Ye,role:"combobox","aria-expanded":ge,"aria-activedescendant":et,"aria-autocomplete":"list","aria-controls":le},reset:Ze,dropdownProps:{suggestions:P?[{...P,options:fe}]:[],activeIndex:s,onSelect:Ie,onHighlight:u,isOpen:ge,id:le}}}import{jsx as j,jsxs as V}from"react/jsx-runtime";var Ot=vt(function({onSubmit:n,onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,className:i,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y},k){let b=ve(null),[A,M]=wt(!1),d=ve(()=>{}),l=ve(void 0);Ct(()=>(b.current?.focus(),()=>clearTimeout(l.current)),[]);let{completedParams:s,suggestionPills:u,setActivePill:x,segments:w,inputProps:O,dropdownProps:B,reset:C}=Pe({onSubmit:I=>d.current(I),onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y});kt(k,()=>({focus:()=>b.current?.focus(),reset:C}),[C]);let L=()=>{b.current?.focus()},z=!!O.value||s.length>0,_=At(()=>{if(!z)return;let{rawQuery:I,completedParams:$}=Y(O.value,s);n({query:O.value.trim(),raw_query:I,completed_params:$}),C(),M(!0),clearTimeout(l.current),l.current=setTimeout(()=>M(!1),3e3)},[z,O.value,s,n,C]);d.current=_;let{onChange:T,placeholder:X,...N}=O,F=!O.value;return V("div",{className:`${D.container} ${i??""}`,children:[j("div",{className:`${D.checkmark} ${A?D.checkmarkVisible:""}`,children:V("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[j("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),j("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:D.checkmarkPath})]})}),j(ye,{...B}),V("div",{className:D.inputWrapper,onClick:L,children:[V("div",{className:D.editorArea,children:[V("div",{className:D.sizerContent,"aria-hidden":"true",children:[F&&X?V("span",{className:D.placeholderText,children:[X," "]}):V("span",{className:D.sizerText,children:[w.map((I,$)=>j("span",{children:I.value},`${$}-${I.type}`)),w.length===0&&"\xA0"]})," ",j(Le,{pills:u,activePillIndex:0,onSelectPill:x})]}),j("textarea",{ref:b,className:D.textarea,rows:1,onChange:T,...N})]}),j("button",{type:"button",className:D.submitButton,disabled:!z,onClick:I=>{I.stopPropagation(),_()},"aria-label":"Submit",children:j("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:j("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});export{Ot as AIAutocomplete,ye as AIAutocompleteDropdown,Pe as useAIAutocomplete};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/filtering.ts","../src/utils/segments.ts","../src/hooks/useAutocompleteFetch.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/hooks/useAutocompleteKeyboard.ts","../src/hooks/useAutocompletePills.ts"],"sourcesContent":["import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps, AutocompleteResult } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n },\n ref,\n ) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n // Render-phase ref assignment — matches the pattern in useAIAutocomplete.ts\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const checkmarkTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n textareaRef.current?.focus();\n return () => clearTimeout(checkmarkTimerRef.current);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => textareaRef.current?.focus(),\n reset,\n }),\n [reset],\n );\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n clearTimeout(checkmarkTimerRef.current);\n checkmarkTimerRef.current = setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg\n width=\"72\"\n height=\"72\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Success\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList pills={suggestionPills} activePillIndex={0} onSelectPill={setActivePill} />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n );\n },\n);\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--ac-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--ac-color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--ac-color-text-default, #fff);\n caret-color: var(--ac-color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--ac-color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--ac-color-text-default, #fff);\n color: var(--ac-color-bg-default, #000);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--ac-color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.visible {\n opacity: 1;\n pointer-events: auto;\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--ac-color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--ac-color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--ac-color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const hasOptions = isOpen && activeSuggestion && activeSuggestion.options.length > 0;\n\n return (\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${hasOptions ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeSuggestion && activeSuggestion.options.length > 0 && (\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n />\n )}\n </div>\n );\n}\n",".list {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--ac-color-background-supportive, #313255);\n color: var(--ac-color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n}\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { type ChangeEvent, useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { useAutocompleteFetch, useDebouncedFetch } from \"./useAutocompleteFetch\";\nimport { useAutocompleteKeyboard } from \"./useAutocompleteKeyboard\";\nimport { useAutocompletePills } from \"./useAutocompletePills\";\n\nlet idCounter = 0;\nfunction useStableId(): string {\n const id = useRef<string | null>(null);\n if (id.current === null) {\n id.current = `:ac-${++idCounter}:`;\n }\n return id.current;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n eagerSuggestions = true,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Controlled / uncontrolled state ===\n const isTextControlled = controlledValue !== undefined;\n const isParamsControlled = controlledParams !== undefined;\n\n const [internalText, setInternalText] = useState(\"\");\n const [internalCompletedParams, setInternalCompletedParams] = useState<CompletedParamState[]>([]);\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const text = isTextControlled ? controlledValue : internalText;\n const completedParams = isParamsControlled ? controlledParams : internalCompletedParams;\n\n // === Refs — must be before setText/setCompletedParams which read them ===\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const controlledValueRef = useRef(controlledValue);\n controlledValueRef.current = controlledValue;\n const controlledParamsRef = useRef(controlledParams);\n controlledParamsRef.current = controlledParams;\n\n // Stable setText that reads controlled value + callback via refs (no stale closures)\n const setText = useCallback(\n (value: string | ((prev: string) => string)) => {\n if (typeof value === \"function\") {\n if (isTextControlled) {\n const newVal = value(controlledValueRef.current ?? \"\");\n onChangeRef.current?.(newVal);\n } else {\n setInternalText((prev) => {\n const newVal = value(prev);\n onChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isTextControlled) setInternalText(value);\n onChangeRef.current?.(value);\n }\n },\n [isTextControlled],\n );\n\n // Stable setCompletedParams — same ref pattern\n const setCompletedParams = useCallback(\n (value: CompletedParamState[] | ((prev: CompletedParamState[]) => CompletedParamState[])) => {\n if (typeof value === \"function\") {\n if (isParamsControlled) {\n const newVal = value(controlledParamsRef.current ?? []);\n onParamsChangeRef.current?.(newVal);\n } else {\n setInternalCompletedParams((prev) => {\n const newVal = value(prev);\n onParamsChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isParamsControlled) setInternalCompletedParams(value);\n onParamsChangeRef.current?.(value);\n }\n },\n [isParamsControlled],\n );\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const apiConfigRef = useRef(apiConfig);\n apiConfigRef.current = apiConfig;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useStableId();\n\n // === Fetch ===\n const { doFetch, isLoading, error, isReady, lastRawQueryRef } = useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n });\n\n useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n });\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n\n const placeholderText = useMemo(() => {\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n return serverPlaceholder || customPlaceholder || \"\";\n }, [suggestions, customPlaceholder]);\n const actionableSuggestions = useMemo(\n () => suggestions.filter((s) => s.type !== \"placeholder\"),\n [suggestions],\n );\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = useMemo(\n () => filterOptions(baseOptions, filterQuery),\n [baseOptions, filterQuery],\n );\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Option selection ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n const base = filterBaseRef.current;\n let prefix = textRef.current.slice(0, base);\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (eagerSuggestions && remainingActionable > 0) {\n // Keep cached suggestions visible and skip the fetch\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n skipNextFetchRef.current = true;\n } else {\n // Clear all suggestions and let the debounced fetch bring fresh ones\n setSuggestions((prev) => prev.filter((s) => s.type === \"placeholder\"));\n }\n },\n [activeSuggestion, actionableSuggestions, eagerSuggestions, setText, setCompletedParams],\n );\n\n // === Text change handler ===\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(() => valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion, setText, setCompletedParams],\n );\n\n // === Keyboard ===\n const { handleKeyDown } = useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n });\n\n // === Pills ===\n const pills = useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n });\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n pills.reEditParam(param).apply(setText);\n },\n [pills, setText],\n );\n\n // === Reset ===\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams(() => []);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch, setText, setCompletedParams, lastRawQueryRef]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: pills.setActivePill,\n removeLastParam: pills.removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[],\n query: string,\n): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import { type MutableRefObject, useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { applyOptionOverrides } from \"../utils/overrides\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\ninterface UseAutocompleteFetchOptions {\n textRef: MutableRefObject<string>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n filterBaseRef: MutableRefObject<number>;\n maskCompletedTextRef: MutableRefObject<boolean | undefined>;\n apiConfigRef: MutableRefObject<APIConfig | undefined>;\n optionOverridesRef: MutableRefObject<OptionOverrides | undefined>;\n onErrorRef: MutableRefObject<((error: Error) => void) | undefined>;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n}\n\ninterface UseAutocompleteFetchReturn {\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n isReady: boolean;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n}: UseAutocompleteFetchOptions): UseAutocompleteFetchReturn {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n\n const doFetch = useCallback(\n async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n const textAtRequest = textRef.current.length;\n\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n apiConfig: apiConfigRef.current,\n });\n\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = textAtRequest;\n }\n } else {\n filterBaseRef.current = textAtRequest;\n }\n\n // Check if the user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n setError(caughtError);\n setIsLoading(false);\n onErrorRef.current?.(caughtError);\n }\n }\n },\n [\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n ],\n );\n\n // Mount fetch\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n return { doFetch, isLoading, error, isReady, lastRawQueryRef };\n}\n\ninterface UseDebouncedFetchOptions {\n text: string;\n completedParams: CompletedParamState[];\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n filterBaseRef: MutableRefObject<number>;\n skipNextFetchRef: MutableRefObject<boolean>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n}: UseDebouncedFetchOptions): void {\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n const attemptFetch = (minDiff: number): boolean => {\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s: Suggestion) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n ]);\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst API_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/api/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(config?: APIConfig): string {\n const key = config?.apiKey || process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(config?: APIConfig): \"Bearer\" | \"Basic\" {\n if (config?.authScheme) return config.authScheme;\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: {\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options?.apiConfig;\n const apiKey = getApiKey(apiConfig);\n const authScheme = getAuthScheme(apiConfig);\n const includeText = !options?.maskCompletedText;\n\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n ...apiConfig?.headers,\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(API_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import { type KeyboardEvent, type MutableRefObject, useCallback } from \"react\";\nimport type {\n AutocompleteResult,\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\ninterface UseAutocompleteKeyboardOptions {\n activeDropdownIndex: number;\n setActiveDropdownIndex: (index: number) => void;\n filteredOptions: SuggestionOption[];\n selectOption: (option: SuggestionOption) => void;\n onSubmitRef: MutableRefObject<((result: AutocompleteResult) => void) | undefined>;\n text: string;\n completedParams: CompletedParamState[];\n isDropdownOpen: boolean;\n hasPlaceholder: boolean;\n placeholderText: string;\n suggestions: Suggestion[];\n filterBaseRef: MutableRefObject<number>;\n columns: number;\n setText: (value: string) => void;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: (prev: Suggestion[]) => Suggestion[]) => void;\n}\n\nexport function useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n}: UseAutocompleteKeyboardOptions) {\n const getTappableIndices = useCallback(() => {\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n // Column-first ordering: all column-0 items, then column-1, etc.\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }, [filteredOptions, columns]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n const col = activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns > 0) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n const result: AutocompleteResult = {\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n };\n onSubmitRef.current(result);\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n } else {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n columns,\n completedParams,\n filteredOptions,\n filterBaseRef,\n getTappableIndices,\n hasPlaceholder,\n isDropdownOpen,\n onSubmitRef,\n placeholderText,\n selectOption,\n setActiveDropdownIndex,\n setCompletedParams,\n setSuggestions,\n setText,\n suggestions,\n text,\n ],\n );\n\n return { handleKeyDown, getTappableIndices };\n}\n","import { type MutableRefObject, useCallback } from \"react\";\nimport type { CompletedParamState, Suggestion } from \"../types\";\n\ninterface UseAutocompletePillsOptions {\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n filterBaseRef: MutableRefObject<number>;\n pillTappedRef: MutableRefObject<boolean>;\n}\n\nexport function useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n}: UseAutocompletePillsOptions) {\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions, setSuggestions, setActiveDropdownIndex, pillTappedRef],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams, setCompletedParams, setSuggestions, setActiveDropdownIndex]);\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n return {\n apply: (setText: (fn: (prev: string) => string) => void) => {\n setText((prev) => {\n let pos = 0;\n for (const p of completedParams) {\n const idx = prev.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === param.id) {\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n }\n pos = idx + p.text.length;\n }\n return prev;\n });\n setCompletedParams((prev) => prev.filter((p) => p.id !== param.id));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n },\n };\n },\n [\n completedParams,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n ],\n );\n\n return { setActivePill, removeLastParam, reEditParam };\n}\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","jsx","jsxs","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","jsx","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","SuggestionItem","jsx","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","activeSuggestion","hasOptions","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","jsx","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","useCallback","useMemo","useRef","useState","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","useCallback","useEffect","useRef","useState","SDK_VERSION","API_ENDPOINT","hasWarnedMissingKey","getApiKey","config","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiConfig","apiKey","authScheme","rawCount","p","contactAccountCount","body","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","useAutocompleteFetch","textRef","suggestionsRef","filterBaseRef","maskCompletedTextRef","apiConfigRef","optionOverridesRef","onErrorRef","setCompletedParams","setSuggestions","setActiveDropdownIndex","isLoading","setIsLoading","useState","error","setError","isReady","setIsReady","fetchVersionRef","useRef","abortRef","lastRawQueryRef","doFetch","useCallback","rawQuery","completed","controller","version","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","inProgressIdx","active","query","match","findExactMatch","prev","err","caughtError","useEffect","useDebouncedFetch","text","completedParams","skipNextFetchRef","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","useCallback","useAutocompleteKeyboard","activeDropdownIndex","setActiveDropdownIndex","filteredOptions","selectOption","onSubmitRef","text","completedParams","isDropdownOpen","hasPlaceholder","placeholderText","suggestions","filterBaseRef","columns","setText","setCompletedParams","setSuggestions","getTappableIndices","useCallback","tappable","o","i","buckets","e","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","result","firstTappable","placeholderSuggestion","s","prev","useCallback","useAutocompletePills","completedParams","suggestions","setCompletedParams","setSuggestions","setActiveDropdownIndex","filterBaseRef","pillTappedRef","setActivePill","index","actionable","s","moved","rest","_","i","placeholders","removeLastParam","lastParam","restoredSuggestion","prev","reEditParam","param","setText","pos","p","idx","before","after","cleaned","idCounter","useStableId","id","useRef","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","eagerSuggestions","controlledValue","controlledParams","onChangeProp","onParamsChange","isTextControlled","isParamsControlled","internalText","setInternalText","useState","internalCompletedParams","setInternalCompletedParams","suggestions","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","text","completedParams","onSubmitRef","onChangeRef","onParamsChangeRef","controlledValueRef","controlledParamsRef","setText","useCallback","value","newVal","prev","setCompletedParams","onErrorRef","optionOverridesRef","maskCompletedTextRef","apiConfigRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","isLoading","error","isReady","lastRawQueryRef","useAutocompleteFetch","useDebouncedFetch","segments","useMemo","deriveSegments","filterQuery","placeholderText","s","actionableSuggestions","activeSuggestion","overrideFn","baseOptions","filteredOptions","filterOptions","hasPlaceholder","isDropdownOpen","selectOption","option","completed","base","prefix","lastWord","needsSpace","newText","remainingActionable","handleChange","e","raw","newValue","valid","invalid","reconcileParams","param","newFilterQuery","match","findExactMatch","handleKeyDown","useAutocompleteKeyboard","pills","useAutocompletePills","reEditParam","reset","activeDescendantId","jsx","jsxs","AIAutocomplete","forwardRef","onSubmit","onError","optionOverrides","maskCompletedText","placeholder","className","apiConfig","columns","eagerSuggestions","value","controlledParams","onChangeProp","onParamsChange","ref","textareaRef","useRef","showCheckmark","setShowCheckmark","useState","handleSubmitRef","checkmarkTimerRef","useEffect","completedParams","suggestionPills","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","result","useImperativeHandle","handleContainerClick","canSubmit","handleSubmit","useCallback","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
|
|
1
|
+
{"version":3,"sources":["../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/filtering.ts","../src/utils/segments.ts","../src/hooks/useAutocompleteFetch.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/hooks/useAutocompleteKeyboard.ts","../src/hooks/useAutocompletePills.ts"],"sourcesContent":["import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps, AutocompleteResult } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n },\n ref,\n ) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n // Render-phase ref assignment — matches the pattern in useAIAutocomplete.ts\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const checkmarkTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n textareaRef.current?.focus();\n return () => clearTimeout(checkmarkTimerRef.current);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n apiConfig,\n columns,\n eagerSuggestions,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => textareaRef.current?.focus(),\n reset,\n }),\n [reset],\n );\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n clearTimeout(checkmarkTimerRef.current);\n checkmarkTimerRef.current = setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg\n width=\"72\"\n height=\"72\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Success\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList pills={suggestionPills} activePillIndex={0} onSelectPill={setActivePill} />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n );\n },\n);\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--ac-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--ac-color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--ac-color-text-default, #fff);\n caret-color: var(--ac-color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--ac-color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--ac-color-text-default, #fff);\n color: var(--ac-color-bg-default, #000);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--ac-color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.visible {\n opacity: 1;\n pointer-events: auto;\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--ac-color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--ac-color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--ac-color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const hasOptions = isOpen && activeSuggestion && activeSuggestion.options.length > 0;\n\n return (\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${hasOptions ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeSuggestion && activeSuggestion.options.length > 0 && (\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n />\n )}\n </div>\n );\n}\n",".list {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--ac-color-background-supportive, #313255);\n color: var(--ac-color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n}\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { type ChangeEvent, useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { useAutocompleteFetch, useDebouncedFetch } from \"./useAutocompleteFetch\";\nimport { useAutocompleteKeyboard } from \"./useAutocompleteKeyboard\";\nimport { useAutocompletePills } from \"./useAutocompletePills\";\n\nlet idCounter = 0;\nfunction useStableId(): string {\n const id = useRef<string | null>(null);\n if (id.current === null) {\n id.current = `:ac-${++idCounter}:`;\n }\n return id.current;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n eagerSuggestions = true,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Controlled / uncontrolled state ===\n const isTextControlled = controlledValue !== undefined;\n const isParamsControlled = controlledParams !== undefined;\n\n const [internalText, setInternalText] = useState(\"\");\n const [internalCompletedParams, setInternalCompletedParams] = useState<CompletedParamState[]>([]);\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const text = isTextControlled ? controlledValue : internalText;\n const completedParams = isParamsControlled ? controlledParams : internalCompletedParams;\n\n // === Refs — must be before setText/setCompletedParams which read them ===\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const controlledValueRef = useRef(controlledValue);\n controlledValueRef.current = controlledValue;\n const controlledParamsRef = useRef(controlledParams);\n controlledParamsRef.current = controlledParams;\n\n // Stable setText that reads controlled value + callback via refs (no stale closures)\n const setText = useCallback(\n (value: string | ((prev: string) => string)) => {\n if (typeof value === \"function\") {\n if (isTextControlled) {\n const newVal = value(controlledValueRef.current ?? \"\");\n onChangeRef.current?.(newVal);\n } else {\n setInternalText((prev) => {\n const newVal = value(prev);\n onChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isTextControlled) setInternalText(value);\n onChangeRef.current?.(value);\n }\n },\n [isTextControlled],\n );\n\n // Stable setCompletedParams — same ref pattern\n const setCompletedParams = useCallback(\n (value: CompletedParamState[] | ((prev: CompletedParamState[]) => CompletedParamState[])) => {\n if (typeof value === \"function\") {\n if (isParamsControlled) {\n const newVal = value(controlledParamsRef.current ?? []);\n onParamsChangeRef.current?.(newVal);\n } else {\n setInternalCompletedParams((prev) => {\n const newVal = value(prev);\n onParamsChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isParamsControlled) setInternalCompletedParams(value);\n onParamsChangeRef.current?.(value);\n }\n },\n [isParamsControlled],\n );\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const apiConfigRef = useRef(apiConfig);\n apiConfigRef.current = apiConfig;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useStableId();\n\n // === Fetch ===\n const { doFetch, isLoading, error, isReady, lastRawQueryRef } = useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n });\n\n useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n });\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n\n const placeholderText = useMemo(() => {\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n return serverPlaceholder || customPlaceholder || \"\";\n }, [suggestions, customPlaceholder]);\n const actionableSuggestions = useMemo(\n () => suggestions.filter((s) => s.type !== \"placeholder\"),\n [suggestions],\n );\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = useMemo(\n () => filterOptions(baseOptions, filterQuery),\n [baseOptions, filterQuery],\n );\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Option selection ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n const base = filterBaseRef.current;\n let prefix = textRef.current.slice(0, base);\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (eagerSuggestions && remainingActionable > 0) {\n // Keep cached suggestions visible and skip the fetch\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n skipNextFetchRef.current = true;\n } else {\n // Clear all suggestions and let the debounced fetch bring fresh ones\n setSuggestions((prev) => prev.filter((s) => s.type === \"placeholder\"));\n }\n },\n [activeSuggestion, actionableSuggestions, eagerSuggestions, setText, setCompletedParams],\n );\n\n // === Text change handler ===\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(() => valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion, setText, setCompletedParams],\n );\n\n // === Keyboard ===\n const { handleKeyDown } = useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n });\n\n // === Pills ===\n const pills = useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n });\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n pills.reEditParam(param).apply(setText);\n },\n [pills, setText],\n );\n\n // === Reset ===\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams(() => []);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch, setText, setCompletedParams, lastRawQueryRef]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: pills.setActivePill,\n removeLastParam: pills.removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[],\n query: string,\n): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import { type MutableRefObject, useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { applyOptionOverrides } from \"../utils/overrides\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\ninterface UseAutocompleteFetchOptions {\n textRef: MutableRefObject<string>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n filterBaseRef: MutableRefObject<number>;\n maskCompletedTextRef: MutableRefObject<boolean | undefined>;\n apiConfigRef: MutableRefObject<APIConfig | undefined>;\n optionOverridesRef: MutableRefObject<OptionOverrides | undefined>;\n onErrorRef: MutableRefObject<((error: Error) => void) | undefined>;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n}\n\ninterface UseAutocompleteFetchReturn {\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n isReady: boolean;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n}: UseAutocompleteFetchOptions): UseAutocompleteFetchReturn {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n\n const doFetch = useCallback(\n async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n const textAtRequest = textRef.current.length;\n\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n apiConfig: apiConfigRef.current,\n });\n\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = textAtRequest;\n }\n } else {\n filterBaseRef.current = textAtRequest;\n }\n\n // Check if the user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n setError(caughtError);\n setIsLoading(false);\n onErrorRef.current?.(caughtError);\n }\n }\n },\n [\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n ],\n );\n\n // Mount fetch\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n return { doFetch, isLoading, error, isReady, lastRawQueryRef };\n}\n\ninterface UseDebouncedFetchOptions {\n text: string;\n completedParams: CompletedParamState[];\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n filterBaseRef: MutableRefObject<number>;\n skipNextFetchRef: MutableRefObject<boolean>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n}: UseDebouncedFetchOptions): void {\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n const attemptFetch = (minDiff: number): boolean => {\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s: Suggestion) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n ]);\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst DEFAULT_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/ac/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(config?: APIConfig): string {\n const key = config?.apiKey || process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(config?: APIConfig): \"Bearer\" | \"Basic\" {\n if (config?.authScheme) return config.authScheme;\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: {\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options?.apiConfig;\n const apiKey = getApiKey(apiConfig);\n const authScheme = getAuthScheme(apiConfig);\n const includeText = !options?.maskCompletedText;\n\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n ...apiConfig?.headers,\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(apiConfig?.endpoint || DEFAULT_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import { type KeyboardEvent, type MutableRefObject, useCallback } from \"react\";\nimport type {\n AutocompleteResult,\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\ninterface UseAutocompleteKeyboardOptions {\n activeDropdownIndex: number;\n setActiveDropdownIndex: (index: number) => void;\n filteredOptions: SuggestionOption[];\n selectOption: (option: SuggestionOption) => void;\n onSubmitRef: MutableRefObject<((result: AutocompleteResult) => void) | undefined>;\n text: string;\n completedParams: CompletedParamState[];\n isDropdownOpen: boolean;\n hasPlaceholder: boolean;\n placeholderText: string;\n suggestions: Suggestion[];\n filterBaseRef: MutableRefObject<number>;\n columns: number;\n setText: (value: string) => void;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: (prev: Suggestion[]) => Suggestion[]) => void;\n}\n\nexport function useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n}: UseAutocompleteKeyboardOptions) {\n const getTappableIndices = useCallback(() => {\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n // Column-first ordering: all column-0 items, then column-1, etc.\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }, [filteredOptions, columns]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n const col = activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns > 0) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n const result: AutocompleteResult = {\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n };\n onSubmitRef.current(result);\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n } else {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n columns,\n completedParams,\n filteredOptions,\n filterBaseRef,\n getTappableIndices,\n hasPlaceholder,\n isDropdownOpen,\n onSubmitRef,\n placeholderText,\n selectOption,\n setActiveDropdownIndex,\n setCompletedParams,\n setSuggestions,\n setText,\n suggestions,\n text,\n ],\n );\n\n return { handleKeyDown, getTappableIndices };\n}\n","import { type MutableRefObject, useCallback } from \"react\";\nimport type { CompletedParamState, Suggestion } from \"../types\";\n\ninterface UseAutocompletePillsOptions {\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n filterBaseRef: MutableRefObject<number>;\n pillTappedRef: MutableRefObject<boolean>;\n}\n\nexport function useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n}: UseAutocompletePillsOptions) {\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions, setSuggestions, setActiveDropdownIndex, pillTappedRef],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams, setCompletedParams, setSuggestions, setActiveDropdownIndex]);\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n return {\n apply: (setText: (fn: (prev: string) => string) => void) => {\n setText((prev) => {\n let pos = 0;\n for (const p of completedParams) {\n const idx = prev.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === param.id) {\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n }\n pos = idx + p.text.length;\n }\n return prev;\n });\n setCompletedParams((prev) => prev.filter((p) => p.id !== param.id));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n },\n };\n },\n [\n completedParams,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n ],\n );\n\n return { setActivePill, removeLastParam, reEditParam };\n}\n"],"mappings":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useRef","useState","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","jsx","jsxs","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","jsx","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","SuggestionItem","jsx","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","activeSuggestion","hasOptions","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","jsx","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","useCallback","useMemo","useRef","useState","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","useCallback","useEffect","useRef","useState","SDK_VERSION","DEFAULT_ENDPOINT","hasWarnedMissingKey","getApiKey","config","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiConfig","apiKey","authScheme","rawCount","p","contactAccountCount","body","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","useAutocompleteFetch","textRef","suggestionsRef","filterBaseRef","maskCompletedTextRef","apiConfigRef","optionOverridesRef","onErrorRef","setCompletedParams","setSuggestions","setActiveDropdownIndex","isLoading","setIsLoading","useState","error","setError","isReady","setIsReady","fetchVersionRef","useRef","abortRef","lastRawQueryRef","doFetch","useCallback","rawQuery","completed","controller","version","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","inProgressIdx","active","query","match","findExactMatch","prev","err","caughtError","useEffect","useDebouncedFetch","text","completedParams","skipNextFetchRef","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","useCallback","useAutocompleteKeyboard","activeDropdownIndex","setActiveDropdownIndex","filteredOptions","selectOption","onSubmitRef","text","completedParams","isDropdownOpen","hasPlaceholder","placeholderText","suggestions","filterBaseRef","columns","setText","setCompletedParams","setSuggestions","getTappableIndices","useCallback","tappable","o","i","buckets","e","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","result","firstTappable","placeholderSuggestion","s","prev","useCallback","useAutocompletePills","completedParams","suggestions","setCompletedParams","setSuggestions","setActiveDropdownIndex","filterBaseRef","pillTappedRef","setActivePill","index","actionable","s","moved","rest","_","i","placeholders","removeLastParam","lastParam","restoredSuggestion","prev","reEditParam","param","setText","pos","p","idx","before","after","cleaned","idCounter","useStableId","id","useRef","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","eagerSuggestions","controlledValue","controlledParams","onChangeProp","onParamsChange","isTextControlled","isParamsControlled","internalText","setInternalText","useState","internalCompletedParams","setInternalCompletedParams","suggestions","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","text","completedParams","onSubmitRef","onChangeRef","onParamsChangeRef","controlledValueRef","controlledParamsRef","setText","useCallback","value","newVal","prev","setCompletedParams","onErrorRef","optionOverridesRef","maskCompletedTextRef","apiConfigRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","isLoading","error","isReady","lastRawQueryRef","useAutocompleteFetch","useDebouncedFetch","segments","useMemo","deriveSegments","filterQuery","placeholderText","s","actionableSuggestions","activeSuggestion","overrideFn","baseOptions","filteredOptions","filterOptions","hasPlaceholder","isDropdownOpen","selectOption","option","completed","base","prefix","lastWord","needsSpace","newText","remainingActionable","handleChange","e","raw","newValue","valid","invalid","reconcileParams","param","newFilterQuery","match","findExactMatch","handleKeyDown","useAutocompleteKeyboard","pills","useAutocompletePills","reEditParam","reset","activeDescendantId","jsx","jsxs","AIAutocomplete","forwardRef","onSubmit","onError","optionOverrides","maskCompletedText","placeholder","className","apiConfig","columns","eagerSuggestions","value","controlledParams","onChangeProp","onParamsChange","ref","textareaRef","useRef","showCheckmark","setShowCheckmark","useState","handleSubmitRef","checkmarkTimerRef","useEffect","completedParams","suggestionPills","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","result","useImperativeHandle","handleContainerClick","canSubmit","handleSubmit","useCallback","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magicx-eng/ai-autocomplete-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "AI Autocomplete React SDK — guided autocomplete with pill-based input and dropdown suggestions",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|