Skip to content

Commit 63fcb89

Browse files
Add Typescript (#2)
* converted component to typescript * fix project * update version and restore library name Co-authored-by: vvillait88 <vvillait88@yahoo.com>
1 parent f49ad37 commit 63fcb89

File tree

9 files changed

+452
-64
lines changed

9 files changed

+452
-64
lines changed

.eslintrc.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,17 @@ module.exports = {
66
extends: [
77
'plugin:react/recommended',
88
'airbnb',
9+
'airbnb-typescript',
910
],
10-
parserOptions: {
11-
ecmaFeatures: {
12-
jsx: true,
13-
},
14-
ecmaVersion: 'latest',
15-
sourceType: 'module',
16-
},
1711
plugins: [
1812
'react',
1913
'unused-imports',
2014
],
15+
parserOptions: {
16+
project: './tsconfig.json',
17+
},
2118
rules: {
19+
'react/require-default-props': 'off',
2220
'react/prop-types': 'off',
2321
'react/jsx-filename-extension': 'off',
2422
'jsx-a11y/mouse-events-have-key-events': 'off',

example/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6323,6 +6323,11 @@ path-type@^4.0.0:
63236323
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
63246324
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
63256325

6326+
pdl-react-autocomplete@*:
6327+
version "1.0.0"
6328+
resolved "https://registry.yarnpkg.com/pdl-react-autocomplete/-/pdl-react-autocomplete-1.0.0.tgz#64ed25b6e12afa1e37d09a4645c08af62dd2b9be"
6329+
integrity sha512-cSOL0XBnOfFxpOIVjkK+KDseIMHHn8Lysc1Q1v/3QMjqW5+88WCNNDQA81xc1JYwh3heh7wo7rmnki50FpTbvA==
6330+
63266331
performance-now@^2.1.0:
63276332
version "2.1.0"
63286333
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"

package.json

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
22
"name": "pdl-react-autocomplete",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "A react component for the People Data Labs Autocomplete API",
5-
"source": "src/index.js",
6-
"main": "dist/main.js",
5+
"source": "src/index.ts",
6+
"main": "dist/index.js",
77
"module": "dist/index.mjs",
8+
"types": "dist/index.d.ts",
89
"targets": {
910
"main": {
1011
"includeNodeModules": false,
@@ -37,15 +38,23 @@
3738
"url": "https://github.com/peopledatalabs/pdl-react-autocomplete/issues"
3839
},
3940
"devDependencies": {
41+
"@parcel/packager-ts": "^2.5.0",
4042
"@parcel/transformer-react-refresh-wrap": "^2.5.0",
43+
"@parcel/transformer-typescript-types": "^2.5.0",
44+
"@types/react": "^18.0.8",
45+
"@types/react-dom": "^18.0.3",
46+
"@typescript-eslint/eslint-plugin": "^5.22.0",
47+
"@typescript-eslint/parser": "^5.22.0",
4148
"eslint": "^7.32.0",
4249
"eslint-config-airbnb": "^19.0.4",
50+
"eslint-config-airbnb-typescript": "^17.0.0",
4351
"eslint-plugin-import": "^2.26.0",
4452
"eslint-plugin-jsx-a11y": "^6.5.1",
4553
"eslint-plugin-react": "^7.28.0",
4654
"eslint-plugin-react-hooks": "^4.5.0",
4755
"eslint-plugin-unused-imports": "^2.0.0",
48-
"parcel": "^2.5.0"
56+
"parcel": "^2.5.0",
57+
"typescript": "^4.6.4"
4958
},
5059
"peerDependencies": {
5160
"react": ">= 16.8.0",

pdl-tsconfig/base.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://json.schemastore.org/tsconfig",
3+
"display": "Default",
4+
"compilerOptions": {
5+
"composite": false,
6+
"declaration": true,
7+
"declarationMap": true,
8+
"esModuleInterop": true,
9+
"forceConsistentCasingInFileNames": true,
10+
"inlineSources": false,
11+
"isolatedModules": true,
12+
"moduleResolution": "node",
13+
"noUnusedLocals": false,
14+
"noUnusedParameters": false,
15+
"preserveWatchOutput": true,
16+
"skipLibCheck": true,
17+
"strict": true
18+
},
19+
"exclude": ["node_modules"]
20+
}

pdl-tsconfig/react-library.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://json.schemastore.org/tsconfig",
3+
"display": "React Library",
4+
"extends": "./base.json",
5+
"compilerOptions": {
6+
"lib": ["dom", "ES2015"],
7+
"module": "ESNext",
8+
"target": "ES6",
9+
"jsx": "react-jsx"
10+
}
11+
}

src/Autocomplete.js renamed to src/Autocomplete.tsx

Lines changed: 79 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,30 @@
22
import React, { useState, useEffect, useRef } from 'react';
33
import './index.css';
44

5+
interface AutocompleteProps {
6+
field: string,
7+
size?: number,
8+
onTermSelected: (term: string) => void,
9+
apiKey: string
10+
}
11+
512
function Autocomplete({
613
field, size, onTermSelected, apiKey,
7-
}) {
14+
}: AutocompleteProps) {
815
const [searchTerm, setSearchTerm] = useState('');
9-
const [searchResults, setSearchResults] = useState([]);
16+
const [searchResults, setSearchResults] = useState < { name: string, count: number }[] >([]);
1017
const [focus, setFocus] = useState(false);
1118
const [errorMessage, setErrorMessage] = useState('');
1219
const [isLoading, setIsLoading] = useState(false);
1320
const [isActive, setIsActive] = useState(0);
1421

1522
const timer = useRef(null);
1623

17-
const autoInput = document.querySelector('.pdl-auto-input');
18-
1924
const clearResults = () => {
2025
setSearchResults([]);
2126
};
2227

23-
const fetchResults = async () => {
28+
const fetchResults = async (): Promise<void> => {
2429
setErrorMessage('');
2530
setIsActive(0);
2631

@@ -29,8 +34,10 @@ function Autocomplete({
2934
setIsLoading(true);
3035

3136
if (searchTerm.length === 0) {
37+
const debouncedTimeout: null | ReturnType<typeof setTimeout> = timer.current;
3238
setIsLoading(false);
33-
clearTimeout(timer.current);
39+
if (debouncedTimeout !== null) clearTimeout(debouncedTimeout); //
40+
3441
clearResults();
3542
return;
3643
}
@@ -81,11 +88,12 @@ function Autocomplete({
8188
setIsLoading(false);
8289
};
8390

84-
const debounce = (cb, delay = 250) => {
85-
clearTimeout(timer.current);
91+
const debounce = (cb: () => void, delay = 250) => {
92+
let debouncedTimeout: ReturnType<typeof setTimeout> | null = timer.current;
93+
if (debouncedTimeout !== null) clearTimeout(debouncedTimeout);
8694

8795
return () => {
88-
timer.current = setTimeout(() => {
96+
debouncedTimeout = setTimeout(() => {
8997
cb();
9098
}, delay);
9199
};
@@ -97,51 +105,69 @@ function Autocomplete({
97105

98106
const blur = () => {
99107
setFocus(false);
100-
autoInput.blur();
108+
const autoInput: HTMLInputElement | null = document.querySelector('.pdl-auto-input');
109+
if (autoInput !== null) { autoInput.blur(); }
101110
};
102111

103-
const selectHandler = (e) => {
112+
const mouseDownHandler = (e: React.MouseEvent) => {
104113
if (searchResults.length === 0) return;
105114

106115
if (e.type === 'mousedown') {
107-
const selected = document.querySelector('.pdl-selected');
108-
const selectedTerm = selected.getAttribute('value');
109-
setSearchTerm(selectedTerm);
110-
onTermSelected(selectedTerm);
111-
blur();
112-
return;
113-
}
116+
const selected: HTMLInputElement | null = document?.querySelector('.pdl-selected');
114117

115-
switch (e.key) {
116-
case 'Enter': {
117-
const selected = document.querySelector('.pdl-selected');
118-
const selectedTerm = selected.getAttribute('value');
119-
setSearchTerm(selectedTerm);
120-
onTermSelected(selectedTerm);
121-
blur();
122-
break;
123-
}
124-
case 'ArrowDown':
125-
if (isActive === (searchResults.length - 1) || (isActive === null)) {
126-
setIsActive(0);
127-
} else {
128-
const toAdd = isActive;
129-
setIsActive(toAdd + 1);
118+
if (selected !== null) {
119+
const selectedTerm: string | null = selected?.getAttribute('data-value');
120+
121+
if (selectedTerm !== null) {
122+
setSearchTerm(selectedTerm);
123+
onTermSelected(selectedTerm);
130124
}
131-
break;
132-
case 'ArrowUp':
133-
if (isActive === 0 || isActive === null) {
134-
setIsActive(searchResults.length - 1);
135-
} else {
136-
const toSubtract = isActive;
137-
setIsActive(toSubtract - 1);
125+
}
126+
}
127+
blur();
128+
};
129+
130+
const keyDownHandler = (e: React.KeyboardEvent) => {
131+
if (searchResults.length === 0) return;
132+
133+
if (e.type === 'keydown') {
134+
switch (e.key) {
135+
case 'Enter': {
136+
const selected: HTMLInputElement | null = document.querySelector('.pdl-selected');
137+
138+
if (selected !== null) {
139+
const selectedTerm = selected.getAttribute('data-value');
140+
141+
if (selectedTerm !== null) {
142+
setSearchTerm(selectedTerm);
143+
onTermSelected(selectedTerm);
144+
}
145+
}
146+
blur();
147+
break;
138148
}
139-
break;
140-
case 'Escape':
141-
blur();
142-
break;
143-
default:
144-
break;
149+
case 'ArrowDown':
150+
if (isActive === (searchResults.length - 1) || (isActive === null)) {
151+
setIsActive(0);
152+
} else {
153+
const toAdd = isActive;
154+
setIsActive(toAdd + 1);
155+
}
156+
break;
157+
case 'ArrowUp':
158+
if (isActive === 0 || isActive === null) {
159+
setIsActive(searchResults.length - 1);
160+
} else {
161+
const toSubtract = isActive;
162+
setIsActive(toSubtract - 1);
163+
}
164+
break;
165+
case 'Escape':
166+
blur();
167+
break;
168+
default:
169+
break;
170+
}
145171
}
146172
};
147173

@@ -184,7 +210,7 @@ function Autocomplete({
184210
onChange={(e) => setSearchTerm(e.currentTarget.value)}
185211
onFocus={() => setFocus(true)}
186212
onBlur={() => setFocus(false)}
187-
onKeyDown={(e) => selectHandler(e)}
213+
onKeyDown={(e) => keyDownHandler(e)}
188214
/>
189215
<div className={`pdl-loading-spinner ${isLoading ? '' : 'pdl-dn'}`} />
190216
</div>
@@ -195,10 +221,13 @@ function Autocomplete({
195221
<div
196222
key={idx}
197223
className={`pdl-suggestion pdl-df pdl-row ${idx === isActive ? 'pdl-selected' : ''}`}
198-
value={searchResult.name}
224+
data-value={searchResult.name}
199225
data-idx={idx}
200-
onMouseOver={(e) => setIsActive(parseInt(e.currentTarget.dataset.idx, 10))}
201-
onMouseDown={(e) => selectHandler(e)}
226+
onMouseOver={(e) => {
227+
const indexString: string | undefined = e.currentTarget.dataset.idx;
228+
if (indexString) setIsActive(parseInt(indexString, 10));
229+
}}
230+
onMouseDown={(e) => mouseDownHandler(e)}
202231
>
203232
<div className="pdl-suggestion-name">
204233
{searchResult.name}
File renamed without changes.

tsconfig.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": "./pdl-tsconfig/react-library.json",
3+
"include": ["src", ".eslintrc.js"],
4+
"exclude": ["dist", "example", "node_modules"]
5+
}

0 commit comments

Comments
 (0)