@pro6pp/infer-core 0.0.2-beta.8 → 0.1.0-beta.17

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/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  /**
2
2
  * Supported ISO 3166-1 alpha-2 country codes.
3
3
  */
4
- type CountryCode = 'NL' | 'DE';
4
+ type CountryCode = 'NL' | 'DE' | 'BE' | 'AT' | 'DK' | (string & {});
5
+ /**
6
+ * Supported language codes for address labels.
7
+ */
8
+ type LanguageCode = 'nl' | 'fr' | 'de' | (string & {});
5
9
  /**
6
10
  * The current step in the address inference process.
7
11
  * - `empty`: No input yet.
@@ -9,13 +13,13 @@ type CountryCode = 'NL' | 'DE';
9
13
  * - `street`: User is selecting a street.
10
14
  * - `city`: User is selecting a city.
11
15
  * - `postcode`: User is entering a postcode.
12
- * - `house_number`: User is entering a house number.
13
- * - `house_number_first`: Specialized mode where number is entered before street.
14
- * - `addition`: Selecting a house number addition (e.g., 'A', 'III').
16
+ * - `street_number`: User is entering a street number.
17
+ * - `street_number_first`: Specialized mode where number is entered before street.
18
+ * - `addition`: Selecting a street number addition (e.g., 'A', 'III').
15
19
  * - `direct`: Direct address hit (often via postcode).
16
20
  * - `final`: A complete, valid address has been identified.
17
21
  */
18
- type Stage = 'empty' | 'mixed' | 'street' | 'city' | 'postcode' | 'house_number' | 'house_number_first' | 'addition' | 'direct' | 'final';
22
+ type Stage = 'empty' | 'mixed' | 'street' | 'city' | 'postcode' | 'street_number' | 'street_number_first' | 'addition' | 'direct' | 'final';
19
23
  /**
20
24
  * The standardized address object returned upon a successful final selection.
21
25
  */
