@pro6pp/infer-react 0.0.2-beta.8 → 0.1.0-beta.19
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 +34 -0
- package/dist/index.cjs +650 -203
- package/dist/index.d.cts +31 -9
- package/dist/index.d.ts +31 -9
- package/dist/index.js +658 -204
- package/dist/styles.css +203 -0
- package/package.json +7 -4
package/dist/index.cjs
CHANGED
|
@@ -38,15 +38,111 @@ __export(index_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(index_exports);
|
|
39
39
|
var import_react = __toESM(require("react"), 1);
|
|
40
40
|
|
|
41
|
+
// ../core/src/label-formatter.ts
|
|
42
|
+
function normalize(str) {
|
|
43
|
+
return str.toLowerCase().trim();
|
|
44
|
+
}
|
|
45
|
+
function escapeRegex(str) {
|
|
46
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
47
|
+
}
|
|
48
|
+
function findWordPosition(query, value) {
|
|
49
|
+
const normalizedQuery = normalize(query);
|
|
50
|
+
const normalizedValue = normalize(value);
|
|
51
|
+
if (normalizedValue.includes(" ")) {
|
|
52
|
+
return normalizedQuery.indexOf(normalizedValue);
|
|
53
|
+
}
|
|
54
|
+
const pattern = new RegExp(`(?:^|[,\\s])${escapeRegex(normalizedValue)}(?:$|[,\\s])`, "g");
|
|
55
|
+
const match = pattern.exec(normalizedQuery);
|
|
56
|
+
if (match) {
|
|
57
|
+
const matchStart = match.index;
|
|
58
|
+
const firstChar = normalizedQuery[matchStart];
|
|
59
|
+
if (firstChar === "," || firstChar === " ") {
|
|
60
|
+
return matchStart + 1;
|
|
61
|
+
}
|
|
62
|
+
return matchStart;
|
|
63
|
+
}
|
|
64
|
+
return -1;
|
|
65
|
+
}
|
|
66
|
+
function detectComponentOrder(query, value) {
|
|
67
|
+
const detected = [];
|
|
68
|
+
const componentMap = [];
|
|
69
|
+
if (value.street) {
|
|
70
|
+
componentMap.push({ value: value.street, type: "street" });
|
|
71
|
+
}
|
|
72
|
+
if (value.city) {
|
|
73
|
+
componentMap.push({ value: value.city, type: "city" });
|
|
74
|
+
}
|
|
75
|
+
if (value.postcode) {
|
|
76
|
+
componentMap.push({ value: value.postcode, type: "postcode" });
|
|
77
|
+
}
|
|
78
|
+
if (value.street_number !== void 0 && value.street_number !== null) {
|
|
79
|
+
componentMap.push({ value: String(value.street_number), type: "street_number" });
|
|
80
|
+
}
|
|
81
|
+
if (value.addition) {
|
|
82
|
+
componentMap.push({ value: value.addition, type: "addition" });
|
|
83
|
+
}
|
|
84
|
+
for (const comp of componentMap) {
|
|
85
|
+
const position = findWordPosition(query, comp.value);
|
|
86
|
+
if (position !== -1) {
|
|
87
|
+
detected.push({
|
|
88
|
+
type: comp.type,
|
|
89
|
+
value: comp.value,
|
|
90
|
+
position
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
detected.sort((a, b) => a.position - b.position);
|
|
95
|
+
return detected;
|
|
96
|
+
}
|
|
97
|
+
function formatLabelByInputOrder(query, value) {
|
|
98
|
+
if (!value || !query) {
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
const detectedOrder = detectComponentOrder(query, value);
|
|
102
|
+
const detectedTypes = new Set(detectedOrder.map((d) => d.type));
|
|
103
|
+
const parts = [];
|
|
104
|
+
for (const detected of detectedOrder) {
|
|
105
|
+
parts.push(detected.value);
|
|
106
|
+
}
|
|
107
|
+
const defaultOrder = ["street", "street_number", "addition", "postcode", "city"];
|
|
108
|
+
for (const type of defaultOrder) {
|
|
109
|
+
if (detectedTypes.has(type)) continue;
|
|
110
|
+
let val;
|
|
111
|
+
switch (type) {
|
|
112
|
+
case "street":
|
|
113
|
+
val = value.street;
|
|
114
|
+
break;
|
|
115
|
+
case "city":
|
|
116
|
+
val = value.city;
|
|
117
|
+
break;
|
|
118
|
+
case "street_number":
|
|
119
|
+
val = value.street_number !== void 0 ? String(value.street_number) : void 0;
|
|
120
|
+
break;
|
|
121
|
+
case "postcode":
|
|
122
|
+
val = value.postcode;
|
|
123
|
+
break;
|
|
124
|
+
case "addition":
|
|
125
|
+
val = value.addition;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
if (val) {
|
|
129
|
+
parts.push(val);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return parts.join(", ");
|
|
133
|
+
}
|
|
134
|
+
|
|
41
135
|
// ../core/src/core.ts
|
|
42
136
|
var DEFAULTS = {
|
|
43
137
|
API_URL: "https://api.pro6pp.nl/v2",
|
|
44
|
-
LIMIT:
|
|
138
|
+
LIMIT: 20,
|
|
45
139
|
DEBOUNCE_MS: 150,
|
|
46
|
-
MIN_DEBOUNCE_MS: 50
|
|
140
|
+
MIN_DEBOUNCE_MS: 50,
|
|
141
|
+
MAX_RETRIES: 0
|
|
47
142
|
};
|
|
48
143
|
var PATTERNS = {
|
|
49
|
-
DIGITS_1_3: /^[0-9]{1,3}
|
|
144
|
+
DIGITS_1_3: /^[0-9]{1,3}$/,
|
|
145
|
+
STREET_NUMBER_PREFIX: /^(\d+)\s*,\s*$/
|
|
50
146
|
};
|
|
51
147
|
var INITIAL_STATE = {
|
|
52
148
|
query: "",
|
|
@@ -55,8 +151,10 @@ var INITIAL_STATE = {
|
|
|
55
151
|
streets: [],
|
|
56
152
|
suggestions: [],
|
|
57
153
|
isValid: false,
|
|
154
|
+
value: null,
|
|
58
155
|
isError: false,
|
|
59
156
|
isLoading: false,
|
|
157
|
+
hasMore: false,
|
|
60
158
|
selectedSuggestionIndex: -1
|
|
61
159
|
};
|
|
62
160
|
var InferCore = class {
|
|
@@ -67,8 +165,11 @@ var InferCore = class {
|
|
|
67
165
|
constructor(config) {
|
|
68
166
|
__publicField(this, "country");
|
|
69
167
|
__publicField(this, "authKey");
|
|
70
|
-
__publicField(this, "
|
|
71
|
-
__publicField(this, "
|
|
168
|
+
__publicField(this, "explicitApiUrl");
|
|
169
|
+
__publicField(this, "baseLimit");
|
|
170
|
+
__publicField(this, "currentLimit");
|
|
171
|
+
__publicField(this, "maxRetries");
|
|
172
|
+
__publicField(this, "language");
|
|
72
173
|
__publicField(this, "fetcher");
|
|
73
174
|
__publicField(this, "onStateChange");
|
|
74
175
|
__publicField(this, "onSelect");
|
|
@@ -79,11 +180,14 @@ var InferCore = class {
|
|
|
79
180
|
__publicField(this, "state");
|
|
80
181
|
__publicField(this, "abortController", null);
|
|
81
182
|
__publicField(this, "debouncedFetch");
|
|
82
|
-
__publicField(this, "isSelecting", false);
|
|
83
183
|
this.country = config.country;
|
|
84
184
|
this.authKey = config.authKey;
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
185
|
+
this.explicitApiUrl = config.apiUrl;
|
|
186
|
+
this.baseLimit = config.limit || DEFAULTS.LIMIT;
|
|
187
|
+
this.currentLimit = this.baseLimit;
|
|
188
|
+
this.language = config.language;
|
|
189
|
+
const configRetries = config.maxRetries !== void 0 ? config.maxRetries : DEFAULTS.MAX_RETRIES;
|
|
190
|
+
this.maxRetries = Math.max(0, Math.min(configRetries, 10));
|
|
87
191
|
this.fetcher = config.fetcher || ((url, init) => fetch(url, init));
|
|
88
192
|
this.onStateChange = config.onStateChange || (() => {
|
|
89
193
|
});
|
|
@@ -100,28 +204,37 @@ var InferCore = class {
|
|
|
100
204
|
* @param value The raw string from the input field.
|
|
101
205
|
*/
|
|
102
206
|
handleInput(value) {
|
|
103
|
-
|
|
104
|
-
this.isSelecting = false;
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
207
|
+
this.currentLimit = this.baseLimit;
|
|
107
208
|
const isEditingFinal = this.state.stage === "final" && value !== this.state.query;
|
|
108
209
|
this.updateState({
|
|
109
210
|
query: value,
|
|
110
211
|
isValid: false,
|
|
212
|
+
value: null,
|
|
111
213
|
isLoading: !!value.trim(),
|
|
112
|
-
selectedSuggestionIndex: -1
|
|
214
|
+
selectedSuggestionIndex: -1,
|
|
215
|
+
hasMore: false,
|
|
216
|
+
stage: isEditingFinal ? null : this.state.stage
|
|
113
217
|
});
|
|
114
218
|
if (isEditingFinal) {
|
|
115
219
|
this.onSelect(null);
|
|
116
220
|
}
|
|
117
221
|
this.debouncedFetch(value);
|
|
118
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Increases the current limit and re-fetches the query to show more results.
|
|
225
|
+
*/
|
|
226
|
+
loadMore() {
|
|
227
|
+
if (this.state.isLoading) return;
|
|
228
|
+
this.currentLimit += this.baseLimit;
|
|
229
|
+
this.updateState({ isLoading: true });
|
|
230
|
+
this.executeFetch(this.state.query);
|
|
231
|
+
}
|
|
119
232
|
/**
|
|
120
233
|
* Handles keyboard events for the input field.
|
|
121
234
|
* Supports:
|
|
122
235
|
* - `ArrowUp`/`ArrowDown`: Navigate through the suggestion list.
|
|
123
236
|
* - `Enter`: Select the currently highlighted suggestion.
|
|
124
|
-
* - `Space`: Automatically inserts a comma if a numeric
|
|
237
|
+
* - `Space`: Automatically inserts a comma if a numeric street number is detected.
|
|
125
238
|
* @param event The keyboard event from the input element.
|
|
126
239
|
*/
|
|
127
240
|
handleKeyDown(event) {
|
|
@@ -169,6 +282,7 @@ var InferCore = class {
|
|
|
169
282
|
* Manually selects a suggestion or a string value.
|
|
170
283
|
* This is typically called when a user clicks a suggestion in the UI.
|
|
171
284
|
* @param item The suggestion object or string to select.
|
|
285
|
+
* @returns boolean True if the selection is a final address.
|
|
172
286
|
*/
|
|
173
287
|
selectItem(item) {
|
|
174
288
|
this.debouncedFetch.cancel();
|
|
@@ -182,26 +296,27 @@ var InferCore = class {
|
|
|
182
296
|
}
|
|
183
297
|
const valueObj = typeof item !== "string" && typeof item.value === "object" ? item.value : void 0;
|
|
184
298
|
const isFullResult = !!valueObj && Object.keys(valueObj).length > 0;
|
|
185
|
-
this.isSelecting = true;
|
|
186
299
|
if (this.state.stage === "final" || isFullResult) {
|
|
187
300
|
let finalQuery = label;
|
|
188
301
|
if (valueObj && Object.keys(valueObj).length > 0) {
|
|
189
|
-
const { street, street_number,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
302
|
+
const { street, street_number, postcode, city, addition } = valueObj;
|
|
303
|
+
if (street && street_number && city) {
|
|
304
|
+
const suffix = addition ? ` ${addition}` : "";
|
|
305
|
+
const postcodeStr = postcode ? `${postcode}, ` : "";
|
|
306
|
+
finalQuery = `${street}, ${street_number}${suffix}, ${postcodeStr}${city}`;
|
|
193
307
|
}
|
|
194
308
|
}
|
|
195
309
|
this.finishSelection(finalQuery, valueObj);
|
|
196
|
-
return;
|
|
310
|
+
return true;
|
|
197
311
|
}
|
|
198
312
|
const subtitle = typeof item !== "string" ? item.subtitle : null;
|
|
199
313
|
this.processSelection(logicValue, subtitle);
|
|
314
|
+
return false;
|
|
200
315
|
}
|
|
201
316
|
shouldAutoInsertComma(currentVal) {
|
|
202
317
|
const isStartOfSegmentAndNumeric = !currentVal.includes(",") && PATTERNS.DIGITS_1_3.test(currentVal.trim());
|
|
203
318
|
if (isStartOfSegmentAndNumeric) return true;
|
|
204
|
-
if (this.state.stage === "
|
|
319
|
+
if (this.state.stage === "street_number") {
|
|
205
320
|
const currentFragment = this.getCurrentFragment(currentVal);
|
|
206
321
|
return PATTERNS.DIGITS_1_3.test(currentFragment);
|
|
207
322
|
}
|
|
@@ -214,12 +329,11 @@ var InferCore = class {
|
|
|
214
329
|
cities: [],
|
|
215
330
|
streets: [],
|
|
216
331
|
isValid: true,
|
|
217
|
-
|
|
332
|
+
value: value || null,
|
|
333
|
+
stage: "final",
|
|
334
|
+
hasMore: false
|
|
218
335
|
});
|
|
219
336
|
this.onSelect(value || label);
|
|
220
|
-
setTimeout(() => {
|
|
221
|
-
this.isSelecting = false;
|
|
222
|
-
}, 0);
|
|
223
337
|
}
|
|
224
338
|
processSelection(text, subtitle) {
|
|
225
339
|
const { stage, query } = this.state;
|
|
@@ -230,7 +344,22 @@ var InferCore = class {
|
|
|
230
344
|
nextQuery = `${subtitle}, ${text}, `;
|
|
231
345
|
} else {
|
|
232
346
|
const prefix = this.getQueryPrefix(query);
|
|
233
|
-
|
|
347
|
+
const shouldAddSubtitle = !prefix || !prefix.includes(subtitle);
|
|
348
|
+
let effectivePrefix = prefix;
|
|
349
|
+
if (prefix && subtitle) {
|
|
350
|
+
const prefixNumMatch = prefix.match(PATTERNS.STREET_NUMBER_PREFIX);
|
|
351
|
+
if (prefixNumMatch) {
|
|
352
|
+
const num = prefixNumMatch[1];
|
|
353
|
+
if (subtitle.startsWith(num)) {
|
|
354
|
+
effectivePrefix = "";
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (shouldAddSubtitle) {
|
|
359
|
+
nextQuery = effectivePrefix ? `${effectivePrefix} ${text}, ${subtitle}, ` : `${text}, ${subtitle}, `;
|
|
360
|
+
} else {
|
|
361
|
+
nextQuery = effectivePrefix ? `${effectivePrefix} ${text}, ` : `${text}, `;
|
|
362
|
+
}
|
|
234
363
|
}
|
|
235
364
|
this.updateQueryAndFetch(nextQuery);
|
|
236
365
|
return;
|
|
@@ -240,50 +369,78 @@ var InferCore = class {
|
|
|
240
369
|
return;
|
|
241
370
|
}
|
|
242
371
|
const hasComma = query.includes(",");
|
|
243
|
-
const isFirstSegment = !hasComma && (stage === "city" || stage === "street" || stage === "
|
|
372
|
+
const isFirstSegment = !hasComma && (stage === "city" || stage === "street" || stage === "street_number_first");
|
|
244
373
|
if (isFirstSegment) {
|
|
245
374
|
nextQuery = `${text}, `;
|
|
246
375
|
} else {
|
|
247
376
|
nextQuery = this.replaceLastSegment(query, text);
|
|
248
|
-
if (stage !== "
|
|
377
|
+
if (stage !== "street_number") {
|
|
249
378
|
nextQuery += ", ";
|
|
250
379
|
}
|
|
251
380
|
}
|
|
252
381
|
this.updateQueryAndFetch(nextQuery);
|
|
253
382
|
}
|
|
254
|
-
executeFetch(val) {
|
|
383
|
+
executeFetch(val, attempt = 0) {
|
|
255
384
|
const text = (val || "").toString();
|
|
256
385
|
if (!text.trim()) {
|
|
257
386
|
this.abortController?.abort();
|
|
258
387
|
this.resetState();
|
|
259
388
|
return;
|
|
260
389
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
390
|
+
if (attempt === 0) {
|
|
391
|
+
this.updateState({ isError: false });
|
|
392
|
+
if (this.abortController) this.abortController.abort();
|
|
393
|
+
this.abortController = new AbortController();
|
|
394
|
+
}
|
|
395
|
+
const currentSignal = this.abortController?.signal;
|
|
396
|
+
const baseUrl = this.explicitApiUrl ? this.explicitApiUrl : `${DEFAULTS.API_URL}/infer/${this.country.toLowerCase()}`;
|
|
397
|
+
const params = new URLSearchParams({
|
|
267
398
|
query: text,
|
|
268
|
-
limit: this.
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
399
|
+
limit: this.currentLimit.toString()
|
|
400
|
+
});
|
|
401
|
+
if (this.explicitApiUrl) {
|
|
402
|
+
params.append("country", this.country.toLowerCase());
|
|
403
|
+
}
|
|
404
|
+
if (this.authKey) {
|
|
405
|
+
params.set("authKey", this.authKey);
|
|
406
|
+
}
|
|
407
|
+
if (this.language) {
|
|
408
|
+
params.set("language", this.language);
|
|
409
|
+
}
|
|
410
|
+
const separator = baseUrl.includes("?") ? "&" : "?";
|
|
411
|
+
const finalUrl = `${baseUrl}${separator}${params.toString()}`;
|
|
412
|
+
this.fetcher(finalUrl, { signal: currentSignal }).then((res) => {
|
|
413
|
+
if (!res.ok) {
|
|
414
|
+
if (attempt < this.maxRetries && (res.status >= 500 || res.status === 429)) {
|
|
415
|
+
return this.retry(val, attempt, currentSignal);
|
|
416
|
+
}
|
|
417
|
+
throw new Error("Network error");
|
|
418
|
+
}
|
|
273
419
|
return res.json();
|
|
274
|
-
}).then((data) =>
|
|
275
|
-
if (
|
|
276
|
-
|
|
420
|
+
}).then((data) => {
|
|
421
|
+
if (data) this.mapResponseToState(data);
|
|
422
|
+
}).catch((e) => {
|
|
423
|
+
if (e.name === "AbortError") return;
|
|
424
|
+
if (attempt < this.maxRetries) {
|
|
425
|
+
return this.retry(val, attempt, currentSignal);
|
|
277
426
|
}
|
|
427
|
+
this.updateState({ isError: true, isLoading: false });
|
|
278
428
|
});
|
|
279
429
|
}
|
|
430
|
+
retry(val, attempt, signal) {
|
|
431
|
+
if (signal?.aborted) return;
|
|
432
|
+
const delay = Math.pow(2, attempt) * 200;
|
|
433
|
+
setTimeout(() => {
|
|
434
|
+
if (!signal?.aborted) {
|
|
435
|
+
this.executeFetch(val, attempt + 1);
|
|
436
|
+
}
|
|
437
|
+
}, delay);
|
|
438
|
+
}
|
|
280
439
|
mapResponseToState(data) {
|
|
281
440
|
const newState = {
|
|
282
441
|
stage: data.stage,
|
|
283
442
|
isLoading: false
|
|
284
443
|
};
|
|
285
|
-
let autoSelect = false;
|
|
286
|
-
let autoSelectItem = null;
|
|
287
444
|
const rawSuggestions = data.suggestions || [];
|
|
288
445
|
const uniqueSuggestions = [];
|
|
289
446
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -291,43 +448,62 @@ var InferCore = class {
|
|
|
291
448
|
const key = `${item.label}|${item.subtitle || ""}|${JSON.stringify(item.value || {})}`;
|
|
292
449
|
if (!seen.has(key)) {
|
|
293
450
|
seen.add(key);
|
|
294
|
-
|
|
451
|
+
const reformattedItem = this.reformatSuggestionLabel(item);
|
|
452
|
+
uniqueSuggestions.push(reformattedItem);
|
|
295
453
|
}
|
|
296
454
|
}
|
|
455
|
+
const totalCount = uniqueSuggestions.length + (data.cities?.length || 0) + (data.streets?.length || 0);
|
|
456
|
+
newState.hasMore = totalCount >= this.currentLimit;
|
|
297
457
|
if (data.stage === "mixed") {
|
|
298
458
|
newState.cities = data.cities || [];
|
|
299
459
|
newState.streets = data.streets || [];
|
|
300
|
-
newState.
|
|
460
|
+
if (newState.cities?.length === 0 && newState.streets?.length === 0) {
|
|
461
|
+
newState.suggestions = uniqueSuggestions;
|
|
462
|
+
} else {
|
|
463
|
+
newState.suggestions = [];
|
|
464
|
+
}
|
|
301
465
|
} else {
|
|
302
466
|
newState.suggestions = uniqueSuggestions;
|
|
303
467
|
newState.cities = [];
|
|
304
468
|
newState.streets = [];
|
|
305
|
-
if (data.stage === "final" && uniqueSuggestions.length === 1) {
|
|
306
|
-
autoSelect = true;
|
|
307
|
-
autoSelectItem = uniqueSuggestions[0];
|
|
308
|
-
}
|
|
309
469
|
}
|
|
310
470
|
newState.isValid = data.stage === "final";
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
newState.cities = [];
|
|
315
|
-
newState.streets = [];
|
|
316
|
-
newState.isValid = true;
|
|
317
|
-
this.updateState(newState);
|
|
318
|
-
const val = typeof autoSelectItem.value === "object" ? autoSelectItem.value : autoSelectItem.label;
|
|
319
|
-
this.onSelect(val);
|
|
320
|
-
} else {
|
|
321
|
-
this.updateState(newState);
|
|
471
|
+
this.updateState(newState);
|
|
472
|
+
if (newState.isValid && uniqueSuggestions.length === 1) {
|
|
473
|
+
this.selectItem(uniqueSuggestions[0]);
|
|
322
474
|
}
|
|
323
475
|
}
|
|
476
|
+
/**
|
|
477
|
+
* Reformats a suggestion's label based on the user's input order.
|
|
478
|
+
* If the suggestion has a structured value object, we reorder the label
|
|
479
|
+
* to match how the user typed the components.
|
|
480
|
+
*/
|
|
481
|
+
reformatSuggestionLabel(item) {
|
|
482
|
+
if (!item.value || typeof item.value === "string") {
|
|
483
|
+
return item;
|
|
484
|
+
}
|
|
485
|
+
const addressValue = item.value;
|
|
486
|
+
if (!addressValue.street || !addressValue.city) {
|
|
487
|
+
return item;
|
|
488
|
+
}
|
|
489
|
+
const reformattedLabel = formatLabelByInputOrder(this.state.query, addressValue);
|
|
490
|
+
if (reformattedLabel) {
|
|
491
|
+
return { ...item, label: reformattedLabel };
|
|
492
|
+
}
|
|
493
|
+
return item;
|
|
494
|
+
}
|
|
324
495
|
updateQueryAndFetch(nextQuery) {
|
|
325
|
-
this.updateState({
|
|
326
|
-
|
|
496
|
+
this.updateState({
|
|
497
|
+
query: nextQuery,
|
|
498
|
+
suggestions: [],
|
|
499
|
+
cities: [],
|
|
500
|
+
streets: [],
|
|
501
|
+
isValid: false,
|
|
502
|
+
value: null,
|
|
503
|
+
isLoading: true,
|
|
504
|
+
hasMore: false
|
|
505
|
+
});
|
|
327
506
|
this.debouncedFetch(nextQuery);
|
|
328
|
-
setTimeout(() => {
|
|
329
|
-
this.isSelecting = false;
|
|
330
|
-
}, 0);
|
|
331
507
|
}
|
|
332
508
|
replaceLastSegment(fullText, newSegment) {
|
|
333
509
|
const lastCommaIndex = fullText.lastIndexOf(",");
|
|
@@ -364,6 +540,49 @@ var InferCore = class {
|
|
|
364
540
|
}
|
|
365
541
|
};
|
|
366
542
|
|
|
543
|
+
// ../core/src/highlight.ts
|
|
544
|
+
function mergeSegments(segments) {
|
|
545
|
+
if (segments.length === 0) return segments;
|
|
546
|
+
const merged = [];
|
|
547
|
+
for (const seg of segments) {
|
|
548
|
+
const last = merged[merged.length - 1];
|
|
549
|
+
if (last && last.match === seg.match) {
|
|
550
|
+
last.text += seg.text;
|
|
551
|
+
} else {
|
|
552
|
+
merged.push({ text: seg.text, match: seg.match });
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return merged;
|
|
556
|
+
}
|
|
557
|
+
function getHighlightSegments(text, query) {
|
|
558
|
+
if (!query || !text) return [{ text, match: false }];
|
|
559
|
+
const segments = [];
|
|
560
|
+
const normalizedText = text.toLowerCase();
|
|
561
|
+
const normalizedQuery = query.toLowerCase();
|
|
562
|
+
let queryCursor = 0;
|
|
563
|
+
let unmatchedCursor = 0;
|
|
564
|
+
for (let textCursor = 0; textCursor < text.length; textCursor++) {
|
|
565
|
+
const isMatch = queryCursor < query.length && normalizedText[textCursor] === normalizedQuery[queryCursor];
|
|
566
|
+
if (!isMatch) continue;
|
|
567
|
+
const hasPrecedingUnmatched = textCursor > unmatchedCursor;
|
|
568
|
+
if (hasPrecedingUnmatched) {
|
|
569
|
+
segments.push({ text: text.slice(unmatchedCursor, textCursor), match: false });
|
|
570
|
+
}
|
|
571
|
+
segments.push({ text: text[textCursor], match: true });
|
|
572
|
+
queryCursor++;
|
|
573
|
+
unmatchedCursor = textCursor + 1;
|
|
574
|
+
}
|
|
575
|
+
const hasRemainingText = unmatchedCursor < text.length;
|
|
576
|
+
if (hasRemainingText) {
|
|
577
|
+
segments.push({ text: text.slice(unmatchedCursor), match: false });
|
|
578
|
+
}
|
|
579
|
+
const isFullMatch = queryCursor === query.length;
|
|
580
|
+
if (!isFullMatch) {
|
|
581
|
+
return [{ text, match: false }];
|
|
582
|
+
}
|
|
583
|
+
return mergeSegments(segments);
|
|
584
|
+
}
|
|
585
|
+
|
|
367
586
|
// ../core/src/default-styles.ts
|
|
368
587
|
var DEFAULT_STYLES = `
|
|
369
588
|
.pro6pp-wrapper {
|
|
@@ -371,116 +590,276 @@ var DEFAULT_STYLES = `
|
|
|
371
590
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
372
591
|
box-sizing: border-box;
|
|
373
592
|
width: 100%;
|
|
593
|
+
-webkit-tap-highlight-color: transparent;
|
|
374
594
|
}
|
|
375
595
|
.pro6pp-wrapper * {
|
|
376
596
|
box-sizing: border-box;
|
|
377
597
|
}
|
|
378
598
|
.pro6pp-input {
|
|
379
599
|
width: 100%;
|
|
380
|
-
padding:
|
|
600
|
+
padding: 12px 14px;
|
|
601
|
+
padding-right: 48px;
|
|
381
602
|
border: 1px solid #e0e0e0;
|
|
382
|
-
border-radius:
|
|
603
|
+
border-radius: 8px;
|
|
383
604
|
font-size: 16px;
|
|
384
605
|
line-height: 1.5;
|
|
606
|
+
appearance: none;
|
|
385
607
|
transition: border-color 0.2s, box-shadow 0.2s;
|
|
386
608
|
}
|
|
609
|
+
|
|
610
|
+
.pro6pp-input::placeholder {
|
|
611
|
+
font-size: 16px;
|
|
612
|
+
color: #a3a3a3;
|
|
613
|
+
}
|
|
614
|
+
|
|
387
615
|
.pro6pp-input:focus {
|
|
388
616
|
outline: none;
|
|
389
617
|
border-color: #3b82f6;
|
|
390
618
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
391
619
|
}
|
|
620
|
+
|
|
621
|
+
.pro6pp-input-addons {
|
|
622
|
+
position: absolute;
|
|
623
|
+
right: 4px;
|
|
624
|
+
top: 0;
|
|
625
|
+
bottom: 0;
|
|
626
|
+
display: flex;
|
|
627
|
+
align-items: center;
|
|
628
|
+
pointer-events: none;
|
|
629
|
+
}
|
|
630
|
+
.pro6pp-input-addons > * {
|
|
631
|
+
pointer-events: auto;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.pro6pp-clear-button {
|
|
635
|
+
background: none;
|
|
636
|
+
border: none;
|
|
637
|
+
width: 32px;
|
|
638
|
+
height: 32px;
|
|
639
|
+
cursor: pointer;
|
|
640
|
+
color: #a3a3a3;
|
|
641
|
+
display: flex;
|
|
642
|
+
align-items: center;
|
|
643
|
+
justify-content: center;
|
|
644
|
+
border-radius: 50%;
|
|
645
|
+
transition: color 0.2s, background-color 0.2s;
|
|
646
|
+
touch-action: manipulation;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
@media (hover: hover) {
|
|
650
|
+
.pro6pp-clear-button:hover {
|
|
651
|
+
color: #1f2937;
|
|
652
|
+
background-color: #f3f4f6;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.pro6pp-clear-button:active {
|
|
657
|
+
background-color: #f3f4f6;
|
|
658
|
+
}
|
|
659
|
+
|
|
392
660
|
.pro6pp-dropdown {
|
|
393
661
|
position: absolute;
|
|
394
662
|
top: 100%;
|
|
395
663
|
left: 0;
|
|
396
664
|
right: 0;
|
|
397
|
-
z-index: 9999;
|
|
398
665
|
margin-top: 4px;
|
|
399
|
-
background:
|
|
400
|
-
border: 1px solid #
|
|
401
|
-
border-radius:
|
|
402
|
-
box-shadow: 0 4px
|
|
403
|
-
|
|
666
|
+
background: #ffffff;
|
|
667
|
+
border: 1px solid #e5e7eb;
|
|
668
|
+
border-radius: 6px;
|
|
669
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
670
|
+
z-index: 9999;
|
|
671
|
+
padding: 0;
|
|
672
|
+
max-height: 280px;
|
|
404
673
|
overflow-y: auto;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
674
|
+
display: flex;
|
|
675
|
+
flex-direction: column;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
@media (max-height: 500px) {
|
|
679
|
+
.pro6pp-dropdown {
|
|
680
|
+
max-height: 180px;
|
|
681
|
+
}
|
|
408
682
|
}
|
|
683
|
+
|
|
684
|
+
.pro6pp-list {
|
|
685
|
+
list-style: none;
|
|
686
|
+
margin: 0;
|
|
687
|
+
padding: 0;
|
|
688
|
+
width: 100%;
|
|
689
|
+
}
|
|
690
|
+
|
|
409
691
|
.pro6pp-item {
|
|
410
|
-
padding:
|
|
692
|
+
padding: 12px 14px;
|
|
411
693
|
cursor: pointer;
|
|
412
694
|
display: flex;
|
|
413
|
-
flex-direction: row;
|
|
414
695
|
align-items: center;
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
696
|
+
font-size: 15px;
|
|
697
|
+
line-height: 1.4;
|
|
698
|
+
color: #374151;
|
|
699
|
+
border-bottom: 1px solid #f3f4f6;
|
|
700
|
+
transition: background-color 0.1s;
|
|
701
|
+
flex-shrink: 0;
|
|
420
702
|
}
|
|
421
|
-
|
|
422
|
-
|
|
703
|
+
|
|
704
|
+
.pro6pp-item:last-child {
|
|
705
|
+
border-bottom: none;
|
|
423
706
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
707
|
+
|
|
708
|
+
@media (hover: hover) {
|
|
709
|
+
.pro6pp-item:hover, .pro6pp-item--active {
|
|
710
|
+
background-color: #f9fafb;
|
|
711
|
+
}
|
|
427
712
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
color: #
|
|
713
|
+
|
|
714
|
+
.pro6pp-item:active {
|
|
715
|
+
background-color: #f3f4f6;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.pro6pp-item__label {
|
|
719
|
+
font-weight: 400;
|
|
720
|
+
flex-shrink: 1;
|
|
431
721
|
overflow: hidden;
|
|
432
722
|
text-overflow: ellipsis;
|
|
433
|
-
|
|
723
|
+
white-space: nowrap;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.pro6pp-item__label--match {
|
|
727
|
+
font-weight: 520;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.pro6pp-item__label--unmatched {
|
|
731
|
+
font-weight: 400;
|
|
732
|
+
color: #4b5563;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.pro6pp-item__subtitle {
|
|
736
|
+
color: #6b7280;
|
|
737
|
+
flex-shrink: 0;
|
|
434
738
|
}
|
|
739
|
+
|
|
435
740
|
.pro6pp-item__chevron {
|
|
436
|
-
|
|
741
|
+
color: #d1d5db;
|
|
437
742
|
display: flex;
|
|
438
743
|
align-items: center;
|
|
439
|
-
|
|
744
|
+
margin-left: auto;
|
|
440
745
|
padding-left: 8px;
|
|
441
746
|
}
|
|
747
|
+
|
|
442
748
|
.pro6pp-no-results {
|
|
443
|
-
padding:
|
|
444
|
-
color: #
|
|
445
|
-
font-size:
|
|
749
|
+
padding: 24px 16px;
|
|
750
|
+
color: #6b7280;
|
|
751
|
+
font-size: 15px;
|
|
446
752
|
text-align: center;
|
|
447
|
-
user-select: none;
|
|
448
|
-
pointer-events: none;
|
|
449
753
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
754
|
+
|
|
755
|
+
.pro6pp-loader-item {
|
|
756
|
+
padding: 10px 12px;
|
|
757
|
+
color: #6b7280;
|
|
758
|
+
font-size: 0.875rem;
|
|
759
|
+
display: flex;
|
|
760
|
+
align-items: center;
|
|
761
|
+
justify-content: center;
|
|
762
|
+
gap: 8px;
|
|
763
|
+
background-color: #f9fafb;
|
|
764
|
+
border-top: 1px solid #f3f4f6;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.pro6pp-mini-spinner {
|
|
768
|
+
width: 14px;
|
|
769
|
+
height: 14px;
|
|
770
|
+
border: 2px solid #e5e7eb;
|
|
771
|
+
border-top-color: #6b7280;
|
|
459
772
|
border-radius: 50%;
|
|
460
773
|
animation: pro6pp-spin 0.6s linear infinite;
|
|
461
|
-
pointer-events: none;
|
|
462
774
|
}
|
|
775
|
+
|
|
776
|
+
@media (max-width: 640px) {
|
|
777
|
+
.pro6pp-input {
|
|
778
|
+
font-size: 16px;
|
|
779
|
+
padding: 10px 12px;
|
|
780
|
+
}
|
|
781
|
+
.pro6pp-item {
|
|
782
|
+
padding: 10px 12px;
|
|
783
|
+
font-size: 14px;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
463
787
|
@keyframes pro6pp-spin {
|
|
464
|
-
to { transform:
|
|
788
|
+
to { transform: rotate(360deg); }
|
|
465
789
|
}
|
|
466
790
|
`;
|
|
467
791
|
|
|
468
792
|
// src/index.tsx
|
|
793
|
+
var HighlightedText = ({ text, query }) => {
|
|
794
|
+
const segments = (0, import_react.useMemo)(() => getHighlightSegments(text, query), [text, query]);
|
|
795
|
+
return /* @__PURE__ */ import_react.default.createElement("span", { className: "pro6pp-item__label" }, segments.map(
|
|
796
|
+
(seg, i) => seg.match ? /* @__PURE__ */ import_react.default.createElement("span", { key: i, className: "pro6pp-item__label--match" }, seg.text) : /* @__PURE__ */ import_react.default.createElement("span", { key: i, className: "pro6pp-item__label--unmatched" }, seg.text)
|
|
797
|
+
));
|
|
798
|
+
};
|
|
469
799
|
function useInfer(config) {
|
|
470
|
-
const [state, setState] = (0, import_react.useState)(
|
|
800
|
+
const [state, setState] = (0, import_react.useState)(() => {
|
|
801
|
+
if (config.initialValue) {
|
|
802
|
+
const suffix = config.initialValue.addition ? ` ${config.initialValue.addition}` : "";
|
|
803
|
+
const postcodeStr = config.initialValue.postcode ? `${config.initialValue.postcode}, ` : "";
|
|
804
|
+
return {
|
|
805
|
+
...INITIAL_STATE,
|
|
806
|
+
value: config.initialValue,
|
|
807
|
+
query: `${config.initialValue.street}, ${config.initialValue.street_number}${suffix}, ${postcodeStr}${config.initialValue.city}`,
|
|
808
|
+
isValid: true,
|
|
809
|
+
stage: "final"
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
return INITIAL_STATE;
|
|
813
|
+
});
|
|
814
|
+
const callbacksRef = (0, import_react.useRef)({
|
|
815
|
+
onStateChange: config.onStateChange,
|
|
816
|
+
onSelect: config.onSelect
|
|
817
|
+
});
|
|
818
|
+
(0, import_react.useEffect)(() => {
|
|
819
|
+
callbacksRef.current = {
|
|
820
|
+
onStateChange: config.onStateChange,
|
|
821
|
+
onSelect: config.onSelect
|
|
822
|
+
};
|
|
823
|
+
}, [config.onStateChange, config.onSelect]);
|
|
471
824
|
const core = (0, import_react.useMemo)(() => {
|
|
472
|
-
|
|
825
|
+
const instance = new InferCore({
|
|
473
826
|
...config,
|
|
474
827
|
onStateChange: (newState) => {
|
|
475
828
|
setState({ ...newState });
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
829
|
+
callbacksRef.current.onStateChange?.(newState);
|
|
830
|
+
},
|
|
831
|
+
onSelect: (selection) => {
|
|
832
|
+
callbacksRef.current.onSelect?.(selection);
|
|
479
833
|
}
|
|
480
834
|
});
|
|
481
|
-
|
|
835
|
+
if (config.initialValue) {
|
|
836
|
+
const address = config.initialValue;
|
|
837
|
+
const suffix = address.addition ? ` ${address.addition}` : "";
|
|
838
|
+
const postcodeStr = address.postcode ? `${address.postcode}, ` : "";
|
|
839
|
+
const label = `${address.street}, ${address.street_number}${suffix}, ${postcodeStr}${address.city}`;
|
|
840
|
+
instance.selectItem({ label, value: address });
|
|
841
|
+
}
|
|
842
|
+
return instance;
|
|
843
|
+
}, [
|
|
844
|
+
config.country,
|
|
845
|
+
config.authKey,
|
|
846
|
+
config.apiUrl,
|
|
847
|
+
config.fetcher,
|
|
848
|
+
config.limit,
|
|
849
|
+
config.debounceMs,
|
|
850
|
+
config.maxRetries,
|
|
851
|
+
config.initialValue,
|
|
852
|
+
config.language
|
|
853
|
+
]);
|
|
854
|
+
const setValue = (address) => {
|
|
855
|
+
if (!address) return;
|
|
856
|
+
const suffix = address.addition ? ` ${address.addition}` : "";
|
|
857
|
+
const postcodeStr = address.postcode ? `${address.postcode}, ` : "";
|
|
858
|
+
const label = `${address.street}, ${address.street_number}${suffix}, ${postcodeStr}${address.city}`;
|
|
859
|
+
core.selectItem({ label, value: address });
|
|
860
|
+
};
|
|
482
861
|
return {
|
|
483
|
-
/** The current UI state (suggestions, loading status, query, etc.). */
|
|
862
|
+
/** The current UI state (suggestions, loading status, query, value, etc.). */
|
|
484
863
|
state,
|
|
485
864
|
/** The raw InferCore instance for manual control. */
|
|
486
865
|
core,
|
|
@@ -490,95 +869,125 @@ function useInfer(config) {
|
|
|
490
869
|
onChange: (e) => core.handleInput(e.target.value),
|
|
491
870
|
onKeyDown: (e) => core.handleKeyDown(e)
|
|
492
871
|
},
|
|
493
|
-
/**
|
|
494
|
-
selectItem: (item) => core.selectItem(item)
|
|
872
|
+
/** Manually select a specific suggestion. */
|
|
873
|
+
selectItem: (item) => core.selectItem(item),
|
|
874
|
+
/** Programmatically set the address value. */
|
|
875
|
+
setValue,
|
|
876
|
+
/** Load more results. */
|
|
877
|
+
loadMore: () => core.loadMore()
|
|
495
878
|
};
|
|
496
879
|
}
|
|
497
|
-
var Pro6PPInfer = (
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
880
|
+
var Pro6PPInfer = (0, import_react.forwardRef)(
|
|
881
|
+
({
|
|
882
|
+
className,
|
|
883
|
+
style,
|
|
884
|
+
inputProps,
|
|
885
|
+
placeholder = "Start typing an address...",
|
|
886
|
+
renderItem,
|
|
887
|
+
disableDefaultStyles = false,
|
|
888
|
+
noResultsText = "No results found",
|
|
889
|
+
loadingText = "Loading more...",
|
|
890
|
+
renderNoResults,
|
|
891
|
+
showClearButton = true,
|
|
892
|
+
...config
|
|
893
|
+
}, ref) => {
|
|
894
|
+
const { state, selectItem, loadMore, inputProps: coreInputProps, core } = useInfer(config);
|
|
895
|
+
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
896
|
+
const internalInputRef = (0, import_react.useRef)(null);
|
|
897
|
+
const wrapperRef = (0, import_react.useRef)(null);
|
|
898
|
+
const observerTarget = (0, import_react.useRef)(null);
|
|
899
|
+
(0, import_react.useImperativeHandle)(ref, () => internalInputRef.current);
|
|
900
|
+
(0, import_react.useEffect)(() => {
|
|
901
|
+
if (disableDefaultStyles) return;
|
|
902
|
+
const styleId = "pro6pp-styles";
|
|
903
|
+
if (!document.getElementById(styleId)) {
|
|
904
|
+
const styleEl = document.createElement("style");
|
|
905
|
+
styleEl.id = styleId;
|
|
906
|
+
styleEl.textContent = DEFAULT_STYLES;
|
|
907
|
+
document.head.appendChild(styleEl);
|
|
908
|
+
}
|
|
909
|
+
}, [disableDefaultStyles]);
|
|
910
|
+
(0, import_react.useEffect)(() => {
|
|
911
|
+
const handleClickOutside = (event) => {
|
|
912
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
913
|
+
setIsOpen(false);
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
917
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
918
|
+
}, []);
|
|
919
|
+
(0, import_react.useEffect)(() => {
|
|
920
|
+
const currentTarget = observerTarget.current;
|
|
921
|
+
if (!currentTarget) return;
|
|
922
|
+
const observer = new IntersectionObserver(
|
|
923
|
+
(entries) => {
|
|
924
|
+
if (entries[0].isIntersecting && state.hasMore && !state.isLoading) {
|
|
925
|
+
loadMore();
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
{ threshold: 0.1 }
|
|
929
|
+
);
|
|
930
|
+
observer.observe(currentTarget);
|
|
931
|
+
return () => {
|
|
932
|
+
if (currentTarget) observer.unobserve(currentTarget);
|
|
933
|
+
};
|
|
934
|
+
}, [state.hasMore, state.isLoading, loadMore, isOpen]);
|
|
935
|
+
const items = (0, import_react.useMemo)(() => {
|
|
936
|
+
return [
|
|
937
|
+
...state.cities.map((c) => ({ ...c, type: "city" })),
|
|
938
|
+
...state.streets.map((s) => ({ ...s, type: "street" })),
|
|
939
|
+
...state.suggestions.map((s) => ({ ...s, type: "suggestion" }))
|
|
940
|
+
];
|
|
941
|
+
}, [state.cities, state.streets, state.suggestions]);
|
|
942
|
+
const handleSelect = (item) => {
|
|
943
|
+
const isFinal = selectItem(item);
|
|
944
|
+
if (!isFinal) {
|
|
945
|
+
setTimeout(() => internalInputRef.current?.focus(), 0);
|
|
946
|
+
} else {
|
|
525
947
|
setIsOpen(false);
|
|
526
948
|
}
|
|
527
949
|
};
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
autoComplete: "off",
|
|
556
|
-
...inputProps,
|
|
557
|
-
...coreInputProps,
|
|
558
|
-
onFocus: (e) => {
|
|
559
|
-
setIsOpen(true);
|
|
560
|
-
inputProps?.onFocus?.(e);
|
|
950
|
+
const handleClear = () => {
|
|
951
|
+
core.handleInput("");
|
|
952
|
+
internalInputRef.current?.focus();
|
|
953
|
+
};
|
|
954
|
+
const hasResults = items.length > 0;
|
|
955
|
+
const showNoResults = !state.isLoading && !state.isError && state.query.length > 0 && !hasResults && !state.isValid;
|
|
956
|
+
const showDropdown = isOpen && (hasResults || state.isLoading || showNoResults);
|
|
957
|
+
const isInfiniteLoading = state.isLoading && items.length > 0;
|
|
958
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { ref: wrapperRef, className: `pro6pp-wrapper ${className || ""}`, style }, /* @__PURE__ */ import_react.default.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ import_react.default.createElement(
|
|
959
|
+
"input",
|
|
960
|
+
{
|
|
961
|
+
ref: internalInputRef,
|
|
962
|
+
type: "text",
|
|
963
|
+
className: "pro6pp-input",
|
|
964
|
+
placeholder,
|
|
965
|
+
autoComplete: "off",
|
|
966
|
+
autoCorrect: "off",
|
|
967
|
+
autoCapitalize: "none",
|
|
968
|
+
spellCheck: "false",
|
|
969
|
+
inputMode: "search",
|
|
970
|
+
enterKeyHint: "search",
|
|
971
|
+
...inputProps,
|
|
972
|
+
...coreInputProps,
|
|
973
|
+
onFocus: (e) => {
|
|
974
|
+
setIsOpen(true);
|
|
975
|
+
inputProps?.onFocus?.(e);
|
|
976
|
+
}
|
|
561
977
|
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const isActive = index === state.selectedSuggestionIndex;
|
|
565
|
-
const secondaryText = item.subtitle || (item.count !== void 0 ? item.count : "");
|
|
566
|
-
const showChevron = item.value === void 0 || item.value === null;
|
|
567
|
-
return /* @__PURE__ */ import_react.default.createElement(
|
|
568
|
-
"li",
|
|
978
|
+
), /* @__PURE__ */ import_react.default.createElement("div", { className: "pro6pp-input-addons" }, showClearButton && state.query.length > 0 && /* @__PURE__ */ import_react.default.createElement(
|
|
979
|
+
"button",
|
|
569
980
|
{
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
575
|
-
onClick: () => handleSelect(item)
|
|
981
|
+
type: "button",
|
|
982
|
+
className: "pro6pp-clear-button",
|
|
983
|
+
onClick: handleClear,
|
|
984
|
+
"aria-label": "Clear input"
|
|
576
985
|
},
|
|
577
|
-
|
|
986
|
+
/* @__PURE__ */ import_react.default.createElement(
|
|
578
987
|
"svg",
|
|
579
988
|
{
|
|
580
|
-
width: "
|
|
581
|
-
height: "
|
|
989
|
+
width: "14",
|
|
990
|
+
height: "14",
|
|
582
991
|
viewBox: "0 0 24 24",
|
|
583
992
|
fill: "none",
|
|
584
993
|
stroke: "currentColor",
|
|
@@ -586,11 +995,49 @@ var Pro6PPInfer = ({
|
|
|
586
995
|
strokeLinecap: "round",
|
|
587
996
|
strokeLinejoin: "round"
|
|
588
997
|
},
|
|
589
|
-
/* @__PURE__ */ import_react.default.createElement("
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
998
|
+
/* @__PURE__ */ import_react.default.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
999
|
+
/* @__PURE__ */ import_react.default.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1000
|
+
)
|
|
1001
|
+
))), showDropdown && /* @__PURE__ */ import_react.default.createElement(
|
|
1002
|
+
"div",
|
|
1003
|
+
{
|
|
1004
|
+
className: "pro6pp-dropdown",
|
|
1005
|
+
onWheel: (e) => e.stopPropagation(),
|
|
1006
|
+
onMouseDown: (e) => e.stopPropagation()
|
|
1007
|
+
},
|
|
1008
|
+
/* @__PURE__ */ import_react.default.createElement("ul", { className: "pro6pp-list", role: "listbox" }, hasResults ? /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, items.map((item, index) => {
|
|
1009
|
+
const isActive = index === state.selectedSuggestionIndex;
|
|
1010
|
+
const secondaryText = item.subtitle || (item.count !== void 0 ? item.count : "");
|
|
1011
|
+
const showChevron = item.value === void 0 || item.value === null;
|
|
1012
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
1013
|
+
"li",
|
|
1014
|
+
{
|
|
1015
|
+
key: `${item.label}-${index}`,
|
|
1016
|
+
role: "option",
|
|
1017
|
+
"aria-selected": isActive,
|
|
1018
|
+
className: `pro6pp-item ${isActive ? "pro6pp-item--active" : ""}`,
|
|
1019
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
1020
|
+
onClick: () => handleSelect(item)
|
|
1021
|
+
},
|
|
1022
|
+
renderItem ? renderItem(item, isActive) : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(HighlightedText, { text: item.label, query: state.query }), secondaryText && /* @__PURE__ */ import_react.default.createElement("span", { className: "pro6pp-item__subtitle" }, ", ", secondaryText), showChevron && /* @__PURE__ */ import_react.default.createElement("div", { className: "pro6pp-item__chevron" }, /* @__PURE__ */ import_react.default.createElement(
|
|
1023
|
+
"svg",
|
|
1024
|
+
{
|
|
1025
|
+
width: "16",
|
|
1026
|
+
height: "16",
|
|
1027
|
+
viewBox: "0 0 24 24",
|
|
1028
|
+
fill: "none",
|
|
1029
|
+
stroke: "currentColor",
|
|
1030
|
+
strokeWidth: "2",
|
|
1031
|
+
strokeLinecap: "round",
|
|
1032
|
+
strokeLinejoin: "round"
|
|
1033
|
+
},
|
|
1034
|
+
/* @__PURE__ */ import_react.default.createElement("polyline", { points: "9 18 15 12 9 6" })
|
|
1035
|
+
)))
|
|
1036
|
+
);
|
|
1037
|
+
}), state.hasMore && !state.isLoading && /* @__PURE__ */ import_react.default.createElement("li", { key: "sentinel", ref: observerTarget, style: { height: "1px", opacity: 0 } }), isInfiniteLoading && /* @__PURE__ */ import_react.default.createElement("li", { key: "loader", className: "pro6pp-loader-item" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "pro6pp-mini-spinner" }), /* @__PURE__ */ import_react.default.createElement("span", null, loadingText))) : state.isLoading ? /* @__PURE__ */ import_react.default.createElement("li", { className: "pro6pp-no-results" }, "Searching...") : /* @__PURE__ */ import_react.default.createElement("li", { className: "pro6pp-no-results" }, renderNoResults ? renderNoResults(state) : noResultsText))
|
|
1038
|
+
));
|
|
1039
|
+
}
|
|
1040
|
+
);
|
|
594
1041
|
// Annotate the CommonJS export names for ESM import in node:
|
|
595
1042
|
0 && (module.exports = {
|
|
596
1043
|
Pro6PPInfer,
|