@magicx-eng/ai-autocomplete-react 0.1.5 → 0.1.6
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 +68 -21
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- 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 +9 -8
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ pnpm add @magicx-eng/ai-autocomplete-react
|
|
|
23
23
|
|
|
24
24
|
### Peer Dependencies
|
|
25
25
|
|
|
26
|
-
React
|
|
26
|
+
React 17 or later:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
pnpm add react react-dom
|
|
@@ -132,6 +132,7 @@ The full component. Owns the input, pills, dropdown, and keyboard navigation.
|
|
|
132
132
|
| `placeholder?` | `string` | — | Fallback placeholder when the server doesn't return one. |
|
|
133
133
|
| `className?` | `string` | — | CSS class applied to the container. |
|
|
134
134
|
| `columns?` | `number` | `2` | Number of columns in the dropdown grid. |
|
|
135
|
+
| `eagerSuggestions?` | `boolean` | `true` | When `true`, show cached next suggestions immediately after selecting an option. When `false`, clear the dropdown and wait for the server response before showing the next suggestions. |
|
|
135
136
|
| `value?` | `string` | — | Controlled text value. |
|
|
136
137
|
| `completedParams?` | `CompletedParamState[]` | — | Controlled completed params. |
|
|
137
138
|
| `onChange?` | `(value: string) => void` | — | Called when text changes (controlled mode). |
|
|
@@ -164,39 +165,85 @@ Accepts the same props as `<AIAutocomplete />` (except `className` and `ref`), w
|
|
|
164
165
|
|
|
165
166
|
#### Return Value
|
|
166
167
|
|
|
168
|
+
**State**
|
|
169
|
+
|
|
170
|
+
| Field | Type | Description |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| `completedParams` | `CompletedParamState[]` | All parameters the user has filled so far. Each entry contains the selected option's `text`, `kind`, `type`, and `metadata`, plus client-side fields like `id` (stable UUID), `options` (cached for re-editing), `suggestionType`, and `suggestionPlaceholder`. Use these to render completed values (e.g. bold text) and to build the final query on submit. |
|
|
173
|
+
| `suggestionPills` | `Suggestion[]` | Unfilled suggestions that should be rendered as pills (inline chips). Excludes placeholder-type suggestions. The first item is the "active" pill whose options appear in the dropdown. Tapping a pill reorders it to the front via `setActivePill`. |
|
|
174
|
+
| `segments` | `Segment[]` | The input text split into typed segments for overlay rendering. Each segment is either `{ type: "text", value: string }` for plain text, or `{ type: "completed", value: string, param: CompletedParamState }` for a completed parameter. Use these to render a styled overlay on top of the textarea — e.g. showing completed params in bold while keeping the textarea's actual text transparent. |
|
|
175
|
+
| `suggestions` | `Suggestion[]` | All suggestions from the server, including placeholder-type suggestions. Most consumers should use `suggestionPills` and `dropdownProps` instead — this is exposed for advanced use cases like custom pill or dropdown rendering. |
|
|
176
|
+
| `activeIndex` | `number` | Index of the currently keyboard-highlighted option in the dropdown. `-1` when no option is highlighted. Automatically managed by arrow keys. |
|
|
177
|
+
| `isLoading` | `boolean` | `true` while a fetch is in flight and no cached suggestions are visible. With `eagerSuggestions={true}` (default), this only triggers on initial mount or after `reset()` — the dropdown stays open during background re-fetches. With `eagerSuggestions={false}`, it also becomes `true` after each option selection, closing the dropdown until fresh data arrives. |
|
|
178
|
+
| `isReady` | `boolean` | `true` when the server's `is_ready` flag indicates the query is complete and ready for execution. Use this to show a visual indicator or enable a submit button. |
|
|
179
|
+
| `error` | `Error \| null` | The most recent fetch error, or `null` if the last fetch succeeded. Cleared on every new fetch attempt. |
|
|
180
|
+
|
|
181
|
+
**Actions**
|
|
182
|
+
|
|
167
183
|
| Field | Type | Description |
|
|
168
184
|
|---|---|---|
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
|
177
|
-
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `error` | `Error \| null` | Last fetch error, or `null`. |
|
|
181
|
-
| `inputProps` | `object` | Spread onto a `<textarea>` — value, placeholder, onChange, onKeyDown, ARIA. |
|
|
182
|
-
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. |
|
|
185
|
+
| `setActivePill` | `(index: number) => void` | Reorder pills by moving the pill at `index` to the front, making it the active pill whose options show in the dropdown. |
|
|
186
|
+
| `removeLastParam` | `() => void` | Remove the most recently completed parameter, restore it as a pill, and re-show its options in the dropdown. Useful for handling backspace on an empty input. |
|
|
187
|
+
| `reEditParam` | `(param: CompletedParamState) => void` | Remove a specific completed parameter from the input text, restore it as a pill with its cached options, and open the dropdown. Use this when the user taps on a bold (completed) param to change their selection. |
|
|
188
|
+
| `reset` | `() => void` | Clear all text, completed params, and suggestions, then re-fetch initial suggestions from the server. Returns the component to its mount state. |
|
|
189
|
+
|
|
190
|
+
**Spread Props**
|
|
191
|
+
|
|
192
|
+
| Field | Type | Description |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| `inputProps` | `object` | Spread onto a `<textarea>` element. Includes `value`, `placeholder`, `onChange`, `onKeyDown`, and ARIA attributes (`role="combobox"`, `aria-expanded`, `aria-activedescendant`, `aria-autocomplete`, `aria-controls`). Handles keyboard navigation, text capitalization, param reconciliation, and exact-match auto-completion internally. |
|
|
195
|
+
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Includes the filtered options for the active suggestion, highlight index, selection handler, highlight handler, open state, and listbox ID. The dropdown handles mouse selection and hover highlighting. |
|
|
183
196
|
|
|
184
197
|
### `<AIAutocompleteDropdown />`
|
|
185
198
|
|
|
186
199
|
The dropdown component for Tier 2 headless integration. Spread `dropdownProps` from the hook.
|
|
187
200
|
|
|
201
|
+
| Prop | Type | Description |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `suggestions` | `Suggestion[]` | Suggestions to display (from `dropdownProps`). |
|
|
204
|
+
| `activeIndex` | `number` | Currently highlighted option index. |
|
|
205
|
+
| `onSelect` | `(option: SuggestionOption) => void` | Called when an option is selected. |
|
|
206
|
+
| `onHighlight` | `(index: number) => void` | Called when an option is highlighted (mouse hover). |
|
|
207
|
+
| `isOpen` | `boolean` | Whether the dropdown is visible. |
|
|
208
|
+
| `id` | `string` | Listbox ID for ARIA. |
|
|
209
|
+
| `className?` | `string` | CSS class applied to the dropdown. |
|
|
210
|
+
|
|
211
|
+
### `Suggestion`
|
|
212
|
+
|
|
213
|
+
Represents an unfilled parameter slot. Rendered as a pill in Tier 1, or available via `suggestionPills` in Tier 2.
|
|
214
|
+
|
|
215
|
+
| Field | Type | Description |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `type` | `string` | Suggestion type identifier (e.g. `"task"`, `"goal"`, `"contact"`). Used as the key for `optionOverrides`. |
|
|
218
|
+
| `text` | `string` | Display text for the pill (e.g. `"type"`, `"goal"`). |
|
|
219
|
+
| `required` | `boolean` | Whether this suggestion must be filled before submission. |
|
|
220
|
+
| `options` | `SuggestionOption[]` | Available options the user can select from. |
|
|
221
|
+
|
|
222
|
+
### `SuggestionOption`
|
|
223
|
+
|
|
224
|
+
An individual option within a suggestion's dropdown.
|
|
225
|
+
|
|
226
|
+
| Field | Type | Description |
|
|
227
|
+
|---|---|---|
|
|
228
|
+
| `text` | `string` | Display text for the option. |
|
|
229
|
+
| `icon?` | `string` | Icon shown before the text (e.g. emoji). |
|
|
230
|
+
| `tag?` | `string` | Label shown after the text in smaller, muted style. |
|
|
231
|
+
| `is_tappable` | `boolean` | Whether the option can be selected. Non-tappable options are always-visible hints that cannot be chosen. |
|
|
232
|
+
| `kind` | `string \| null` | Category of the option (e.g. `"automation"`, `"email"`), or `null`. Passed through to `CompletedParam` on selection. |
|
|
233
|
+
| `metadata?` | `Record<string, unknown>` | Arbitrary metadata passed through with the selection. Available on the completed param after the user selects this option. |
|
|
234
|
+
|
|
188
235
|
## CSS Customization
|
|
189
236
|
|
|
190
237
|
The component uses CSS Modules with customizable CSS variables. Override them on a parent element:
|
|
191
238
|
|
|
192
239
|
```css
|
|
193
240
|
.my-autocomplete {
|
|
194
|
-
--ac-color-border-default: #ccc;
|
|
195
|
-
--ac-color-text-default: #333;
|
|
196
|
-
--ac-color-text-muted: #999;
|
|
197
|
-
--ac-color-bg-default: #
|
|
198
|
-
--ac-color-background-default: #fff;
|
|
199
|
-
--ac-color-background-supportive: #
|
|
241
|
+
--ac-color-border-default: #ccc; /* Input border */
|
|
242
|
+
--ac-color-text-default: #333; /* Input text, caret, submit button bg, highlighted option */
|
|
243
|
+
--ac-color-text-muted: #999; /* Placeholder, pill text, option text */
|
|
244
|
+
--ac-color-bg-default: #000; /* Submit button icon color (foreground on button) */
|
|
245
|
+
--ac-color-background-default: #fff; /* Dropdown background */
|
|
246
|
+
--ac-color-background-supportive: #eee; /* Pill background */
|
|
200
247
|
}
|
|
201
248
|
```
|
|
202
249
|
|
package/dist/index.d.mts
CHANGED
|
@@ -58,6 +58,9 @@ interface AIAutocompleteProps {
|
|
|
58
58
|
className?: string;
|
|
59
59
|
apiConfig?: APIConfig;
|
|
60
60
|
columns?: number;
|
|
61
|
+
/** When true (default), show cached next suggestions immediately after option select.
|
|
62
|
+
* When false, clear suggestions and wait for the server response. */
|
|
63
|
+
eagerSuggestions?: boolean;
|
|
61
64
|
value?: string;
|
|
62
65
|
completedParams?: CompletedParamState[];
|
|
63
66
|
onChange?: (value: string) => void;
|
|
@@ -76,6 +79,9 @@ interface UseAIAutocompleteOptions {
|
|
|
76
79
|
placeholder?: string;
|
|
77
80
|
apiConfig?: APIConfig;
|
|
78
81
|
columns?: number;
|
|
82
|
+
/** When true (default), show cached next suggestions immediately after option select.
|
|
83
|
+
* When false, clear suggestions and wait for the server response. */
|
|
84
|
+
eagerSuggestions?: boolean;
|
|
79
85
|
value?: string;
|
|
80
86
|
completedParams?: CompletedParamState[];
|
|
81
87
|
onChange?: (value: string) => void;
|
|
@@ -121,6 +127,6 @@ declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProp
|
|
|
121
127
|
|
|
122
128
|
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
123
129
|
|
|
124
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
130
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, eagerSuggestions, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
125
131
|
|
|
126
132
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
package/dist/index.d.ts
CHANGED
|
@@ -58,6 +58,9 @@ interface AIAutocompleteProps {
|
|
|
58
58
|
className?: string;
|
|
59
59
|
apiConfig?: APIConfig;
|
|
60
60
|
columns?: number;
|
|
61
|
+
/** When true (default), show cached next suggestions immediately after option select.
|
|
62
|
+
* When false, clear suggestions and wait for the server response. */
|
|
63
|
+
eagerSuggestions?: boolean;
|
|
61
64
|
value?: string;
|
|
62
65
|
completedParams?: CompletedParamState[];
|
|
63
66
|
onChange?: (value: string) => void;
|
|
@@ -76,6 +79,9 @@ interface UseAIAutocompleteOptions {
|
|
|
76
79
|
placeholder?: string;
|
|
77
80
|
apiConfig?: APIConfig;
|
|
78
81
|
columns?: number;
|
|
82
|
+
/** When true (default), show cached next suggestions immediately after option select.
|
|
83
|
+
* When false, clear suggestions and wait for the server response. */
|
|
84
|
+
eagerSuggestions?: boolean;
|
|
79
85
|
value?: string;
|
|
80
86
|
completedParams?: CompletedParamState[];
|
|
81
87
|
onChange?: (value: string) => void;
|
|
@@ -121,6 +127,6 @@ declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProp
|
|
|
121
127
|
|
|
122
128
|
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
123
129
|
|
|
124
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
130
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, eagerSuggestions, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
125
131
|
|
|
126
132
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var be=Object.defineProperty;var Je=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var et=Object.prototype.hasOwnProperty;var tt=(e,o)=>{for(var t in o)be(e,t,{get:o[t],enumerable:!0})},ot=(e,o,t,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of Ze(o))!et.call(e,n)&&n!==t&&be(e,n,{get:()=>o[n],enumerable:!(r=Je(o,n))||r.enumerable});return e};var nt=e=>ot(be({},"__esModule",{value:!0}),e);var St={};tt(St,{AIAutocomplete:()=>ze,AIAutocompleteDropdown:()=>re,useAIAutocomplete:()=>ce});module.exports=nt(St);var D=require("react");var j={};var ye={};var Re={};var W={};var ne=require("react/jsx-runtime");function _e({option:e,isHighlighted:o,onSelect:t,onHighlight:r,id:n}){let a=[W.item,o?W.highlighted:"",e.is_tappable?W.tappable:W.nonTappable].filter(Boolean).join(" ");return(0,ne.jsxs)("div",{id:n,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:r,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&(0,ne.jsx)("span",{className:W.tag,children:e.tag})]})}var Se=require("react/jsx-runtime");function Te({options:e,activeIndex:o,onSelect:t,onHighlight:r,listboxId:n}){return(0,Se.jsx)("div",{className:Re.grid,children:e.map((a,i)=>(0,Se.jsx)(_e,{option:a,isHighlighted:i===o,onSelect:t,onHighlight:()=>r(i),id:`${n}-option-${i}`},a.text))})}var xe=require("react/jsx-runtime");function re({suggestions:e,activeIndex:o,onSelect:t,onHighlight:r,isOpen:n,id:a,className:i}){let l=e[0],d=n&&l&&l.options.length>0;return(0,xe.jsx)("div",{id:a,role:"listbox",className:`${ye.dropdown} ${d?ye.visible:""} ${i??""}`,onMouseDown:g=>g.preventDefault(),children:l&&l.options.length>0&&(0,xe.jsx)(Te,{options:l.options,activeIndex:o,onSelect:t,onHighlight:r,listboxId:a})})}var ae={};var Pe=require("react/jsx-runtime");function lt(e){return e===0?.4:e===1?.3:.15}function Ee({pills:e,activePillIndex:o,onSelectPill:t}){return(0,Pe.jsx)("span",{className:ae.list,children:e.map((r,n)=>(0,Pe.jsx)("button",{type:"button",className:`${ae.pill} ${n===o?ae.active:""}`,style:{opacity:lt(n)},onClick:()=>t(n),children:r.text},`${r.type}-${r.text}`))})}var u=require("react");function se(e,o){let t=o.trimStart();if(!t)return e;let r=t.toLowerCase();return e.filter(n=>!n.is_tappable||n.text.toLowerCase().includes(r))}function Z(e,o){let t=o.trim();if(!t)return null;let r=t.toLowerCase();return e.find(n=>n.is_tappable&&n.text.toLowerCase()===r)??null}function Me(e,o){let t=[],r=0;for(let a of o){let i=e.indexOf(a.text,r);i!==-1&&(i>r&&t.push({type:"text",value:e.slice(r,i)}),t.push({type:"completed",value:a.text,param:a}),r=i+a.text.length)}let n=e.slice(r);return n&&t.push({type:"text",value:n}),t}function Ue(e,o){let t=[],r=[],n=0;for(let a of o){let i=e.indexOf(a.text,n);i===-1?r.push(a):(t.push(a),n=i+a.text.length)}return{valid:t,invalid:r}}var T=require("react");var ut="0.1.5",pt=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",Le=!1;function mt(e){let o=e?.apiKey||process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!o&&!Le&&(Le=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),o}function dt(e){return e?.authScheme?e.authScheme:process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function ft(){return crypto.randomUUID()}function gt(e,o){return{placeholder:e.placeholder,type:e.type,...o&&{text:e.text},kind:e.kind}}async function Ne(e,o,t){let r=t?.apiConfig,n=mt(r),a=dt(r),i=!t?.maskCompletedText,l=t?.contactAccountCount,d={data:{raw_query:e,completed_params:o.map(b=>gt(b,i)),...l!=null&&{contact_account_count:l}},meta:{request_id:ft(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:ut}},g={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo",...r?.headers};n&&(g.Authorization=a==="Basic"?`Basic ${btoa(n)}`:`Bearer ${n}`);let p=await fetch(pt,{method:"POST",headers:g,body:JSON.stringify(d),signal:t?.signal});if(!p.ok)throw new Error(`API error: ${p.status} ${p.statusText}`);return p.json()}function G(e,o){let t=e,r={},n=[];for(let a of o){let i=(r[a.type]??0)+1;r[a.type]=i;let d=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,g=t.indexOf(a.text);g!==-1&&(t=t.slice(0,g)+d+t.slice(g+a.text.length)),n.push({...a,placeholder:d})}return{rawQuery:t,completedParams:n}}function De(e,o){return o?e.map(t=>{let r=o[t.type];if(!r)return t;let n=r("");if(n.length===0)return t;let a=new Set(n.map(l=>l.text)),i=(t.options??[]).filter(l=>!a.has(l.text));return{...t,options:[...n,...i]}}):e}var ht=100,bt=300,yt=2;function Fe({textRef:e,suggestionsRef:o,filterBaseRef:t,maskCompletedTextRef:r,apiConfigRef:n,optionOverridesRef:a,onErrorRef:i,setCompletedParams:l,setSuggestions:d,setActiveDropdownIndex:g}){let[p,b]=(0,T.useState)(!1),[h,S]=(0,T.useState)(null),[k,x]=(0,T.useState)(!1),v=(0,T.useRef)(0),A=(0,T.useRef)(null),m=(0,T.useRef)(""),f=(0,T.useCallback)(async(s,c)=>{A.current?.abort();let P=new AbortController;A.current=P;let U=++v.current,F=e.current.length;o.current.some($=>$.type!=="placeholder")||b(!0),S(null);try{let $=c.find(_=>_.type==="contact"&&_.metadata?.contact_account_count)?.metadata?.contact_account_count,K=await Ne(s,c,{maskCompletedText:r.current,signal:P.signal,contactAccountCount:typeof $=="number"?$:void 0,apiConfig:n.current});if(U!==v.current)return;let R=De(K.data.suggestions??[],a.current);x(K.data.is_ready??!1),m.current=s;let E=K.data.input??[],q=E[E.length-1],H=e.current;if(q?.state==="in_progress"){let _=H.toLowerCase().lastIndexOf(q.text.toLowerCase());_!==-1?t.current=_:t.current=F}else t.current=F;let O=R.filter(_=>_.type!=="placeholder")[0];if(O){let _=H.slice(t.current),B=Z(O.options,_);B&&(l(M=>[...M,{id:crypto.randomUUID(),placeholder:"",type:O.type,text:B.text,kind:B.kind,suggestionType:O.type,suggestionPlaceholder:O.text,options:O.options,metadata:B.metadata}]),R=R.filter(M=>M!==O))}d(R),b(!1),g(-1)}catch($){if(U===v.current){let K=$ instanceof Error?$:new Error(String($));S(K),b(!1),i.current?.(K)}}},[e,o,t,r,n,a,i,l,d,g]);return(0,T.useEffect)(()=>(f("",[]),()=>{A.current?.abort()}),[f]),{doFetch:f,isLoading:p,error:h,isReady:k,lastRawQueryRef:m}}function $e({text:e,completedParams:o,doFetch:t,filterBaseRef:r,skipNextFetchRef:n,suggestionsRef:a,lastRawQueryRef:i}){let l=(0,T.useRef)(null),d=(0,T.useRef)(null),g=(0,T.useRef)(!0);(0,T.useEffect)(()=>{l.current&&clearTimeout(l.current),d.current&&clearTimeout(d.current);let p=b=>{if(n.current)return n.current=!1,!1;if(!e&&o.length===0)return g.current?(t("",[]),!0):(g.current=!0,!1);let h=e.slice(r.current),x=a.current.filter(F=>F.type!=="placeholder")[0],A=(x?se(x.options,h):[]).filter(F=>F.is_tappable),m=x?Z(x.options,h)!==null:!1,f=h.trim().length>0;if(A.length>0&&!m&&f)return!1;let{rawQuery:s,completedParams:c}=G(e,o),P=s.length<i.current.length,U=Math.abs(s.length-i.current.length);return P||U>=b?(t(s,c),!0):!1};return l.current=setTimeout(()=>{p(yt)&&d.current&&clearTimeout(d.current)},ht),d.current=setTimeout(()=>p(1),bt),()=>{l.current&&clearTimeout(l.current),d.current&&clearTimeout(d.current)}},[e,o,t,r,n,a,i])}var ve=require("react");function Ke({activeDropdownIndex:e,setActiveDropdownIndex:o,filteredOptions:t,selectOption:r,onSubmitRef:n,text:a,completedParams:i,isDropdownOpen:l,hasPlaceholder:d,placeholderText:g,suggestions:p,filterBaseRef:b,columns:h,setText:S,setCompletedParams:k,setSuggestions:x}){let v=(0,ve.useCallback)(()=>{let m=t.map((c,P)=>c.is_tappable?P:-1).filter(c=>c!==-1),f=m.filter(c=>c%h===0),s=m.filter(c=>c%h===1);return[...f,...s]},[t,h]);return{handleKeyDown:(0,ve.useCallback)(m=>{let f=v();switch(m.key){case"ArrowDown":{if(m.preventDefault(),f.length===0)return;let s=f.indexOf(e),c=s<f.length-1?s+1:0;o(f[c]);break}case"ArrowUp":{if(m.preventDefault(),f.length===0)return;let s=f.indexOf(e),c=s>0?s-1:f.length-1;o(f[c]);break}case"ArrowRight":{if(e<0)break;if(e%h===0){let s=e+1;s<t.length&&t[s]?.is_tappable&&(m.preventDefault(),o(s))}break}case"ArrowLeft":{if(e<0)break;if(e%h===1){let s=e-1;s>=0&&t[s]?.is_tappable&&(m.preventDefault(),o(s))}break}case"Enter":{if(m.preventDefault(),e>=0&&t[e]?.is_tappable)r(t[e]);else if(n.current){let{rawQuery:s,completedParams:c}=G(a,i),P={query:a.trim(),raw_query:s,completed_params:c};n.current(P)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)m.preventDefault(),r(t[e]);else if(l){let s=t.find(c=>c.is_tappable);s&&(m.preventDefault(),r(s))}else if(!a&&d){m.preventDefault();let s=p.find(c=>c.type==="placeholder");s?(S(g),b.current=g.length,k(c=>[...c,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:g,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),x(c=>c.filter(P=>P!==s))):(S(g),b.current=g.length)}break}case"Escape":o(-1);break}},[e,h,i,t,b,v,d,l,n,g,r,o,k,x,S,p,a]),getTappableIndices:v}}var ie=require("react");function je({completedParams:e,suggestions:o,setCompletedParams:t,setSuggestions:r,setActiveDropdownIndex:n,filterBaseRef:a,pillTappedRef:i}){let l=(0,ie.useCallback)(p=>{let b=o.filter(x=>x.type!=="placeholder");if(p<0||p>=b.length)return;let h=b[p],S=b.filter((x,v)=>v!==p),k=o.filter(x=>x.type==="placeholder");r([...k,h,...S]),i.current=!0,n(-1)},[o,r,n,i]),d=(0,ie.useCallback)(()=>{if(e.length===0)return;let p=e[e.length-1],b={type:p.suggestionType,text:p.suggestionPlaceholder,required:!0,options:p.options};t(h=>h.slice(0,-1)),r(h=>[b,...h]),n(-1)},[e,t,r,n]),g=(0,ie.useCallback)(p=>{let b={type:p.suggestionType,text:p.suggestionPlaceholder,required:!0,options:p.options};return{apply:h=>{h(S=>{let k=0;for(let x of e){let v=S.indexOf(x.text,k);if(v!==-1){if(x.id===p.id){let A=S.slice(0,v),m=S.slice(v+p.text.length),f=(A+m).replace(/ {2,}/g," ");return a.current=Math.min(a.current,f.length),f}k=v+x.text.length}}return S}),t(S=>S.filter(k=>k.id!==p.id)),r(S=>[b,...S]),n(-1),i.current=!0}}},[e,t,r,n,a,i]);return{setActivePill:l,removeLastParam:d,reEditParam:g}}function ce({onSubmit:e,onError:o,optionOverrides:t,maskCompletedText:r,placeholder:n,apiConfig:a,columns:i=2,value:l,completedParams:d,onChange:g,onParamsChange:p}){let b=l!==void 0,h=d!==void 0,[S,k]=(0,u.useState)(""),[x,v]=(0,u.useState)([]),[A,m]=(0,u.useState)([]),[f,s]=(0,u.useState)(-1),c=b?l:S,P=h?d:x,U=(0,u.useRef)(e);U.current=e;let F=(0,u.useRef)(g);F.current=g;let z=(0,u.useRef)(p);z.current=p;let $=(0,u.useRef)(l);$.current=l;let K=(0,u.useRef)(d);K.current=d;let R=(0,u.useCallback)(y=>{if(typeof y=="function")if(b){let w=y($.current??"");F.current?.(w)}else k(w=>{let Q=y(w);return F.current?.(Q),Q});else b||k(y),F.current?.(y)},[b]),E=(0,u.useCallback)(y=>{if(typeof y=="function")if(h){let w=y(K.current??[]);z.current?.(w)}else v(w=>{let Q=y(w);return z.current?.(Q),Q});else h||v(y),z.current?.(y)},[h]),q=(0,u.useRef)(o);q.current=o;let H=(0,u.useRef)(t);H.current=t;let Y=(0,u.useRef)(r);Y.current=r;let O=(0,u.useRef)(a);O.current=a;let _=(0,u.useRef)(c);_.current=c;let B=(0,u.useRef)(A);B.current=A;let M=(0,u.useRef)(0),ee=(0,u.useRef)(!1),Ae=(0,u.useRef)(!1),le=(0,u.useId)(),{doFetch:ue,isLoading:Ce,error:qe,isReady:Be,lastRawQueryRef:pe}=Fe({textRef:_,suggestionsRef:B,filterBaseRef:M,maskCompletedTextRef:Y,apiConfigRef:O,optionOverridesRef:H,onErrorRef:q,setCompletedParams:E,setSuggestions:m,setActiveDropdownIndex:s});$e({text:c,completedParams:P,doFetch:ue,filterBaseRef:M,skipNextFetchRef:Ae,suggestionsRef:B,lastRawQueryRef:pe});let Qe=(0,u.useMemo)(()=>Me(c,P),[c,P]);M.current=Math.min(M.current,c.length);let me=c.slice(M.current),de=(0,u.useMemo)(()=>A.filter(w=>w.type==="placeholder").map(w=>w.text).join(" ")||n||"",[A,n]),te=(0,u.useMemo)(()=>A.filter(y=>y.type!=="placeholder"),[A]),C=te[0],ke=C?t?.[C.type]:void 0,we=C?ke?ke(me.trim()):C.options??[]:[],fe=(0,u.useMemo)(()=>se(we,me),[we,me]),Oe=de.length>0,ge=!Ce&&fe.length>0&&(!!c||ee.current||!Oe),Ie=(0,u.useCallback)(y=>{if(!C)return;let w={id:crypto.randomUUID(),placeholder:"",type:C.type,text:y.text,kind:y.kind,suggestionType:C.type,suggestionPlaceholder:C.text,options:C.options,metadata:y.metadata},Q=M.current,L=_.current.slice(0,Q);if(L.length>0&&!L.endsWith(" ")){let N=L.split(/\s+/).pop()??"";N&&y.text.toLowerCase().startsWith(N.toLowerCase())&&(L=L.slice(0,L.length-N.length))}let he=L.length>0&&L[L.length-1]!==" ",V=L+(he?" ":"")+y.text+" ";R(V),M.current=V.length,E(N=>[...N,w]),m(N=>N.filter(J=>J!==C)),ee.current=!1,s(-1),te.length-1>0&&(Ae.current=!0)},[C,te,R,E]),He=(0,u.useCallback)(y=>{let w=y.target.value,L=w.length>0&&!y.nativeEvent?.isComposing&&w[0]!==w[0].toUpperCase()?w[0].toUpperCase()+w.slice(1):w;R(L),ee.current=!1,s(-1);let{valid:he,invalid:V}=Ue(L,P);if(V.length>0){E(()=>he);for(let X of V)m(N=>[{type:X.suggestionType,text:X.suggestionPlaceholder,required:!0,options:X.options},...N])}if(C&&V.length===0){let X=L.slice(M.current),N=Z(C.options,X);N&&(E(J=>[...J,{id:crypto.randomUUID(),placeholder:"",type:C.type,text:N.text,kind:N.kind,suggestionType:C.type,suggestionPlaceholder:C.text,options:C.options,metadata:N.metadata}]),m(J=>J.filter(Ye=>Ye!==C)))}},[P,C,R,E]),{handleKeyDown:Ve}=Ke({activeDropdownIndex:f,setActiveDropdownIndex:s,filteredOptions:fe,selectOption:Ie,onSubmitRef:U,text:c,completedParams:P,isDropdownOpen:ge,hasPlaceholder:Oe,placeholderText:de,suggestions:A,filterBaseRef:M,columns:i,setText:R,setCompletedParams:E,setSuggestions:m}),oe=je({completedParams:P,suggestions:A,setCompletedParams:E,setSuggestions:m,setActiveDropdownIndex:s,filterBaseRef:M,pillTappedRef:ee}),Xe=(0,u.useCallback)(y=>{oe.reEditParam(y).apply(R)},[oe,R]),We=(0,u.useCallback)(()=>{R(""),E(()=>[]),m([]),s(-1),M.current=0,pe.current="",ue("",[])},[ue,R,E,pe]),Ge=f>=0?`${le}-option-${f}`:void 0;return{completedParams:P,suggestionPills:te,setActivePill:oe.setActivePill,removeLastParam:oe.removeLastParam,reEditParam:Xe,segments:Qe,suggestions:A,activeIndex:f,isReady:Be,isLoading:Ce,error:qe,inputProps:{value:c,placeholder:de||void 0,onChange:He,onKeyDown:Ve,role:"combobox","aria-expanded":ge,"aria-activedescendant":Ge,"aria-autocomplete":"list","aria-controls":le},reset:We,dropdownProps:{suggestions:C?[{...C,options:fe}]:[],activeIndex:f,onSelect:Ie,onHighlight:s,isOpen:ge,id:le}}}var I=require("react/jsx-runtime"),ze=(0,D.forwardRef)(function({onSubmit:o,onError:t,optionOverrides:r,maskCompletedText:n,placeholder:a,className:i,apiConfig:l,columns:d,value:g,completedParams:p,onChange:b,onParamsChange:h},S){let k=(0,D.useRef)(null),[x,v]=(0,D.useState)(!1),A=(0,D.useRef)(()=>{}),m=(0,D.useRef)(void 0);(0,D.useEffect)(()=>(k.current?.focus(),()=>clearTimeout(m.current)),[]);let{completedParams:f,suggestionPills:s,setActivePill:c,segments:P,inputProps:U,dropdownProps:F,reset:z}=ce({onSubmit:O=>A.current(O),onError:t,optionOverrides:r,maskCompletedText:n,placeholder:a,apiConfig:l,columns:d,value:g,completedParams:p,onChange:b,onParamsChange:h});(0,D.useImperativeHandle)(S,()=>({focus:()=>k.current?.focus(),reset:z}),[z]);let $=()=>{k.current?.focus()},K=!!U.value||f.length>0,R=(0,D.useCallback)(()=>{if(!K)return;let{rawQuery:O,completedParams:_}=G(U.value,f);o({query:U.value.trim(),raw_query:O,completed_params:_}),z(),v(!0),clearTimeout(m.current),m.current=setTimeout(()=>v(!1),3e3)},[K,U.value,f,o,z]);A.current=R;let{onChange:E,placeholder:q,...H}=U,Y=!U.value;return(0,I.jsxs)("div",{className:`${j.container} ${i??""}`,children:[(0,I.jsx)("div",{className:`${j.checkmark} ${x?j.checkmarkVisible:""}`,children:(0,I.jsxs)("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[(0,I.jsx)("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),(0,I.jsx)("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:j.checkmarkPath})]})}),(0,I.jsx)(re,{...F}),(0,I.jsxs)("div",{className:j.inputWrapper,onClick:$,children:[(0,I.jsxs)("div",{className:j.editorArea,children:[(0,I.jsxs)("div",{className:j.sizerContent,"aria-hidden":"true",children:[Y&&q?(0,I.jsxs)("span",{className:j.placeholderText,children:[q," "]}):(0,I.jsxs)("span",{className:j.sizerText,children:[P.map((O,_)=>(0,I.jsx)("span",{children:O.value},`${_}-${O.type}`)),P.length===0&&"\xA0"]})," ",(0,I.jsx)(Ee,{pills:s,activePillIndex:0,onSelectPill:c})]}),(0,I.jsx)("textarea",{ref:k,className:j.textarea,rows:1,onChange:E,...H})]}),(0,I.jsx)("button",{type:"button",className:j.submitButton,disabled:!K,onClick:O=>{O.stopPropagation(),R()},"aria-label":"Submit",children:(0,I.jsx)("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:(0,I.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 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});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|