@@ -24,15 +28,11 @@ interface AddressValue {
24
28
  street: string;
25
29
  /** The name of the city/locality. */
26
30
  city: string;
27
- /** The house number (formatted). */
31
+ /** The street number. */
28
32
  street_number?: string | number;
29
- /** The house number (numeric part). */
30
- house_number?: string | number;
31
33
  /** The postal code. */
32
34
  postcode?: string;
33
- /** The full postal code including letters (country-specific). */
34
- postcode_full?: string;
35
- /** The house number addition or suffix. */
35
+ /** The street number addition or suffix. */
36
36
  addition?: string;
37
37
  /** Allow for extra fields if API expands. */
38
38
  [key: string]: unknown;
@@ -68,6 +68,8 @@ interface InferState {
68
68
  suggestions: InferResult[];
69
69
  /** Flag indicating if the current selection is a complete, valid address. */
70
70
  isValid: boolean;
71
+ /** The complete address object if valid, otherwise null. */
72
+ value: AddressValue | null;
71
73
  /** Flag indicating if the last API request failed. */
72
74
  isError: boolean;
73
75
  /** Flag indicating if a network request is currently in progress. */
@@ -126,6 +128,12 @@ interface InferConfig {
126
128
  * @default 0
127
129
  */
128
130
  maxRetries?: number;
131
+ /**
132
+ * Language code for response labels.
133
+ * Affects the language of returned address labels.
134
+ * Only applicable for BE country code.
135
+ */
136
+ language?: LanguageCode;
129
137
  /**
130
138
  * Callback triggered whenever the internal state (suggestions, loading status, etc.) updates.
131
139
  */
@@ -137,6 +145,13 @@ interface InferConfig {
137
145
  */
138
146
  onSelect?: (selection: AddressValue | string | null) => void;
139
147
  }
148
+ /**
149
+ * Represents a segment of text that should be highlighted or left plain.
150
+ */
151
+ interface HighlightSegment {
152
+ text: string;
153
+ match: boolean;
154
+ }
140
155
 
141
156
  /**
142
157
  * The initial state of the address inference engine.
@@ -153,6 +168,7 @@ declare class InferCore {
153
168
  private baseLimit;
154
169
  private currentLimit;
155
170
  private maxRetries;
171
+ private language?;
156
172
  private fetcher;
157
173
  private onStateChange;
158
174
  private onSelect;
@@ -163,7 +179,6 @@ declare class InferCore {
163
179
  state: InferState;
164
180
  private abortController;
165
181
  private debouncedFetch;
166
- private isSelecting;
167
182
  /**
168
183
  * Initializes a new instance of the Infer engine.
169
184
  * @param config The configuration object including API keys and callbacks.
@@ -184,7 +199,7 @@ declare class InferCore {
184
199
  * Supports:
185
200
  * - `ArrowUp`/`ArrowDown`: Navigate through the suggestion list.
186
201
  * - `Enter`: Select the currently highlighted suggestion.
187
- * - `Space`: Automatically inserts a comma if a numeric house number is detected.
202
+ * - `Space`: Automatically inserts a comma if a numeric street number is detected.
188
203
  * @param event The keyboard event from the input element.
189
204
  */
190
205
  handleKeyDown(event: KeyboardEvent | {
@@ -205,6 +220,12 @@ declare class InferCore {
205
220
  private executeFetch;
206
221
  private retry;
207
222
  private mapResponseToState;
223
+ /**
224
+ * Reformats a suggestion's label based on the user's input order.
225
+ * If the suggestion has a structured value object, we reorder the label
226
+ * to match how the user typed the components.
227
+ */
228
+ private reformatSuggestionLabel;
208
229
  private updateQueryAndFetch;
209
230
  private replaceLastSegment;
210
231
  private getQueryPrefix;
@@ -214,6 +235,23 @@ declare class InferCore {
214
235
  private debounce;
215
236
  }
216
237
 
217
- declare const DEFAULT_STYLES = "\n .pro6pp-wrapper {\n position: relative;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n box-sizing: border-box;\n width: 100%;\n }\n .pro6pp-wrapper * {\n box-sizing: border-box;\n }\n .pro6pp-input {\n width: 100%;\n padding: 10px 12px;\n padding-right: 48px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 16px;\n line-height: 1.5;\n transition: border-color 0.2s, box-shadow 0.2s;\n }\n .pro6pp-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .pro6pp-input-addons {\n position: absolute;\n right: 6px;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n gap: 2px;\n pointer-events: none;\n }\n .pro6pp-input-addons > * {\n pointer-events: auto;\n }\n\n .pro6pp-clear-button {\n background: none;\n border: none;\n width: 28px;\n height: 28px;\n cursor: pointer;\n color: #a3a3a3;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: color 0.2s, background-color 0.2s, transform 0.1s;\n }\n .pro6pp-clear-button:hover {\n color: #1f2937;\n background-color: #f3f4f6;\n }\n .pro6pp-clear-button:active {\n transform: scale(0.92);\n }\n .pro6pp-clear-button svg {\n width: 18px;\n height: 18px;\n }\n\n .pro6pp-loader {\n width: 18px;\n height: 18px;\n margin: 0 4px;\n border: 2px solid #e0e0e0;\n border-top-color: #6b7280;\n border-radius: 50%;\n animation: pro6pp-spin 0.6s linear infinite;\n flex-shrink: 0;\n }\n\n .pro6pp-dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n z-index: 9999;\n margin-top: 4px;\n background: white;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n max-height: 300px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n }\n .pro6pp-list {\n list-style: none !important;\n padding: 0 !important;\n margin: 0 !important;\n flex-grow: 1;\n }\n .pro6pp-item {\n padding: 12px 16px;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n align-items: center;\n color: #111827;\n font-size: 14px;\n line-height: 1.2;\n white-space: nowrap;\n overflow: hidden;\n }\n .pro6pp-item:hover, .pro6pp-item--active {\n background-color: #f9fafb;\n }\n .pro6pp-item__label {\n font-weight: 500;\n flex-shrink: 0;\n }\n .pro6pp-item__subtitle {\n font-size: 14px;\n color: #6b7280;\n overflow: hidden;\n text-overflow: ellipsis;\n flex-shrink: 1;\n }\n .pro6pp-item__chevron {\n margin-left: auto;\n display: flex;\n align-items: center;\n color: #9ca3af;\n padding-left: 8px;\n }\n .pro6pp-no-results {\n padding: 16px;\n color: #6b7280;\n font-size: 14px;\n text-align: center;\n }\n .pro6pp-load-more {\n width: 100%;\n padding: 10px;\n background: #f9fafb;\n border: none;\n border-top: 1px solid #e0e0e0;\n color: #3b82f6;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background-color 0.2s;\n flex-shrink: 0;\n }\n .pro6pp-load-more:hover {\n background-color: #f3f4f6;\n }\n\n @keyframes pro6pp-spin {\n to { transform: rotate(360deg); }\n }\n";
238
+ /**
239
+ * Splits text into matched and unmatched segments based on a fuzzy query sequence.
240
+ * Consecutive matched characters are merged into single segments for cleaner rendering.
241
+ */
242
+ declare function getHighlightSegments(text: string, query: string): HighlightSegment[];
243
+
244
+ /**
245
+ * Formats a label for display based on the user's input order.
246
+ * Components the user typed appear first (in their order),
247
+ * followed by components they didn't type (new info from API).
248
+ *
249
+ * @param query The user's current query string
250
+ * @param value The structured address value from the API
251
+ * @returns A formatted label string
252
+ */
253
+ declare function formatLabelByInputOrder(query: string, value: AddressValue): string;
254
+
255
+ declare const DEFAULT_STYLES = "\n .pro6pp-wrapper {\n position: relative;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n box-sizing: border-box;\n width: 100%;\n -webkit-tap-highlight-color: transparent;\n }\n .pro6pp-wrapper * {\n box-sizing: border-box;\n }\n .pro6pp-input {\n width: 100%;\n padding: 12px 14px;\n padding-right: 48px;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n font-size: 16px;\n line-height: 1.5;\n appearance: none;\n transition: border-color 0.2s, box-shadow 0.2s;\n }\n\n .pro6pp-input::placeholder {\n font-size: 16px;\n color: #a3a3a3;\n }\n\n .pro6pp-input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .pro6pp-input-addons {\n position: absolute;\n right: 4px;\n top: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n pointer-events: none;\n }\n .pro6pp-input-addons > * {\n pointer-events: auto;\n }\n\n .pro6pp-clear-button {\n background: none;\n border: none;\n width: 32px;\n height: 32px;\n cursor: pointer;\n color: #a3a3a3;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n transition: color 0.2s, background-color 0.2s;\n touch-action: manipulation;\n }\n\n @media (hover: hover) {\n .pro6pp-clear-button:hover {\n color: #1f2937;\n background-color: #f3f4f6;\n }\n }\n\n .pro6pp-clear-button:active {\n background-color: #f3f4f6;\n }\n\n .pro6pp-dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n margin-top: 4px;\n background: #ffffff;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n z-index: 9999;\n padding: 0;\n max-height: 280px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n }\n\n @media (max-height: 500px) {\n .pro6pp-dropdown {\n max-height: 180px;\n }\n }\n\n .pro6pp-list {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n }\n\n .pro6pp-item {\n padding: 12px 14px;\n cursor: pointer;\n display: flex;\n align-items: center;\n font-size: 15px;\n line-height: 1.4;\n color: #374151;\n border-bottom: 1px solid #f3f4f6;\n transition: background-color 0.1s;\n flex-shrink: 0;\n }\n\n .pro6pp-item:last-child {\n border-bottom: none;\n }\n\n @media (hover: hover) {\n .pro6pp-item:hover, .pro6pp-item--active {\n background-color: #f9fafb;\n }\n }\n\n .pro6pp-item:active {\n background-color: #f3f4f6;\n }\n\n .pro6pp-item__label {\n font-weight: 400;\n flex-shrink: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .pro6pp-item__label--match {\n font-weight: 520;\n }\n\n .pro6pp-item__label--unmatched {\n font-weight: 400;\n color: #4b5563;\n }\n\n .pro6pp-item__subtitle {\n color: #6b7280;\n flex-shrink: 0;\n }\n\n .pro6pp-item__chevron {\n color: #d1d5db;\n display: flex;\n align-items: center;\n margin-left: auto;\n padding-left: 8px;\n }\n\n .pro6pp-no-results {\n padding: 24px 16px;\n color: #6b7280;\n font-size: 15px;\n text-align: center;\n }\n\n .pro6pp-loader-item {\n padding: 10px 12px;\n color: #6b7280;\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background-color: #f9fafb;\n border-top: 1px solid #f3f4f6;\n }\n\n .pro6pp-mini-spinner {\n width: 14px;\n height: 14px;\n border: 2px solid #e5e7eb;\n border-top-color: #6b7280;\n border-radius: 50%;\n animation: pro6pp-spin 0.6s linear infinite;\n }\n\n @media (max-width: 640px) {\n .pro6pp-input {\n font-size: 16px;\n padding: 10px 12px;\n }\n .pro6pp-item {\n padding: 10px 12px;\n font-size: 14px;\n }\n }\n\n @keyframes pro6pp-spin {\n to { transform: rotate(360deg); }\n }\n";
218
256
 
219
- export { type AddressValue, type CountryCode, DEFAULT_STYLES, type Fetcher, INITIAL_STATE, type InferConfig, InferCore, type InferResult, type InferState, type Stage };
257
+ export { type AddressValue, type CountryCode, DEFAULT_STYLES, type Fetcher, type HighlightSegment, INITIAL_STATE, type InferConfig, InferCore, type InferResult, type InferState, type LanguageCode, type Stage, formatLabelByInputOrder, getHighlightSegments };
@@ -1,23 +1,31 @@
1
- "use strict";var Pro6PPCore=(()=>{var h=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var w=(a,e,t)=>e in a?h(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var C=(a,e)=>{for(var t in e)h(a,t,{get:e[t],enumerable:!0})},L=(a,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of v(e))!I.call(a,s)&&s!==t&&h(a,s,{get:()=>e[s],enumerable:!(i=y(e,s))||i.enumerable});return a};var T=a=>L(h({},"__esModule",{value:!0}),a);var l=(a,e,t)=>w(a,typeof e!="symbol"?e+"":e,t);var A={};C(A,{DEFAULT_STYLES:()=>S,INITIAL_STATE:()=>g,InferCore:()=>f});var d={API_URL:"https://api.pro6pp.nl/v2",LIMIT:20,DEBOUNCE_MS:150,MIN_DEBOUNCE_MS:50,MAX_RETRIES:0},x={DIGITS_1_3:/^[0-9]{1,3}$/},g={query:"",stage:null,cities:[],streets:[],suggestions:[],isValid:!1,isError:!1,isLoading:!1,hasMore:!1,selectedSuggestionIndex:-1},f=class{constructor(e){l(this,"country");l(this,"authKey");l(this,"explicitApiUrl");l(this,"baseLimit");l(this,"currentLimit");l(this,"maxRetries");l(this,"fetcher");l(this,"onStateChange");l(this,"onSelect");l(this,"state");l(this,"abortController",null);l(this,"debouncedFetch");l(this,"isSelecting",!1);this.country=e.country,this.authKey=e.authKey,this.explicitApiUrl=e.apiUrl,this.baseLimit=e.limit||d.LIMIT,this.currentLimit=this.baseLimit;let t=e.maxRetries!==void 0?e.maxRetries:d.MAX_RETRIES;this.maxRetries=Math.max(0,Math.min(t,10)),this.fetcher=e.fetcher||((r,o)=>fetch(r,o)),this.onStateChange=e.onStateChange||(()=>{}),this.onSelect=e.onSelect||(()=>{}),this.state={...g};let i=e.debounceMs!==void 0?e.debounceMs:d.DEBOUNCE_MS,s=Math.max(i,d.MIN_DEBOUNCE_MS);this.debouncedFetch=this.debounce(r=>this.executeFetch(r),s)}handleInput(e){if(this.isSelecting){this.isSelecting=!1;return}this.currentLimit=this.baseLimit;let t=this.state.stage==="final"&&e!==this.state.query;this.updateState({query:e,isValid:!1,isLoading:!!e.trim(),selectedSuggestionIndex:-1,hasMore:!1}),t&&this.onSelect(null),this.debouncedFetch(e)}loadMore(){this.state.isLoading||(this.currentLimit+=this.baseLimit,this.updateState({isLoading:!0}),this.executeFetch(this.state.query))}handleKeyDown(e){let t=e.target;if(!t)return;let i=this.state.cities.length+this.state.streets.length+this.state.suggestions.length;if(i>0){if(e.key==="ArrowDown"){e.preventDefault();let r=this.state.selectedSuggestionIndex+1;r>=i&&(r=0),this.updateState({selectedSuggestionIndex:r});return}if(e.key==="ArrowUp"){e.preventDefault();let r=this.state.selectedSuggestionIndex-1;r<0&&(r=i-1),this.updateState({selectedSuggestionIndex:r});return}if(e.key==="Enter"&&this.state.selectedSuggestionIndex>=0){e.preventDefault();let o=[...this.state.cities,...this.state.streets,...this.state.suggestions][this.state.selectedSuggestionIndex];o&&(this.selectItem(o),this.updateState({selectedSuggestionIndex:-1}));return}}let s=t.value;if(e.key===" "&&this.shouldAutoInsertComma(s)){e.preventDefault();let r=`${s.trim()}, `;this.updateQueryAndFetch(r)}}selectItem(e){this.debouncedFetch.cancel(),this.abortController&&this.abortController.abort();let t=typeof e=="string"?e:e.label,i=t;typeof e!="string"&&typeof e.value=="string"&&(i=e.value);let s=typeof e!="string"&&typeof e.value=="object"?e.value:void 0,r=!!s&&Object.keys(s).length>0;if(this.isSelecting=!0,this.state.stage==="final"||r){let u=t;if(s&&Object.keys(s).length>0){let{street:p,street_number:n,house_number:c,city:b}=s,m=n||c;p&&m&&b&&(u=`${p} ${m}, ${b}`)}return this.finishSelection(u,s),!0}let o=typeof e!="string"?e.subtitle:null;return this.processSelection(i,o),!1}shouldAutoInsertComma(e){if(!e.includes(",")&&x.DIGITS_1_3.test(e.trim()))return!0;if(this.state.stage==="house_number"){let i=this.getCurrentFragment(e);return x.DIGITS_1_3.test(i)}return!1}finishSelection(e,t){this.updateState({query:e,suggestions:[],cities:[],streets:[],isValid:!0,stage:"final",hasMore:!1}),this.onSelect(t||e)}processSelection(e,t){let{stage:i,query:s}=this.state,r=s;if(t&&(i==="city"||i==="street"||i==="mixed")){if(i==="city")r=`${t}, ${e}, `;else{let n=this.getQueryPrefix(s);r=n?`${n} ${e}, ${t}, `:`${e}, ${t}, `}this.updateQueryAndFetch(r);return}if(i==="direct"||i==="addition"){this.finishSelection(e);return}!s.includes(",")&&(i==="city"||i==="street"||i==="house_number_first")?r=`${e}, `:(r=this.replaceLastSegment(s,e),i!=="house_number"&&(r+=", ")),this.updateQueryAndFetch(r)}executeFetch(e,t=0){let i=(e||"").toString();if(!i.trim()){this.abortController?.abort(),this.resetState();return}t===0&&(this.updateState({isError:!1}),this.abortController&&this.abortController.abort(),this.abortController=new AbortController);let s=this.abortController?.signal,r=this.explicitApiUrl?this.explicitApiUrl:`${d.API_URL}/infer/${this.country.toLowerCase()}`,o=new URLSearchParams({country:this.country.toLowerCase(),query:i,limit:this.currentLimit.toString()});this.authKey&&o.set("authKey",this.authKey);let u=r.includes("?")?"&":"?",p=`${r}${u}${o.toString()}`;this.fetcher(p,{signal:s}).then(n=>{if(!n.ok){if(t<this.maxRetries&&(n.status>=500||n.status===429))return this.retry(e,t,s);throw new Error("Network error")}return n.json()}).then(n=>{n&&this.mapResponseToState(n)}).catch(n=>{if(n.name!=="AbortError"){if(t<this.maxRetries)return this.retry(e,t,s);this.updateState({isError:!0,isLoading:!1})}})}retry(e,t,i){if(i?.aborted)return;let s=Math.pow(2,t)*200;setTimeout(()=>{i?.aborted||this.executeFetch(e,t+1)},s)}mapResponseToState(e){let t={stage:e.stage,isLoading:!1},i=!1,s=null,r=e.suggestions||[],o=[],u=new Set;for(let n of r){let c=`${n.label}|${n.subtitle||""}|${JSON.stringify(n.value||{})}`;u.has(c)||(u.add(c),o.push(n))}let p=o.length+(e.cities?.length||0)+(e.streets?.length||0);if(t.hasMore=p>=this.currentLimit,e.stage==="mixed")t.cities=e.cities||[],t.streets=e.streets||[],t.suggestions=[];else{t.suggestions=o,t.cities=[],t.streets=[];let n=o[0],c=n&&typeof n.value=="object"&&n.value!==null&&Object.keys(n.value).length>0;(e.stage==="final"||c)&&o.length===1&&(i=!0,s=n)}if(t.isValid=e.stage==="final",i&&s){t.query=s.label,t.suggestions=[],t.cities=[],t.streets=[],t.isValid=!0,t.hasMore=!1,this.isSelecting=!0,this.updateState(t);let n=typeof s.value=="object"?s.value:s.label;this.onSelect(n)}else this.updateState(t)}updateQueryAndFetch(e){this.updateState({query:e,suggestions:[],cities:[],streets:[]}),this.updateState({isLoading:!0,isValid:!1,hasMore:!1}),this.debouncedFetch(e)}replaceLastSegment(e,t){let i=e.lastIndexOf(",");return i===-1?t:`${e.slice(0,i+1)} ${t}`.trim()}getQueryPrefix(e){let t=e.lastIndexOf(",");return t===-1?"":e.slice(0,t+1).trimEnd()}getCurrentFragment(e){return(e.split(",").slice(-1)[0]??"").trim()}resetState(){this.updateState({...g,query:this.state.query})}updateState(e){this.state={...this.state,...e},this.onStateChange(this.state)}debounce(e,t){let i,s=(...r)=>{i&&clearTimeout(i),i=setTimeout(()=>e.apply(this,r),t)};return s.cancel=()=>{i&&(clearTimeout(i),i=void 0)},s}};var S=`
1
+ "use strict";var Pro6PPCore=(()=>{var f=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var w=(n,t,e)=>t in n?f(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var A=(n,t)=>{for(var e in t)f(n,e,{get:t[e],enumerable:!0})},E=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of T(t))!L.call(n,r)&&r!==e&&f(n,r,{get:()=>t[r],enumerable:!(i=_(t,r))||i.enumerable});return n};var R=n=>E(f({},"__esModule",{value:!0}),n);var l=(n,t,e)=>w(n,typeof t!="symbol"?t+"":t,e);var U={};A(U,{DEFAULT_STYLES:()=>I,INITIAL_STATE:()=>y,InferCore:()=>S,formatLabelByInputOrder:()=>m,getHighlightSegments:()=>D});function v(n){return n.toLowerCase().trim()}function $(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function F(n,t){let e=v(n),i=v(t);if(i.includes(" "))return e.indexOf(i);let s=new RegExp(`(?:^|[,\\s])${$(i)}(?:$|[,\\s])`,"g").exec(e);if(s){let o=s.index,p=e[o];return p===","||p===" "?o+1:o}return-1}function M(n,t){let e=[],i=[];t.street&&i.push({value:t.street,type:"street"}),t.city&&i.push({value:t.city,type:"city"}),t.postcode&&i.push({value:t.postcode,type:"postcode"}),t.street_number!==void 0&&t.street_number!==null&&i.push({value:String(t.street_number),type:"street_number"}),t.addition&&i.push({value:t.addition,type:"addition"});for(let r of i){let s=F(n,r.value);s!==-1&&e.push({type:r.type,value:r.value,position:s})}return e.sort((r,s)=>r.position-s.position),e}function m(n,t){if(!t||!n)return"";let e=M(n,t),i=new Set(e.map(o=>o.type)),r=[];for(let o of e)r.push(o.value);let s=["street","street_number","addition","postcode","city"];for(let o of s){if(i.has(o))continue;let p;switch(o){case"street":p=t.street;break;case"city":p=t.city;break;case"street_number":p=t.street_number!==void 0?String(t.street_number):void 0;break;case"postcode":p=t.postcode;break;case"addition":p=t.addition;break}p&&r.push(p)}return r.join(", ")}var g={API_URL:"https://api.pro6pp.nl/v2",LIMIT:20,DEBOUNCE_MS:150,MIN_DEBOUNCE_MS:50,MAX_RETRIES:0},x={DIGITS_1_3:/^[0-9]{1,3}$/,STREET_NUMBER_PREFIX:/^(\d+)\s*,\s*$/},y={query:"",stage:null,cities:[],streets:[],suggestions:[],isValid:!1,value:null,isError:!1,isLoading:!1,hasMore:!1,selectedSuggestionIndex:-1},S=class{constructor(t){l(this,"country");l(this,"authKey");l(this,"explicitApiUrl");l(this,"baseLimit");l(this,"currentLimit");l(this,"maxRetries");l(this,"language");l(this,"fetcher");l(this,"onStateChange");l(this,"onSelect");l(this,"state");l(this,"abortController",null);l(this,"debouncedFetch");this.country=t.country,this.authKey=t.authKey,this.explicitApiUrl=t.apiUrl,this.baseLimit=t.limit||g.LIMIT,this.currentLimit=this.baseLimit,this.language=t.language;let e=t.maxRetries!==void 0?t.maxRetries:g.MAX_RETRIES;this.maxRetries=Math.max(0,Math.min(e,10)),this.fetcher=t.fetcher||((s,o)=>fetch(s,o)),this.onStateChange=t.onStateChange||(()=>{}),this.onSelect=t.onSelect||(()=>{}),this.state={...y};let i=t.debounceMs!==void 0?t.debounceMs:g.DEBOUNCE_MS,r=Math.max(i,g.MIN_DEBOUNCE_MS);this.debouncedFetch=this.debounce(s=>this.executeFetch(s),r)}handleInput(t){this.currentLimit=this.baseLimit;let e=this.state.stage==="final"&&t!==this.state.query;this.updateState({query:t,isValid:!1,value:null,isLoading:!!t.trim(),selectedSuggestionIndex:-1,hasMore:!1,stage:e?null:this.state.stage}),e&&this.onSelect(null),this.debouncedFetch(t)}loadMore(){this.state.isLoading||(this.currentLimit+=this.baseLimit,this.updateState({isLoading:!0}),this.executeFetch(this.state.query))}handleKeyDown(t){let e=t.target;if(!e)return;let i=this.state.cities.length+this.state.streets.length+this.state.suggestions.length;if(i>0){if(t.key==="ArrowDown"){t.preventDefault();let s=this.state.selectedSuggestionIndex+1;s>=i&&(s=0),this.updateState({selectedSuggestionIndex:s});return}if(t.key==="ArrowUp"){t.preventDefault();let s=this.state.selectedSuggestionIndex-1;s<0&&(s=i-1),this.updateState({selectedSuggestionIndex:s});return}if(t.key==="Enter"&&this.state.selectedSuggestionIndex>=0){t.preventDefault();let o=[...this.state.cities,...this.state.streets,...this.state.suggestions][this.state.selectedSuggestionIndex];o&&(this.selectItem(o),this.updateState({selectedSuggestionIndex:-1}));return}}let r=e.value;if(t.key===" "&&this.shouldAutoInsertComma(r)){t.preventDefault();let s=`${r.trim()}, `;this.updateQueryAndFetch(s)}}selectItem(t){this.debouncedFetch.cancel(),this.abortController&&this.abortController.abort();let e=typeof t=="string"?t:t.label,i=e;typeof t!="string"&&typeof t.value=="string"&&(i=t.value);let r=typeof t!="string"&&typeof t.value=="object"?t.value:void 0,s=!!r&&Object.keys(r).length>0;if(this.state.stage==="final"||s){let p=e;if(r&&Object.keys(r).length>0){let{street:c,street_number:a,postcode:d,city:u,addition:h}=r;if(c&&a&&u){let b=h?` ${h}`:"",C=d?`${d}, `:"";p=`${c}, ${a}${b}, ${C}${u}`}}return this.finishSelection(p,r),!0}let o=typeof t!="string"?t.subtitle:null;return this.processSelection(i,o),!1}shouldAutoInsertComma(t){if(!t.includes(",")&&x.DIGITS_1_3.test(t.trim()))return!0;if(this.state.stage==="street_number"){let i=this.getCurrentFragment(t);return x.DIGITS_1_3.test(i)}return!1}finishSelection(t,e){this.updateState({query:t,suggestions:[],cities:[],streets:[],isValid:!0,value:e||null,stage:"final",hasMore:!1}),this.onSelect(e||t)}processSelection(t,e){let{stage:i,query:r}=this.state,s=r;if(e&&(i==="city"||i==="street"||i==="mixed")){if(i==="city")s=`${e}, ${t}, `;else{let a=this.getQueryPrefix(r),d=!a||!a.includes(e),u=a;if(a&&e){let h=a.match(x.STREET_NUMBER_PREFIX);if(h){let b=h[1];e.startsWith(b)&&(u="")}}d?s=u?`${u} ${t}, ${e}, `:`${t}, ${e}, `:s=u?`${u} ${t}, `:`${t}, `}this.updateQueryAndFetch(s);return}if(i==="direct"||i==="addition"){this.finishSelection(t);return}!r.includes(",")&&(i==="city"||i==="street"||i==="street_number_first")?s=`${t}, `:(s=this.replaceLastSegment(r,t),i!=="street_number"&&(s+=", ")),this.updateQueryAndFetch(s)}executeFetch(t,e=0){let i=(t||"").toString();if(!i.trim()){this.abortController?.abort(),this.resetState();return}e===0&&(this.updateState({isError:!1}),this.abortController&&this.abortController.abort(),this.abortController=new AbortController);let r=this.abortController?.signal,s=this.explicitApiUrl?this.explicitApiUrl:`${g.API_URL}/infer/${this.country.toLowerCase()}`,o=new URLSearchParams({query:i,limit:this.currentLimit.toString()});this.explicitApiUrl&&o.append("country",this.country.toLowerCase()),this.authKey&&o.set("authKey",this.authKey),this.language&&o.set("language",this.language);let p=s.includes("?")?"&":"?",c=`${s}${p}${o.toString()}`;this.fetcher(c,{signal:r}).then(a=>{if(!a.ok){if(e<this.maxRetries&&(a.status>=500||a.status===429))return this.retry(t,e,r);throw new Error("Network error")}return a.json()}).then(a=>{a&&this.mapResponseToState(a)}).catch(a=>{if(a.name!=="AbortError"){if(e<this.maxRetries)return this.retry(t,e,r);this.updateState({isError:!0,isLoading:!1})}})}retry(t,e,i){if(i?.aborted)return;let r=Math.pow(2,e)*200;setTimeout(()=>{i?.aborted||this.executeFetch(t,e+1)},r)}mapResponseToState(t){let e={stage:t.stage,isLoading:!1},i=t.suggestions||[],r=[],s=new Set;for(let p of i){let c=`${p.label}|${p.subtitle||""}|${JSON.stringify(p.value||{})}`;if(!s.has(c)){s.add(c);let a=this.reformatSuggestionLabel(p);r.push(a)}}let o=r.length+(t.cities?.length||0)+(t.streets?.length||0);e.hasMore=o>=this.currentLimit,t.stage==="mixed"?(e.cities=t.cities||[],e.streets=t.streets||[],e.cities?.length===0&&e.streets?.length===0?e.suggestions=r:e.suggestions=[]):(e.suggestions=r,e.cities=[],e.streets=[]),e.isValid=t.stage==="final",this.updateState(e),e.isValid&&r.length===1&&this.selectItem(r[0])}reformatSuggestionLabel(t){if(!t.value||typeof t.value=="string")return t;let e=t.value;if(!e.street||!e.city)return t;let i=m(this.state.query,e);return i?{...t,label:i}:t}updateQueryAndFetch(t){this.updateState({query:t,suggestions:[],cities:[],streets:[],isValid:!1,value:null,isLoading:!0,hasMore:!1}),this.debouncedFetch(t)}replaceLastSegment(t,e){let i=t.lastIndexOf(",");return i===-1?e:`${t.slice(0,i+1)} ${e}`.trim()}getQueryPrefix(t){let e=t.lastIndexOf(",");return e===-1?"":t.slice(0,e+1).trimEnd()}getCurrentFragment(t){return(t.split(",").slice(-1)[0]??"").trim()}resetState(){this.updateState({...y,query:this.state.query})}updateState(t){this.state={...this.state,...t},this.onStateChange(this.state)}debounce(t,e){let i,r=(...s)=>{i&&clearTimeout(i),i=setTimeout(()=>t.apply(this,s),e)};return r.cancel=()=>{i&&(clearTimeout(i),i=void 0)},r}};function k(n){if(n.length===0)return n;let t=[];for(let e of n){let i=t[t.length-1];i&&i.match===e.match?i.text+=e.text:t.push({text:e.text,match:e.match})}return t}function D(n,t){if(!t||!n)return[{text:n,match:!1}];let e=[],i=n.toLowerCase(),r=t.toLowerCase(),s=0,o=0;for(let a=0;a<n.length;a++){if(!(s<t.length&&i[a]===r[s]))continue;a>o&&e.push({text:n.slice(o,a),match:!1}),e.push({text:n[a],match:!0}),s++,o=a+1}return o<n.length&&e.push({text:n.slice(o),match:!1}),s===t.length?k(e):[{text:n,match:!1}]}var I=`
2
2
  .pro6pp-wrapper {
3
3
  position: relative;
4
4
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
5
5
  box-sizing: border-box;
6
6
  width: 100%;
7
+ -webkit-tap-highlight-color: transparent;
7
8
  }
8
9
  .pro6pp-wrapper * {
9
10
  box-sizing: border-box;
10
11
  }
11
12
  .pro6pp-input {
12
13
  width: 100%;
13
- padding: 10px 12px;
14
+ padding: 12px 14px;
14
15
  padding-right: 48px;
15
16
  border: 1px solid #e0e0e0;
16
- border-radius: 4px;
17
+ border-radius: 8px;
17
18
  font-size: 16px;
18
19
  line-height: 1.5;
20
+ appearance: none;
19
21
  transition: border-color 0.2s, box-shadow 0.2s;
20
22
  }
23
+
24
+ .pro6pp-input::placeholder {
25
+ font-size: 16px;
26
+ color: #a3a3a3;
27
+ }
28
+
21
29
  .pro6pp-input:focus {
22
30
  outline: none;
23
31
  border-color: #3b82f6;
@@ -26,12 +34,11 @@
26
34
 
27
35
  .pro6pp-input-addons {
28
36
  position: absolute;
29
- right: 6px;
37
+ right: 4px;
30
38
  top: 0;
31
39
  bottom: 0;
32
40
  display: flex;
33
41
  align-items: center;
34
- gap: 2px;
35
42
  pointer-events: none;
36
43
  }
37
44
  .pro6pp-input-addons > * {
@@ -41,37 +48,27 @@
41
48
  .pro6pp-clear-button {
42
49
  background: none;
43
50
  border: none;
44
- width: 28px;
45
- height: 28px;
51
+ width: 32px;
52
+ height: 32px;
46
53
  cursor: pointer;
47
54
  color: #a3a3a3;
48
55
  display: flex;
49
56
  align-items: center;
50
57
  justify-content: center;
51
58
  border-radius: 50%;
52
- transition: color 0.2s, background-color 0.2s, transform 0.1s;
53
- }
54
- .pro6pp-clear-button:hover {
55
- color: #1f2937;
56
- background-color: #f3f4f6;
57
- }
58
- .pro6pp-clear-button:active {
59
- transform: scale(0.92);
59
+ transition: color 0.2s, background-color 0.2s;
60
+ touch-action: manipulation;
60
61
  }
61
- .pro6pp-clear-button svg {
62
- width: 18px;
63
- height: 18px;
62
+
63
+ @media (hover: hover) {
64
+ .pro6pp-clear-button:hover {
65
+ color: #1f2937;
66
+ background-color: #f3f4f6;
67
+ }
64
68
  }
65
69
 
66
- .pro6pp-loader {
67
- width: 18px;
68
- height: 18px;
69
- margin: 0 4px;
70
- border: 2px solid #e0e0e0;
71
- border-top-color: #6b7280;
72
- border-radius: 50%;
73
- animation: pro6pp-spin 0.6s linear infinite;
74
- flex-shrink: 0;
70
+ .pro6pp-clear-button:active {
71
+ background-color: #f3f4f6;
75
72
  }
76
73
 
77
74
  .pro6pp-dropdown {
@@ -79,80 +76,129 @@
79
76
  top: 100%;
80
77
  left: 0;
81
78
  right: 0;
82
- z-index: 9999;
83
79
  margin-top: 4px;
84
- background: white;
85
- border: 1px solid #e0e0e0;
86
- border-radius: 4px;
87
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
88
- max-height: 300px;
80
+ background: #ffffff;
81
+ border: 1px solid #e5e7eb;
82
+ border-radius: 6px;
83
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
84
+ z-index: 9999;
85
+ padding: 0;
86
+ max-height: 280px;
89
87
  overflow-y: auto;
90
88
  display: flex;
91
89
  flex-direction: column;
92
90
  }
91
+
92
+ @media (max-height: 500px) {
93
+ .pro6pp-dropdown {
94
+ max-height: 180px;
95
+ }
96
+ }
97
+
93
98
  .pro6pp-list {
94
- list-style: none !important;
95
- padding: 0 !important;
96
- margin: 0 !important;
97
- flex-grow: 1;
99
+ list-style: none;
100
+ margin: 0;
101
+ padding: 0;
102
+ width: 100%;
98
103
  }
104
+
99
105
  .pro6pp-item {
100
- padding: 12px 16px;
106
+ padding: 12px 14px;
101
107
  cursor: pointer;
102
108
  display: flex;
103
- flex-direction: row;
104
109
  align-items: center;
105
- color: #111827;
106
- font-size: 14px;
107
- line-height: 1.2;
108
- white-space: nowrap;
109
- overflow: hidden;
110
+ font-size: 15px;
111
+ line-height: 1.4;
112
+ color: #374151;
113
+ border-bottom: 1px solid #f3f4f6;
114
+ transition: background-color 0.1s;
115
+ flex-shrink: 0;
110
116
  }
111
- .pro6pp-item:hover, .pro6pp-item--active {
112
- background-color: #f9fafb;
117
+
118
+ .pro6pp-item:last-child {
119
+ border-bottom: none;
120
+ }
121
+
122
+ @media (hover: hover) {
123
+ .pro6pp-item:hover, .pro6pp-item--active {
124
+ background-color: #f9fafb;
125
+ }
113
126
  }
127
+
128
+ .pro6pp-item:active {
129
+ background-color: #f3f4f6;
130
+ }
131
+
114
132
  .pro6pp-item__label {
115
- font-weight: 500;
116
- flex-shrink: 0;
133
+ font-weight: 400;
134
+ flex-shrink: 1;
135
+ overflow: hidden;
136
+ text-overflow: ellipsis;
137
+ white-space: nowrap;
138
+ }
139
+
140
+ .pro6pp-item__label--match {
141
+ font-weight: 520;
142
+ }
143
+
144
+ .pro6pp-item__label--unmatched {
145
+ font-weight: 400;
146
+ color: #4b5563;
117
147
  }
148
+
118
149
  .pro6pp-item__subtitle {
119
- font-size: 14px;
120
150
  color: #6b7280;
121
- overflow: hidden;
122
- text-overflow: ellipsis;
123
- flex-shrink: 1;
151
+ flex-shrink: 0;
124
152
  }
153
+
125
154
  .pro6pp-item__chevron {
126
- margin-left: auto;
155
+ color: #d1d5db;
127
156
  display: flex;
128
157
  align-items: center;
129
- color: #9ca3af;
158
+ margin-left: auto;
130
159
  padding-left: 8px;
131
160
  }
161
+
132
162
  .pro6pp-no-results {
133
- padding: 16px;
163
+ padding: 24px 16px;
134
164
  color: #6b7280;
135
- font-size: 14px;
165
+ font-size: 15px;
136
166
  text-align: center;
137
167
  }
138
- .pro6pp-load-more {
139
- width: 100%;
140
- padding: 10px;
141
- background: #f9fafb;
142
- border: none;
143
- border-top: 1px solid #e0e0e0;
144
- color: #3b82f6;
145
- font-size: 13px;
146
- font-weight: 600;
147
- cursor: pointer;
148
- transition: background-color 0.2s;
149
- flex-shrink: 0;
168
+
169
+ .pro6pp-loader-item {
170
+ padding: 10px 12px;
171
+ color: #6b7280;
172
+ font-size: 0.875rem;
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ gap: 8px;
177
+ background-color: #f9fafb;
178
+ border-top: 1px solid #f3f4f6;
150
179
  }
151
- .pro6pp-load-more:hover {
152
- background-color: #f3f4f6;
180
+
181
+ .pro6pp-mini-spinner {
182
+ width: 14px;
183
+ height: 14px;
184
+ border: 2px solid #e5e7eb;
185
+ border-top-color: #6b7280;
186
+ border-radius: 50%;
187
+ animation: pro6pp-spin 0.6s linear infinite;
188
+ }
189
+
190
+ @media (max-width: 640px) {
191
+ .pro6pp-input {
192
+ font-size: 16px;
193
+ padding: 10px 12px;
194
+ }
195
+ .pro6pp-item {
196
+ padding: 10px 12px;
197
+ font-size: 14px;
198
+ }
153
199
  }
154
200
 
155
201
  @keyframes pro6pp-spin {
156
202
  to { transform: rotate(360deg); }
157
203
  }
158
- `;return T(A);})();
204
+ `;return R(U);})();