@pro6pp/infer-core 0.0.2-beta.1 → 0.0.2-beta.11

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.js CHANGED
@@ -1 +1,211 @@
1
- "use strict";var o=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var S=(r,t,e)=>t in r?o(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var m=(r,t)=>{for(var e in t)o(r,e,{get:t[e],enumerable:!0})},v=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of g(t))!f.call(r,i)&&i!==e&&o(r,i,{get:()=>t[i],enumerable:!(s=p(t,i))||s.enumerable});return r};var y=r=>v(o({},"__esModule",{value:!0}),r);var a=(r,t,e)=>S(r,typeof t!="symbol"?t+"":t,e);var I={};m(I,{INITIAL_STATE:()=>l,InferCore:()=>h});module.exports=y(I);var u={API_URL:"https://api.pro6pp.nl/v2",LIMIT:1e3,DEBOUNCE_MS:300},d={DIGITS_1_3:/^[0-9]{1,3}$/},l={query:"",stage:null,cities:[],streets:[],suggestions:[],isValid:!1,isError:!1,isLoading:!1},h=class{constructor(t){a(this,"country");a(this,"authKey");a(this,"apiUrl");a(this,"limit");a(this,"fetcher");a(this,"onStateChange");a(this,"onSelect");a(this,"state");a(this,"abortController",null);a(this,"debouncedFetch");this.country=t.country,this.authKey=t.authKey,this.apiUrl=t.apiUrl||u.API_URL,this.limit=t.limit||u.LIMIT,this.fetcher=t.fetcher||((e,s)=>fetch(e,s)),this.onStateChange=t.onStateChange||(()=>{}),this.onSelect=t.onSelect||(()=>{}),this.state={...l},this.debouncedFetch=this.debounce(e=>this.executeFetch(e),u.DEBOUNCE_MS)}handleInput(t){this.updateState({query:t,isValid:!1,isLoading:!!t.trim()}),this.state.stage==="final"&&this.onSelect(null),this.debouncedFetch(t)}handleKeyDown(t){let s=t.target.value;if(t.key===" "&&this.shouldAutoInsertComma(s)){t.preventDefault();let i=`${s.trim()}, `;this.updateQueryAndFetch(i)}}selectItem(t){let e=typeof t=="string"?t:t.label,s=typeof t!="string"?t.value:void 0,i=typeof t!="string"?t.subtitle:null;if(this.state.stage==="final"){this.finishSelection(e,s);return}this.processSelection(e,i)}shouldAutoInsertComma(t){if(!t.includes(",")&&d.DIGITS_1_3.test(t.trim()))return!0;if(this.state.stage==="house_number"){let s=this.getCurrentFragment(t);return d.DIGITS_1_3.test(s)}return!1}finishSelection(t,e){this.updateState({query:t,suggestions:[],cities:[],streets:[],isValid:!0}),this.onSelect(e||t)}processSelection(t,e){let{stage:s,query:i}=this.state,n=i;if(e&&(s==="city"||s==="street"||s==="mixed")){if(s==="city")n=`${e}, ${t}, `;else{let c=this.getQueryPrefix(i);n=c?`${c} ${t}, ${e}, `:`${t}, ${e}, `}this.updateQueryAndFetch(n);return}if(s==="direct"||s==="addition"){this.finishSelection(t),this.handleInput(t);return}!i.includes(",")&&(s==="city"||s==="street"||s==="house_number_first")?n=`${t}, `:(n=this.replaceLastSegment(i,t),s!=="house_number"&&(n+=", ")),this.updateQueryAndFetch(n)}executeFetch(t){let e=(t||"").toString();if(!e.trim()){this.abortController?.abort(),this.resetState();return}this.updateState({isError:!1}),this.abortController&&this.abortController.abort(),this.abortController=new AbortController;let s=new URL(`${this.apiUrl}/infer/${this.country.toLowerCase()}`),i={authKey:this.authKey,query:e,limit:this.limit.toString()};s.search=new URLSearchParams(i).toString(),this.fetcher(s.toString(),{signal:this.abortController.signal}).then(n=>{if(!n.ok)throw new Error("Network error");return n.json()}).then(n=>this.mapResponseToState(n)).catch(n=>{n.name!=="AbortError"&&this.updateState({isError:!0,isLoading:!1})})}mapResponseToState(t){let e={stage:t.stage,isLoading:!1};t.stage==="mixed"?(e.cities=t.cities||[],e.streets=t.streets||[],e.suggestions=[]):(e.suggestions=t.suggestions||[],e.cities=[],e.streets=[]),e.isValid=t.stage==="final",this.updateState(e)}updateQueryAndFetch(t){this.updateState({query:t,suggestions:[],cities:[],streets:[]}),this.handleInput(t)}replaceLastSegment(t,e){let s=t.lastIndexOf(",");return s===-1?e:`${t.slice(0,s+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({...l,query:this.state.query})}updateState(t){this.state={...this.state,...t},this.onStateChange(this.state)}debounce(t,e){let s;return(...i)=>{s&&clearTimeout(s),s=setTimeout(()=>t.apply(this,i),e)}}};0&&(module.exports={INITIAL_STATE,InferCore});
1
+ var x=Object.defineProperty;var S=(a,t,e)=>t in a?x(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var l=(a,t,e)=>S(a,typeof t!="symbol"?t+"":t,e);var c={API_URL:"https://api.pro6pp.nl/v2",LIMIT:20,DEBOUNCE_MS:150,MIN_DEBOUNCE_MS:50,MAX_RETRIES:0},g={DIGITS_1_3:/^[0-9]{1,3}$/},f={query:"",stage:null,cities:[],streets:[],suggestions:[],isValid:!1,isError:!1,isLoading:!1,hasMore:!1,selectedSuggestionIndex:-1},m=class{constructor(t){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");this.country=t.country,this.authKey=t.authKey,this.explicitApiUrl=t.apiUrl,this.baseLimit=t.limit||c.LIMIT,this.currentLimit=this.baseLimit;let e=t.maxRetries!==void 0?t.maxRetries:c.MAX_RETRIES;this.maxRetries=Math.max(0,Math.min(e,10)),this.fetcher=t.fetcher||((r,n)=>fetch(r,n)),this.onStateChange=t.onStateChange||(()=>{}),this.onSelect=t.onSelect||(()=>{}),this.state={...f};let i=t.debounceMs!==void 0?t.debounceMs:c.DEBOUNCE_MS,s=Math.max(i,c.MIN_DEBOUNCE_MS);this.debouncedFetch=this.debounce(r=>this.executeFetch(r),s)}handleInput(t){this.currentLimit=this.baseLimit;let e=this.state.stage==="final"&&t!==this.state.query;this.updateState({query:t,isValid:!1,isLoading:!!t.trim(),selectedSuggestionIndex:-1,hasMore:!1}),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 r=this.state.selectedSuggestionIndex+1;r>=i&&(r=0),this.updateState({selectedSuggestionIndex:r});return}if(t.key==="ArrowUp"){t.preventDefault();let r=this.state.selectedSuggestionIndex-1;r<0&&(r=i-1),this.updateState({selectedSuggestionIndex:r});return}if(t.key==="Enter"&&this.state.selectedSuggestionIndex>=0){t.preventDefault();let n=[...this.state.cities,...this.state.streets,...this.state.suggestions][this.state.selectedSuggestionIndex];n&&(this.selectItem(n),this.updateState({selectedSuggestionIndex:-1}));return}}let s=e.value;if(t.key===" "&&this.shouldAutoInsertComma(s)){t.preventDefault();let r=`${s.trim()}, `;this.updateQueryAndFetch(r)}}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 s=typeof t!="string"&&typeof t.value=="object"?t.value:void 0,r=!!s&&Object.keys(s).length>0;if(this.state.stage==="final"||r){let p=e;if(s&&Object.keys(s).length>0){let{street:u,street_number:o,city:d,addition:h}=s;if(u&&o&&d){let b=h?` ${h}`:"";p=`${u} ${o}${b}, ${d}`}}return this.finishSelection(p,s),!0}let n=typeof t!="string"?t.subtitle:null;return this.processSelection(i,n),!1}shouldAutoInsertComma(t){if(!t.includes(",")&&g.DIGITS_1_3.test(t.trim()))return!0;if(this.state.stage==="street_number"){let i=this.getCurrentFragment(t);return g.DIGITS_1_3.test(i)}return!1}finishSelection(t,e){this.updateState({query:t,suggestions:[],cities:[],streets:[],isValid:!0,stage:"final",hasMore:!1}),this.onSelect(e||t)}processSelection(t,e){let{stage:i,query:s}=this.state,r=s;if(e&&(i==="city"||i==="street"||i==="mixed")){if(i==="city")r=`${e}, ${t}, `;else{let o=this.getQueryPrefix(s);!o||!o.includes(e)?r=o?`${o} ${t}, ${e}, `:`${t}, ${e}, `:r=o?`${o} ${t}, `:`${t}, `}this.updateQueryAndFetch(r);return}if(i==="direct"||i==="addition"){this.finishSelection(t);return}!s.includes(",")&&(i==="city"||i==="street"||i==="street_number_first")?r=`${t}, `:(r=this.replaceLastSegment(s,t),i!=="street_number"&&(r+=", ")),this.updateQueryAndFetch(r)}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 s=this.abortController?.signal,r=this.explicitApiUrl?this.explicitApiUrl:`${c.API_URL}/infer/${this.country.toLowerCase()}`,n=new URLSearchParams({country:this.country.toLowerCase(),query:i,limit:this.currentLimit.toString()});this.authKey&&n.set("authKey",this.authKey);let p=r.includes("?")?"&":"?",u=`${r}${p}${n.toString()}`;this.fetcher(u,{signal:s}).then(o=>{if(!o.ok){if(e<this.maxRetries&&(o.status>=500||o.status===429))return this.retry(t,e,s);throw new Error("Network error")}return o.json()}).then(o=>{o&&this.mapResponseToState(o)}).catch(o=>{if(o.name!=="AbortError"){if(e<this.maxRetries)return this.retry(t,e,s);this.updateState({isError:!0,isLoading:!1})}})}retry(t,e,i){if(i?.aborted)return;let s=Math.pow(2,e)*200;setTimeout(()=>{i?.aborted||this.executeFetch(t,e+1)},s)}mapResponseToState(t){let e={stage:t.stage,isLoading:!1},i=t.suggestions||[],s=[],r=new Set;for(let p of i){let u=`${p.label}|${p.subtitle||""}|${JSON.stringify(p.value||{})}`;r.has(u)||(r.add(u),s.push(p))}let n=s.length+(t.cities?.length||0)+(t.streets?.length||0);e.hasMore=n>=this.currentLimit,t.stage==="mixed"?(e.cities=t.cities||[],e.streets=t.streets||[],e.suggestions=[]):(e.suggestions=s,e.cities=[],e.streets=[]),e.isValid=t.stage==="final",this.updateState(e),e.isValid&&s.length===1&&this.selectItem(s[0])}updateQueryAndFetch(t){this.updateState({query:t,suggestions:[],cities:[],streets:[]}),this.updateState({isLoading:!0,isValid:!1,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({...f,query:this.state.query})}updateState(t){this.state={...this.state,...t},this.onStateChange(this.state)}debounce(t,e){let i,s=(...r)=>{i&&clearTimeout(i),i=setTimeout(()=>t.apply(this,r),e)};return s.cancel=()=>{i&&(clearTimeout(i),i=void 0)},s}};function w(a,t){if(!t||!a)return[{text:a,match:!1}];let e=[],i=a.toLowerCase(),s=t.toLowerCase(),r=0,n=0;for(let o=0;o<a.length;o++){if(!(r<t.length&&i[o]===s[r]))continue;o>n&&e.push({text:a.slice(n,o),match:!1}),e.push({text:a[o],match:!0}),r++,n=o+1}return n<a.length&&e.push({text:a.slice(n),match:!1}),r===t.length?e:[{text:a,match:!1}]}var y=`
2
+ .pro6pp-wrapper {
3
+ position: relative;
4
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
5
+ box-sizing: border-box;
6
+ width: 100%;
7
+ -webkit-tap-highlight-color: transparent;
8
+ }
9
+ .pro6pp-wrapper * {
10
+ box-sizing: border-box;
11
+ }
12
+ .pro6pp-input {
13
+ width: 100%;
14
+ padding: 12px 14px;
15
+ padding-right: 48px;
16
+ border: 1px solid #e0e0e0;
17
+ border-radius: 8px;
18
+ font-size: 16px;
19
+ line-height: 1.5;
20
+ appearance: none;
21
+ transition: border-color 0.2s, box-shadow 0.2s;
22
+ }
23
+
24
+ .pro6pp-input::placeholder {
25
+ font-size: 16px;
26
+ color: #a3a3a3;
27
+ }
28
+
29
+ .pro6pp-input:focus {
30
+ outline: none;
31
+ border-color: #3b82f6;
32
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
33
+ }
34
+
35
+ .pro6pp-input-addons {
36
+ position: absolute;
37
+ right: 4px;
38
+ top: 0;
39
+ bottom: 0;
40
+ display: flex;
41
+ align-items: center;
42
+ pointer-events: none;
43
+ }
44
+ .pro6pp-input-addons > * {
45
+ pointer-events: auto;
46
+ }
47
+
48
+ .pro6pp-clear-button {
49
+ background: none;
50
+ border: none;
51
+ width: 32px;
52
+ height: 32px;
53
+ cursor: pointer;
54
+ color: #a3a3a3;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ border-radius: 50%;
59
+ transition: color 0.2s, background-color 0.2s;
60
+ touch-action: manipulation;
61
+ }
62
+
63
+ @media (hover: hover) {
64
+ .pro6pp-clear-button:hover {
65
+ color: #1f2937;
66
+ background-color: #f3f4f6;
67
+ }
68
+ }
69
+
70
+ .pro6pp-clear-button:active {
71
+ background-color: #f3f4f6;
72
+ }
73
+
74
+ .pro6pp-loader {
75
+ width: 20px;
76
+ height: 20px;
77
+ margin: 0 8px;
78
+ border: 2px solid #e0e0e0;
79
+ border-top-color: #6b7280;
80
+ border-radius: 50%;
81
+ animation: pro6pp-spin 0.6s linear infinite;
82
+ flex-shrink: 0;
83
+ }
84
+
85
+ .pro6pp-dropdown {
86
+ position: absolute;
87
+ top: 100%;
88
+ left: 0;
89
+ right: 0;
90
+ margin-top: 4px;
91
+ background: #ffffff;
92
+ border: 1px solid #e5e7eb;
93
+ border-radius: 6px;
94
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
95
+ z-index: 9999;
96
+ padding: 0;
97
+ max-height: 280px;
98
+ overflow-y: auto;
99
+ display: flex;
100
+ flex-direction: column;
101
+ }
102
+
103
+ @media (max-height: 500px) {
104
+ .pro6pp-dropdown {
105
+ max-height: 180px;
106
+ }
107
+ }
108
+
109
+ .pro6pp-list {
110
+ list-style: none;
111
+ margin: 0;
112
+ padding: 0;
113
+ width: 100%;
114
+ }
115
+
116
+ .pro6pp-item {
117
+ padding: 12px 14px;
118
+ cursor: pointer;
119
+ display: flex;
120
+ align-items: center;
121
+ font-size: 15px;
122
+ line-height: 1.4;
123
+ color: #374151;
124
+ border-bottom: 1px solid #f3f4f6;
125
+ transition: background-color 0.1s;
126
+ flex-shrink: 0;
127
+ }
128
+
129
+ .pro6pp-item:last-child {
130
+ border-bottom: none;
131
+ }
132
+
133
+ @media (hover: hover) {
134
+ .pro6pp-item:hover, .pro6pp-item--active {
135
+ background-color: #f9fafb;
136
+ }
137
+ }
138
+
139
+ .pro6pp-item:active {
140
+ background-color: #f3f4f6;
141
+ }
142
+
143
+ .pro6pp-item__label {
144
+ font-weight: 500;
145
+ flex-shrink: 1;
146
+ overflow: hidden;
147
+ text-overflow: ellipsis;
148
+ white-space: nowrap;
149
+ }
150
+
151
+ .pro6pp-item__subtitle {
152
+ font-size: 13px;
153
+ color: #6b7280;
154
+ flex-shrink: 0;
155
+ }
156
+
157
+ .pro6pp-item__chevron {
158
+ color: #d1d5db;
159
+ display: flex;
160
+ align-items: center;
161
+ margin-left: auto;
162
+ padding-left: 8px;
163
+ }
164
+
165
+ .pro6pp-no-results {
166
+ padding: 24px 16px;
167
+ color: #6b7280;
168
+ font-size: 15px;
169
+ text-align: center;
170
+ }
171
+
172
+ .pro6pp-load-more {
173
+ width: 100%;
174
+ padding: 14px;
175
+ background: #f9fafb;
176
+ border: none;
177
+ border-top: 1px solid #e0e0e0;
178
+ color: #3b82f6;
179
+ font-size: 14px;
180
+ font-weight: 600;
181
+ cursor: pointer;
182
+ flex-shrink: 0;
183
+ touch-action: manipulation;
184
+ }
185
+
186
+ @media (max-width: 640px) {
187
+ .pro6pp-input {
188
+ font-size: 16px;
189
+ padding: 10px 12px;
190
+ }
191
+ .pro6pp-item {
192
+ padding: 10px 12px;
193
+ font-size: 14px;
194
+ }
195
+ .pro6pp-item__subtitle {
196
+ font-size: 12px;
197
+ }
198
+ .pro6pp-load-more {
199
+ padding: 12px;
200
+ font-size: 13px;
201
+ }
202
+ }
203
+
204
+ .pro6pp-load-more:active {
205
+ background-color: #f3f4f6;
206
+ }
207
+
208
+ @keyframes pro6pp-spin {
209
+ to { transform: rotate(360deg); }
210
+ }
211
+ `;export{y as DEFAULT_STYLES,f as INITIAL_STATE,m as InferCore,w as getHighlightSegments};
package/package.json CHANGED
@@ -1,17 +1,39 @@
1
1
  {
2
2
  "name": "@pro6pp/infer-core",
3
+ "type": "module",
3
4
  "description": "Core logic and client for the Pro6PP Infer API.",
4
- "version": "0.0.2-beta.1",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
5
+ "homepage": "https://github.com/pro6pp/infer-sdk/tree/main/packages/core",
6
+ "keywords": [
7
+ "pro6pp",
8
+ "infer-api",
9
+ "sdk",
10
+ "core",
11
+ "headless",
12
+ "address",
13
+ "autocomplete",
14
+ "validation",
15
+ "postal-code",
16
+ "netherlands",
17
+ "germany",
18
+ "api-client",
19
+ "typescript"
20
+ ],
21
+ "bugs": {
22
+ "url": "https://github.com/pro6pp/infer-sdk/issues"
23
+ },
24
+ "sideEffects": false,
25
+ "version": "0.0.2-beta.11",
26
+ "main": "./dist/index.cjs",
27
+ "module": "./dist/index.js",
7
28
  "types": "./dist/index.d.ts",
8
29
  "unpkg": "./dist/index.global.js",
9
30
  "jsdelivr": "./dist/index.global.js",
10
31
  "exports": {
11
32
  ".": {
12
33
  "types": "./dist/index.d.ts",
13
- "import": "./dist/index.mjs",
14
- "require": "./dist/index.js"
34
+ "script": "./dist/index.global.js",
35
+ "import": "./dist/index.js",
36
+ "require": "./dist/index.cjs"
15
37
  }
16
38
  },
17
39
  "files": [
@@ -21,7 +43,9 @@
21
43
  "scripts": {
22
44
  "build": "tsup",
23
45
  "dev": "tsup --watch",
24
- "type-check": "tsc --noEmit"
46
+ "type-check": "tsc --noEmit",
47
+ "test": "vitest",
48
+ "test:coverage": "vitest run --coverage"
25
49
  },
26
50
  "devDependencies": {
27
51
  "tsup": "^8.0.0",
@@ -33,7 +57,7 @@
33
57
  "license": "MIT",
34
58
  "repository": {
35
59
  "type": "git",
36
- "url": "https://github.com/pro6pp/infer-sdk",
60
+ "url": "git+https://github.com/pro6pp/infer-sdk.git",
37
61
  "directory": "packages/core"
38
62
  }
39
63
  }
package/dist/index.d.mts DELETED
@@ -1,130 +0,0 @@
1
- /**
2
- * Supported ISO 3166-1 alpha-2 country codes.
3
- */
4
- type CountryCode = 'NL' | 'DE';
5
- /**
6
- * The current step in the address inference process.
7
- */
8
- type Stage = 'empty' | 'mixed' | 'street' | 'city' | 'postcode' | 'house_number' | 'house_number_first' | 'addition' | 'direct' | 'final';
9
- /**
10
- * The standardized address object returned upon selection.
11
- */
12
- interface AddressValue {
13
- street: string;
14
- city: string;
15
- street_number?: string | number;
16
- house_number?: string | number;
17
- postcode?: string;
18
- postcode_full?: string;
19
- addition?: string;
20
- /** Allow for extra fields if API expands. */
21
- [key: string]: unknown;
22
- }
23
- /**
24
- * A single item in the dropdown list.
25
- */
26
- interface InferResult {
27
- /** The text to display in the UI (e.g. "Amsterdam"). */
28
- label: string;
29
- /** The actual address data. Only present if this result completes an address. */
30
- value?: AddressValue;
31
- /** Helper text. */
32
- subtitle?: string | null;
33
- /** Number of underlying results (optional). */
34
- count?: number | string;
35
- }
36
- /**
37
- * The complete state returned by the `useInfer` hook.
38
- */
39
- interface InferState {
40
- /** The current value of the input field. */
41
- query: string;
42
- /** The current inference stage. */
43
- stage: Stage | null;
44
- /** List of cities to display, specific to `mixed` mode. */
45
- cities: InferResult[];
46
- /** List of streets to display, specific to `mixed` mode. */
47
- streets: InferResult[];
48
- /** General suggestions to display. */
49
- suggestions: InferResult[];
50
- /** True if a full, valid address has been selected. */
51
- isValid: boolean;
52
- /** True if the last network request failed. */
53
- isError: boolean;
54
- /** True if a network request is currently active. */
55
- isLoading: boolean;
56
- }
57
- /**
58
- * Custom fetch implementation, compatible with `window.fetch`.
59
- * Useful for server-side usage or testing.
60
- */
61
- type Fetcher = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
62
- /**
63
- * Configuration for Infer Core.
64
- */
65
- interface InferConfig {
66
- /**
67
- * Pro6PP Authorization Key.
68
- */
69
- authKey: string;
70
- /**
71
- * Country to search addresses in.
72
- */
73
- country: CountryCode;
74
- /**
75
- * Base URL for the Pro6PP API.
76
- * Useful for proxying requests through your own backend.
77
- * @default 'https://api.pro6pp.nl/v2'
78
- */
79
- apiUrl?: string;
80
- /**
81
- * Custom fetch implementation.
82
- * Useful for server-side usage or testing.
83
- */
84
- fetcher?: Fetcher;
85
- /**
86
- * Maximum number of results to return.
87
- * @default 1000
88
- */
89
- limit?: number;
90
- /**
91
- * Callback fired when the internal state changes.
92
- */
93
- onStateChange?: (state: InferState) => void;
94
- /**
95
- * Callback fired when a user selects a full valid address.
96
- */
97
- onSelect?: (selection: AddressValue | string | null) => void;
98
- }
99
-
100
- declare const INITIAL_STATE: InferState;
101
- declare class InferCore {
102
- private country;
103
- private authKey;
104
- private apiUrl;
105
- private limit;
106
- private fetcher;
107
- private onStateChange;
108
- private onSelect;
109
- state: InferState;
110
- private abortController;
111
- private debouncedFetch;
112
- constructor(config: InferConfig);
113
- handleInput(value: string): void;
114
- handleKeyDown(event: KeyboardEvent | React.KeyboardEvent<HTMLInputElement>): void;
115
- selectItem(item: InferResult | string): void;
116
- private shouldAutoInsertComma;
117
- private finishSelection;
118
- private processSelection;
119
- private executeFetch;
120
- private mapResponseToState;
121
- private updateQueryAndFetch;
122
- private replaceLastSegment;
123
- private getQueryPrefix;
124
- private getCurrentFragment;
125
- private resetState;
126
- private updateState;
127
- private debounce;
128
- }
129
-
130
- export { type AddressValue, type CountryCode, type Fetcher, INITIAL_STATE, type InferConfig, InferCore, type InferResult, type InferState, type Stage };
package/dist/index.mjs DELETED
@@ -1 +0,0 @@
1
- var d=Object.defineProperty;var p=(a,t,e)=>t in a?d(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var n=(a,t,e)=>p(a,typeof t!="symbol"?t+"":t,e);var o={API_URL:"https://api.pro6pp.nl/v2",LIMIT:1e3,DEBOUNCE_MS:300},l={DIGITS_1_3:/^[0-9]{1,3}$/},h={query:"",stage:null,cities:[],streets:[],suggestions:[],isValid:!1,isError:!1,isLoading:!1},c=class{constructor(t){n(this,"country");n(this,"authKey");n(this,"apiUrl");n(this,"limit");n(this,"fetcher");n(this,"onStateChange");n(this,"onSelect");n(this,"state");n(this,"abortController",null);n(this,"debouncedFetch");this.country=t.country,this.authKey=t.authKey,this.apiUrl=t.apiUrl||o.API_URL,this.limit=t.limit||o.LIMIT,this.fetcher=t.fetcher||((e,s)=>fetch(e,s)),this.onStateChange=t.onStateChange||(()=>{}),this.onSelect=t.onSelect||(()=>{}),this.state={...h},this.debouncedFetch=this.debounce(e=>this.executeFetch(e),o.DEBOUNCE_MS)}handleInput(t){this.updateState({query:t,isValid:!1,isLoading:!!t.trim()}),this.state.stage==="final"&&this.onSelect(null),this.debouncedFetch(t)}handleKeyDown(t){let s=t.target.value;if(t.key===" "&&this.shouldAutoInsertComma(s)){t.preventDefault();let r=`${s.trim()}, `;this.updateQueryAndFetch(r)}}selectItem(t){let e=typeof t=="string"?t:t.label,s=typeof t!="string"?t.value:void 0,r=typeof t!="string"?t.subtitle:null;if(this.state.stage==="final"){this.finishSelection(e,s);return}this.processSelection(e,r)}shouldAutoInsertComma(t){if(!t.includes(",")&&l.DIGITS_1_3.test(t.trim()))return!0;if(this.state.stage==="house_number"){let s=this.getCurrentFragment(t);return l.DIGITS_1_3.test(s)}return!1}finishSelection(t,e){this.updateState({query:t,suggestions:[],cities:[],streets:[],isValid:!0}),this.onSelect(e||t)}processSelection(t,e){let{stage:s,query:r}=this.state,i=r;if(e&&(s==="city"||s==="street"||s==="mixed")){if(s==="city")i=`${e}, ${t}, `;else{let u=this.getQueryPrefix(r);i=u?`${u} ${t}, ${e}, `:`${t}, ${e}, `}this.updateQueryAndFetch(i);return}if(s==="direct"||s==="addition"){this.finishSelection(t),this.handleInput(t);return}!r.includes(",")&&(s==="city"||s==="street"||s==="house_number_first")?i=`${t}, `:(i=this.replaceLastSegment(r,t),s!=="house_number"&&(i+=", ")),this.updateQueryAndFetch(i)}executeFetch(t){let e=(t||"").toString();if(!e.trim()){this.abortController?.abort(),this.resetState();return}this.updateState({isError:!1}),this.abortController&&this.abortController.abort(),this.abortController=new AbortController;let s=new URL(`${this.apiUrl}/infer/${this.country.toLowerCase()}`),r={authKey:this.authKey,query:e,limit:this.limit.toString()};s.search=new URLSearchParams(r).toString(),this.fetcher(s.toString(),{signal:this.abortController.signal}).then(i=>{if(!i.ok)throw new Error("Network error");return i.json()}).then(i=>this.mapResponseToState(i)).catch(i=>{i.name!=="AbortError"&&this.updateState({isError:!0,isLoading:!1})})}mapResponseToState(t){let e={stage:t.stage,isLoading:!1};t.stage==="mixed"?(e.cities=t.cities||[],e.streets=t.streets||[],e.suggestions=[]):(e.suggestions=t.suggestions||[],e.cities=[],e.streets=[]),e.isValid=t.stage==="final",this.updateState(e)}updateQueryAndFetch(t){this.updateState({query:t,suggestions:[],cities:[],streets:[]}),this.handleInput(t)}replaceLastSegment(t,e){let s=t.lastIndexOf(",");return s===-1?e:`${t.slice(0,s+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({...h,query:this.state.query})}updateState(t){this.state={...this.state,...t},this.onStateChange(this.state)}debounce(t,e){let s;return(...r)=>{s&&clearTimeout(s),s=setTimeout(()=>t.apply(this,r),e)}}};export{h as INITIAL_STATE,c as InferCore};