@pro6pp/infer-react 0.0.2-beta.7 → 0.0.2-beta.8
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 +1 -0
- package/dist/index.cjs +58 -15
- package/dist/index.d.cts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +58 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@ You can customize the appearance of the component via the following props:
|
|
|
42
42
|
| `noResultsText` | The text to display when no suggestions are found. |
|
|
43
43
|
| `renderItem` | A custom render function for suggestion items, receiving the `item` and `isActive` state. |
|
|
44
44
|
| `renderNoResults` | A custom render function for the empty state, receiving the current `state`. |
|
|
45
|
+
| `debounceMs` | Delay in ms before API search. Defaults to `150` (min `50`). |
|
|
45
46
|
|
|
46
47
|
---
|
|
47
48
|
|
package/dist/index.cjs
CHANGED
|
@@ -42,7 +42,8 @@ var import_react = __toESM(require("react"), 1);
|
|
|
42
42
|
var DEFAULTS = {
|
|
43
43
|
API_URL: "https://api.pro6pp.nl/v2",
|
|
44
44
|
LIMIT: 1e3,
|
|
45
|
-
DEBOUNCE_MS:
|
|
45
|
+
DEBOUNCE_MS: 150,
|
|
46
|
+
MIN_DEBOUNCE_MS: 50
|
|
46
47
|
};
|
|
47
48
|
var PATTERNS = {
|
|
48
49
|
DIGITS_1_3: /^[0-9]{1,3}$/
|
|
@@ -59,6 +60,10 @@ var INITIAL_STATE = {
|
|
|
59
60
|
selectedSuggestionIndex: -1
|
|
60
61
|
};
|
|
61
62
|
var InferCore = class {
|
|
63
|
+
/**
|
|
64
|
+
* Initializes a new instance of the Infer engine.
|
|
65
|
+
* @param config The configuration object including API keys and callbacks.
|
|
66
|
+
*/
|
|
62
67
|
constructor(config) {
|
|
63
68
|
__publicField(this, "country");
|
|
64
69
|
__publicField(this, "authKey");
|
|
@@ -67,6 +72,10 @@ var InferCore = class {
|
|
|
67
72
|
__publicField(this, "fetcher");
|
|
68
73
|
__publicField(this, "onStateChange");
|
|
69
74
|
__publicField(this, "onSelect");
|
|
75
|
+
/**
|
|
76
|
+
* The current read-only state of the engine.
|
|
77
|
+
* Use `onStateChange` to react to updates.
|
|
78
|
+
*/
|
|
70
79
|
__publicField(this, "state");
|
|
71
80
|
__publicField(this, "abortController", null);
|
|
72
81
|
__publicField(this, "debouncedFetch");
|
|
@@ -81,11 +90,15 @@ var InferCore = class {
|
|
|
81
90
|
this.onSelect = config.onSelect || (() => {
|
|
82
91
|
});
|
|
83
92
|
this.state = { ...INITIAL_STATE };
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
93
|
+
const configDebounce = config.debounceMs !== void 0 ? config.debounceMs : DEFAULTS.DEBOUNCE_MS;
|
|
94
|
+
const debounceTime = Math.max(configDebounce, DEFAULTS.MIN_DEBOUNCE_MS);
|
|
95
|
+
this.debouncedFetch = this.debounce((val) => this.executeFetch(val), debounceTime);
|
|
88
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Processes new text input from the user.
|
|
99
|
+
* Triggers a debounced API request and updates the internal state.
|
|
100
|
+
* @param value The raw string from the input field.
|
|
101
|
+
*/
|
|
89
102
|
handleInput(value) {
|
|
90
103
|
if (this.isSelecting) {
|
|
91
104
|
this.isSelecting = false;
|
|
@@ -103,6 +116,14 @@ var InferCore = class {
|
|
|
103
116
|
}
|
|
104
117
|
this.debouncedFetch(value);
|
|
105
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Handles keyboard events for the input field.
|
|
121
|
+
* Supports:
|
|
122
|
+
* - `ArrowUp`/`ArrowDown`: Navigate through the suggestion list.
|
|
123
|
+
* - `Enter`: Select the currently highlighted suggestion.
|
|
124
|
+
* - `Space`: Automatically inserts a comma if a numeric house number is detected.
|
|
125
|
+
* @param event The keyboard event from the input element.
|
|
126
|
+
*/
|
|
106
127
|
handleKeyDown(event) {
|
|
107
128
|
const target = event.target;
|
|
108
129
|
if (!target) return;
|
|
@@ -144,6 +165,11 @@ var InferCore = class {
|
|
|
144
165
|
this.updateQueryAndFetch(next);
|
|
145
166
|
}
|
|
146
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Manually selects a suggestion or a string value.
|
|
170
|
+
* This is typically called when a user clicks a suggestion in the UI.
|
|
171
|
+
* @param item The suggestion object or string to select.
|
|
172
|
+
*/
|
|
147
173
|
selectItem(item) {
|
|
148
174
|
this.debouncedFetch.cancel();
|
|
149
175
|
if (this.abortController) {
|
|
@@ -379,21 +405,18 @@ var DEFAULT_STYLES = `
|
|
|
379
405
|
list-style: none !important;
|
|
380
406
|
padding: 0 !important;
|
|
381
407
|
margin: 0 !important;
|
|
382
|
-
overflow: hidden;
|
|
383
408
|
}
|
|
384
409
|
.pro6pp-item {
|
|
385
|
-
padding:
|
|
410
|
+
padding: 10px 16px;
|
|
386
411
|
cursor: pointer;
|
|
387
412
|
display: flex;
|
|
388
413
|
flex-direction: row;
|
|
389
414
|
align-items: center;
|
|
390
415
|
color: #000000;
|
|
391
416
|
font-size: 14px;
|
|
392
|
-
line-height: 1;
|
|
417
|
+
line-height: 1.2;
|
|
393
418
|
white-space: nowrap;
|
|
394
419
|
overflow: hidden;
|
|
395
|
-
border-radius: 0 !important;
|
|
396
|
-
margin: 0 !important;
|
|
397
420
|
}
|
|
398
421
|
.pro6pp-item:hover, .pro6pp-item--active {
|
|
399
422
|
background-color: #f5f5f5;
|
|
@@ -455,15 +478,19 @@ function useInfer(config) {
|
|
|
455
478
|
}
|
|
456
479
|
}
|
|
457
480
|
});
|
|
458
|
-
}, [config.country, config.authKey, config.limit]);
|
|
481
|
+
}, [config.country, config.authKey, config.limit, config.debounceMs]);
|
|
459
482
|
return {
|
|
483
|
+
/** The current UI state (suggestions, loading status, query, etc.). */
|
|
460
484
|
state,
|
|
485
|
+
/** The raw InferCore instance for manual control. */
|
|
461
486
|
core,
|
|
487
|
+
/** Pre-configured event handlers to spread onto an <input /> element. */
|
|
462
488
|
inputProps: {
|
|
463
489
|
value: state.query,
|
|
464
490
|
onChange: (e) => core.handleInput(e.target.value),
|
|
465
491
|
onKeyDown: (e) => core.handleKeyDown(e)
|
|
466
492
|
},
|
|
493
|
+
/** Function to manually select a specific suggestion. */
|
|
467
494
|
selectItem: (item) => core.selectItem(item)
|
|
468
495
|
};
|
|
469
496
|
}
|
|
@@ -479,7 +506,9 @@ var Pro6PPInfer = ({
|
|
|
479
506
|
...config
|
|
480
507
|
}) => {
|
|
481
508
|
const { state, selectItem, inputProps: coreInputProps } = useInfer(config);
|
|
509
|
+
const [isOpen, setIsOpen] = (0, import_react.useState)(false);
|
|
482
510
|
const inputRef = (0, import_react.useRef)(null);
|
|
511
|
+
const wrapperRef = (0, import_react.useRef)(null);
|
|
483
512
|
(0, import_react.useEffect)(() => {
|
|
484
513
|
if (disableDefaultStyles) return;
|
|
485
514
|
const styleId = "pro6pp-styles";
|
|
@@ -490,6 +519,15 @@ var Pro6PPInfer = ({
|
|
|
490
519
|
document.head.appendChild(styleEl);
|
|
491
520
|
}
|
|
492
521
|
}, [disableDefaultStyles]);
|
|
522
|
+
(0, import_react.useEffect)(() => {
|
|
523
|
+
const handleClickOutside = (event) => {
|
|
524
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
525
|
+
setIsOpen(false);
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
529
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
530
|
+
}, []);
|
|
493
531
|
const items = (0, import_react.useMemo)(() => {
|
|
494
532
|
return [
|
|
495
533
|
...state.cities.map((c) => ({ ...c, type: "city" })),
|
|
@@ -499,14 +537,15 @@ var Pro6PPInfer = ({
|
|
|
499
537
|
}, [state.cities, state.streets, state.suggestions]);
|
|
500
538
|
const handleSelect = (item) => {
|
|
501
539
|
selectItem(item);
|
|
540
|
+
setIsOpen(false);
|
|
502
541
|
if (!state.isValid && inputRef.current) {
|
|
503
542
|
inputRef.current.focus();
|
|
504
543
|
}
|
|
505
544
|
};
|
|
506
545
|
const hasResults = items.length > 0;
|
|
507
546
|
const showNoResults = !state.isLoading && !state.isError && state.query.length > 0 && !hasResults && !state.isValid;
|
|
508
|
-
const showDropdown = hasResults || showNoResults;
|
|
509
|
-
return /* @__PURE__ */ import_react.default.createElement("div", { className: `pro6pp-wrapper ${className || ""}`, style }, /* @__PURE__ */ import_react.default.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ import_react.default.createElement(
|
|
547
|
+
const showDropdown = isOpen && (hasResults || showNoResults);
|
|
548
|
+
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(
|
|
510
549
|
"input",
|
|
511
550
|
{
|
|
512
551
|
ref: inputRef,
|
|
@@ -515,11 +554,15 @@ var Pro6PPInfer = ({
|
|
|
515
554
|
placeholder,
|
|
516
555
|
autoComplete: "off",
|
|
517
556
|
...inputProps,
|
|
518
|
-
...coreInputProps
|
|
557
|
+
...coreInputProps,
|
|
558
|
+
onFocus: (e) => {
|
|
559
|
+
setIsOpen(true);
|
|
560
|
+
inputProps?.onFocus?.(e);
|
|
561
|
+
}
|
|
519
562
|
}
|
|
520
563
|
), state.isLoading && /* @__PURE__ */ import_react.default.createElement("div", { className: "pro6pp-loader" })), showDropdown && /* @__PURE__ */ import_react.default.createElement("ul", { className: "pro6pp-dropdown", role: "listbox" }, hasResults ? items.map((item, index) => {
|
|
521
564
|
const isActive = index === state.selectedSuggestionIndex;
|
|
522
|
-
const secondaryText = item.subtitle || item.count;
|
|
565
|
+
const secondaryText = item.subtitle || (item.count !== void 0 ? item.count : "");
|
|
523
566
|
const showChevron = item.value === void 0 || item.value === null;
|
|
524
567
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
525
568
|
"li",
|
package/dist/index.d.cts
CHANGED
|
@@ -2,26 +2,56 @@ import React from 'react';
|
|
|
2
2
|
import { InferConfig, InferState, InferCore, InferResult } from '@pro6pp/infer-core';
|
|
3
3
|
export { AddressValue, CountryCode, Fetcher, InferConfig, InferResult, InferState, Stage } from '@pro6pp/infer-core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A headless React hook that provides the logic for address search using the Infer API.
|
|
7
|
+
* @param config The engine configuration (authKey, country, etc.).
|
|
8
|
+
* @returns An object containing the current state, the core instance, and pre-bound input props.
|
|
9
|
+
*/
|
|
5
10
|
declare function useInfer(config: InferConfig): {
|
|
11
|
+
/** The current UI state (suggestions, loading status, query, etc.). */
|
|
6
12
|
state: InferState;
|
|
13
|
+
/** The raw InferCore instance for manual control. */
|
|
7
14
|
core: InferCore;
|
|
15
|
+
/** Pre-configured event handlers to spread onto an <input /> element. */
|
|
8
16
|
inputProps: {
|
|
9
17
|
value: string;
|
|
10
18
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
11
19
|
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
12
20
|
};
|
|
21
|
+
/** Function to manually select a specific suggestion. */
|
|
13
22
|
selectItem: (item: InferResult | string) => void;
|
|
14
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Props for the Pro6PPInfer component.
|
|
26
|
+
*/
|
|
15
27
|
interface Pro6PPInferProps extends InferConfig {
|
|
28
|
+
/** Optional CSS class for the wrapper div. */
|
|
16
29
|
className?: string;
|
|
30
|
+
/** Optional inline styles for the wrapper div. */
|
|
17
31
|
style?: React.CSSProperties;
|
|
32
|
+
/** Attributes to pass directly to the underlying input element. */
|
|
18
33
|
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
|
|
34
|
+
/** * Custom placeholder text.
|
|
35
|
+
* @default 'Start typing an address...'
|
|
36
|
+
*/
|
|
19
37
|
placeholder?: string;
|
|
38
|
+
/** A custom render function for individual suggestion items. */
|
|
20
39
|
renderItem?: (item: InferResult, isActive: boolean) => React.ReactNode;
|
|
40
|
+
/** * If true, prevents the default CSS theme from being injected.
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
21
43
|
disableDefaultStyles?: boolean;
|
|
44
|
+
/** * The text to show when no results are found.
|
|
45
|
+
* @default 'No results found'
|
|
46
|
+
*/
|
|
22
47
|
noResultsText?: string;
|
|
48
|
+
/** A custom render function for the "no results" state. */
|
|
23
49
|
renderNoResults?: (state: InferState) => React.ReactNode;
|
|
24
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* A styled React component for Pro6PP Infer API.
|
|
53
|
+
* Includes styling, keyboard navigation, and loading states.
|
|
54
|
+
*/
|
|
25
55
|
declare const Pro6PPInfer: React.FC<Pro6PPInferProps>;
|
|
26
56
|
|
|
27
57
|
export { Pro6PPInfer, type Pro6PPInferProps, useInfer };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,26 +2,56 @@ import React from 'react';
|
|
|
2
2
|
import { InferConfig, InferState, InferCore, InferResult } from '@pro6pp/infer-core';
|
|
3
3
|
export { AddressValue, CountryCode, Fetcher, InferConfig, InferResult, InferState, Stage } from '@pro6pp/infer-core';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* A headless React hook that provides the logic for address search using the Infer API.
|
|
7
|
+
* @param config The engine configuration (authKey, country, etc.).
|
|
8
|
+
* @returns An object containing the current state, the core instance, and pre-bound input props.
|
|
9
|
+
*/
|
|
5
10
|
declare function useInfer(config: InferConfig): {
|
|
11
|
+
/** The current UI state (suggestions, loading status, query, etc.). */
|
|
6
12
|
state: InferState;
|
|
13
|
+
/** The raw InferCore instance for manual control. */
|
|
7
14
|
core: InferCore;
|
|
15
|
+
/** Pre-configured event handlers to spread onto an <input /> element. */
|
|
8
16
|
inputProps: {
|
|
9
17
|
value: string;
|
|
10
18
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
11
19
|
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
12
20
|
};
|
|
21
|
+
/** Function to manually select a specific suggestion. */
|
|
13
22
|
selectItem: (item: InferResult | string) => void;
|
|
14
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Props for the Pro6PPInfer component.
|
|
26
|
+
*/
|
|
15
27
|
interface Pro6PPInferProps extends InferConfig {
|
|
28
|
+
/** Optional CSS class for the wrapper div. */
|
|
16
29
|
className?: string;
|
|
30
|
+
/** Optional inline styles for the wrapper div. */
|
|
17
31
|
style?: React.CSSProperties;
|
|
32
|
+
/** Attributes to pass directly to the underlying input element. */
|
|
18
33
|
inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
|
|
34
|
+
/** * Custom placeholder text.
|
|
35
|
+
* @default 'Start typing an address...'
|
|
36
|
+
*/
|
|
19
37
|
placeholder?: string;
|
|
38
|
+
/** A custom render function for individual suggestion items. */
|
|
20
39
|
renderItem?: (item: InferResult, isActive: boolean) => React.ReactNode;
|
|
40
|
+
/** * If true, prevents the default CSS theme from being injected.
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
21
43
|
disableDefaultStyles?: boolean;
|
|
44
|
+
/** * The text to show when no results are found.
|
|
45
|
+
* @default 'No results found'
|
|
46
|
+
*/
|
|
22
47
|
noResultsText?: string;
|
|
48
|
+
/** A custom render function for the "no results" state. */
|
|
23
49
|
renderNoResults?: (state: InferState) => React.ReactNode;
|
|
24
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* A styled React component for Pro6PP Infer API.
|
|
53
|
+
* Includes styling, keyboard navigation, and loading states.
|
|
54
|
+
*/
|
|
25
55
|
declare const Pro6PPInfer: React.FC<Pro6PPInferProps>;
|
|
26
56
|
|
|
27
57
|
export { Pro6PPInfer, type Pro6PPInferProps, useInfer };
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,8 @@ import React, { useState, useMemo, useEffect, useRef } from "react";
|
|
|
9
9
|
var DEFAULTS = {
|
|
10
10
|
API_URL: "https://api.pro6pp.nl/v2",
|
|
11
11
|
LIMIT: 1e3,
|
|
12
|
-
DEBOUNCE_MS:
|
|
12
|
+
DEBOUNCE_MS: 150,
|
|
13
|
+
MIN_DEBOUNCE_MS: 50
|
|
13
14
|
};
|
|
14
15
|
var PATTERNS = {
|
|
15
16
|
DIGITS_1_3: /^[0-9]{1,3}$/
|
|
@@ -26,6 +27,10 @@ var INITIAL_STATE = {
|
|
|
26
27
|
selectedSuggestionIndex: -1
|
|
27
28
|
};
|
|
28
29
|
var InferCore = class {
|
|
30
|
+
/**
|
|
31
|
+
* Initializes a new instance of the Infer engine.
|
|
32
|
+
* @param config The configuration object including API keys and callbacks.
|
|
33
|
+
*/
|
|
29
34
|
constructor(config) {
|
|
30
35
|
__publicField(this, "country");
|
|
31
36
|
__publicField(this, "authKey");
|
|
@@ -34,6 +39,10 @@ var InferCore = class {
|
|
|
34
39
|
__publicField(this, "fetcher");
|
|
35
40
|
__publicField(this, "onStateChange");
|
|
36
41
|
__publicField(this, "onSelect");
|
|
42
|
+
/**
|
|
43
|
+
* The current read-only state of the engine.
|
|
44
|
+
* Use `onStateChange` to react to updates.
|
|
45
|
+
*/
|
|
37
46
|
__publicField(this, "state");
|
|
38
47
|
__publicField(this, "abortController", null);
|
|
39
48
|
__publicField(this, "debouncedFetch");
|
|
@@ -48,11 +57,15 @@ var InferCore = class {
|
|
|
48
57
|
this.onSelect = config.onSelect || (() => {
|
|
49
58
|
});
|
|
50
59
|
this.state = { ...INITIAL_STATE };
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
);
|
|
60
|
+
const configDebounce = config.debounceMs !== void 0 ? config.debounceMs : DEFAULTS.DEBOUNCE_MS;
|
|
61
|
+
const debounceTime = Math.max(configDebounce, DEFAULTS.MIN_DEBOUNCE_MS);
|
|
62
|
+
this.debouncedFetch = this.debounce((val) => this.executeFetch(val), debounceTime);
|
|
55
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Processes new text input from the user.
|
|
66
|
+
* Triggers a debounced API request and updates the internal state.
|
|
67
|
+
* @param value The raw string from the input field.
|
|
68
|
+
*/
|
|
56
69
|
handleInput(value) {
|
|
57
70
|
if (this.isSelecting) {
|
|
58
71
|
this.isSelecting = false;
|
|
@@ -70,6 +83,14 @@ var InferCore = class {
|
|
|
70
83
|
}
|
|
71
84
|
this.debouncedFetch(value);
|
|
72
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Handles keyboard events for the input field.
|
|
88
|
+
* Supports:
|
|
89
|
+
* - `ArrowUp`/`ArrowDown`: Navigate through the suggestion list.
|
|
90
|
+
* - `Enter`: Select the currently highlighted suggestion.
|
|
91
|
+
* - `Space`: Automatically inserts a comma if a numeric house number is detected.
|
|
92
|
+
* @param event The keyboard event from the input element.
|
|
93
|
+
*/
|
|
73
94
|
handleKeyDown(event) {
|
|
74
95
|
const target = event.target;
|
|
75
96
|
if (!target) return;
|
|
@@ -111,6 +132,11 @@ var InferCore = class {
|
|
|
111
132
|
this.updateQueryAndFetch(next);
|
|
112
133
|
}
|
|
113
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Manually selects a suggestion or a string value.
|
|
137
|
+
* This is typically called when a user clicks a suggestion in the UI.
|
|
138
|
+
* @param item The suggestion object or string to select.
|
|
139
|
+
*/
|
|
114
140
|
selectItem(item) {
|
|
115
141
|
this.debouncedFetch.cancel();
|
|
116
142
|
if (this.abortController) {
|
|
@@ -346,21 +372,18 @@ var DEFAULT_STYLES = `
|
|
|
346
372
|
list-style: none !important;
|
|
347
373
|
padding: 0 !important;
|
|
348
374
|
margin: 0 !important;
|
|
349
|
-
overflow: hidden;
|
|
350
375
|
}
|
|
351
376
|
.pro6pp-item {
|
|
352
|
-
padding:
|
|
377
|
+
padding: 10px 16px;
|
|
353
378
|
cursor: pointer;
|
|
354
379
|
display: flex;
|
|
355
380
|
flex-direction: row;
|
|
356
381
|
align-items: center;
|
|
357
382
|
color: #000000;
|
|
358
383
|
font-size: 14px;
|
|
359
|
-
line-height: 1;
|
|
384
|
+
line-height: 1.2;
|
|
360
385
|
white-space: nowrap;
|
|
361
386
|
overflow: hidden;
|
|
362
|
-
border-radius: 0 !important;
|
|
363
|
-
margin: 0 !important;
|
|
364
387
|
}
|
|
365
388
|
.pro6pp-item:hover, .pro6pp-item--active {
|
|
366
389
|
background-color: #f5f5f5;
|
|
@@ -422,15 +445,19 @@ function useInfer(config) {
|
|
|
422
445
|
}
|
|
423
446
|
}
|
|
424
447
|
});
|
|
425
|
-
}, [config.country, config.authKey, config.limit]);
|
|
448
|
+
}, [config.country, config.authKey, config.limit, config.debounceMs]);
|
|
426
449
|
return {
|
|
450
|
+
/** The current UI state (suggestions, loading status, query, etc.). */
|
|
427
451
|
state,
|
|
452
|
+
/** The raw InferCore instance for manual control. */
|
|
428
453
|
core,
|
|
454
|
+
/** Pre-configured event handlers to spread onto an <input /> element. */
|
|
429
455
|
inputProps: {
|
|
430
456
|
value: state.query,
|
|
431
457
|
onChange: (e) => core.handleInput(e.target.value),
|
|
432
458
|
onKeyDown: (e) => core.handleKeyDown(e)
|
|
433
459
|
},
|
|
460
|
+
/** Function to manually select a specific suggestion. */
|
|
434
461
|
selectItem: (item) => core.selectItem(item)
|
|
435
462
|
};
|
|
436
463
|
}
|
|
@@ -446,7 +473,9 @@ var Pro6PPInfer = ({
|
|
|
446
473
|
...config
|
|
447
474
|
}) => {
|
|
448
475
|
const { state, selectItem, inputProps: coreInputProps } = useInfer(config);
|
|
476
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
449
477
|
const inputRef = useRef(null);
|
|
478
|
+
const wrapperRef = useRef(null);
|
|
450
479
|
useEffect(() => {
|
|
451
480
|
if (disableDefaultStyles) return;
|
|
452
481
|
const styleId = "pro6pp-styles";
|
|
@@ -457,6 +486,15 @@ var Pro6PPInfer = ({
|
|
|
457
486
|
document.head.appendChild(styleEl);
|
|
458
487
|
}
|
|
459
488
|
}, [disableDefaultStyles]);
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
const handleClickOutside = (event) => {
|
|
491
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
492
|
+
setIsOpen(false);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
496
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
497
|
+
}, []);
|
|
460
498
|
const items = useMemo(() => {
|
|
461
499
|
return [
|
|
462
500
|
...state.cities.map((c) => ({ ...c, type: "city" })),
|
|
@@ -466,14 +504,15 @@ var Pro6PPInfer = ({
|
|
|
466
504
|
}, [state.cities, state.streets, state.suggestions]);
|
|
467
505
|
const handleSelect = (item) => {
|
|
468
506
|
selectItem(item);
|
|
507
|
+
setIsOpen(false);
|
|
469
508
|
if (!state.isValid && inputRef.current) {
|
|
470
509
|
inputRef.current.focus();
|
|
471
510
|
}
|
|
472
511
|
};
|
|
473
512
|
const hasResults = items.length > 0;
|
|
474
513
|
const showNoResults = !state.isLoading && !state.isError && state.query.length > 0 && !hasResults && !state.isValid;
|
|
475
|
-
const showDropdown = hasResults || showNoResults;
|
|
476
|
-
return /* @__PURE__ */ React.createElement("div", { className: `pro6pp-wrapper ${className || ""}`, style }, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(
|
|
514
|
+
const showDropdown = isOpen && (hasResults || showNoResults);
|
|
515
|
+
return /* @__PURE__ */ React.createElement("div", { ref: wrapperRef, className: `pro6pp-wrapper ${className || ""}`, style }, /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(
|
|
477
516
|
"input",
|
|
478
517
|
{
|
|
479
518
|
ref: inputRef,
|
|
@@ -482,11 +521,15 @@ var Pro6PPInfer = ({
|
|
|
482
521
|
placeholder,
|
|
483
522
|
autoComplete: "off",
|
|
484
523
|
...inputProps,
|
|
485
|
-
...coreInputProps
|
|
524
|
+
...coreInputProps,
|
|
525
|
+
onFocus: (e) => {
|
|
526
|
+
setIsOpen(true);
|
|
527
|
+
inputProps?.onFocus?.(e);
|
|
528
|
+
}
|
|
486
529
|
}
|
|
487
530
|
), state.isLoading && /* @__PURE__ */ React.createElement("div", { className: "pro6pp-loader" })), showDropdown && /* @__PURE__ */ React.createElement("ul", { className: "pro6pp-dropdown", role: "listbox" }, hasResults ? items.map((item, index) => {
|
|
488
531
|
const isActive = index === state.selectedSuggestionIndex;
|
|
489
|
-
const secondaryText = item.subtitle || item.count;
|
|
532
|
+
const secondaryText = item.subtitle || (item.count !== void 0 ? item.count : "");
|
|
490
533
|
const showChevron = item.value === void 0 || item.value === null;
|
|
491
534
|
return /* @__PURE__ */ React.createElement(
|
|
492
535
|
"li",
|
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"url": "https://github.com/pro6pp/infer-sdk/issues"
|
|
21
21
|
},
|
|
22
22
|
"sideEffects": false,
|
|
23
|
-
"version": "0.0.2-beta.
|
|
23
|
+
"version": "0.0.2-beta.8",
|
|
24
24
|
"main": "./dist/index.cjs",
|
|
25
25
|
"module": "./dist/index.js",
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"react": ">=16"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@pro6pp/infer-core": "0.0.2-beta.
|
|
49
|
+
"@pro6pp/infer-core": "0.0.2-beta.6"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@testing-library/dom": "^10.4.1",
|