JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Auto-complete</title>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Open Sans', sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
h1 {
text-align: center;
position: absolute;
margin-top: 10%;
letter-spacing: 1px;
margin-left: 20px;
font-weight: 300;
}
#input {
background: transparent;
outline: none;
border: 1px solid grey;
z-index: 10;
width: 582px;
height: 44px;
font-size: 25px;
border-radius: 20px;
padding-left: 20px;
padding-top: 10px;
margin-top: 35%;
}
.div {
width: auto;
display: inline-block;
visibility: hidden;
position: fixed;
overflow: auto;
font-size: 25px;
}
#time {
font-style: italic;
font-size: 13px;
margin-left: 20px;
text-decoration: underline;
letter-spacing: 0.5px;
}
</style>
</head>
<body>
<div>
<h1>Auto-complete...</h1>
<div contenteditable="true" id="input"></div>
<div id="time"></div>
<div id='fake-div' class='div'></div>
<script src="index.js"></script>
</div>
</body>
</html>
JavaScript
const $input = document.getElementById('input');
const $time = document.getElementById('time');
const $fakeDiv = document.getElementById('fake-div');
const r = $input.getBoundingClientRect();
let INPUT_DEBOUNCE = null;
const $span = document.createElement('span');
const css = getComputedStyle($input);
$span.style.cssText = `
width: ${r.width}px;
height: ${r.height}px;
left: ${r.left}px;
top: ${r.top}px;
z-index: -10;
opacity: 0.4;
position: absolute;
white-space: pre-wrap;
font-size: ${parseInt(css.fontSize)}px;
padding-left: ${parseInt(css.paddingLeft)}px;
padding-top: ${parseInt(css.paddingTop) + 1}px;
`;
document.body.appendChild($span);
class Trie {
constructor() {
this.trie = null;
this.suggestions = [];
}
newNode() {
return {
isLeaf: false,
children: {}
}
}
add(word) {
if (!this.trie) this.trie = this.newNode();
let root = this.trie;
for (const letter of word) {
if (!(letter in root.children)) {
root.children[letter] = this.newNode();
}
root = root.children[letter];
}
root.isLeaf = true;
}
find(word) {
let root = this.trie;
for (const letter of word) {
if (letter in root.children) {
root = root.children[letter];
} else {
return null;
}
}
return root;
}
traverse(root, word) {
if (root.isLeaf) {
this.suggestions.push(word);
return;
}
for (const letter in root.children) {
this.traverse(root.children[letter], word + letter);
}
}
complete(word, CHILDREN = null) {
const root = this.find(word);
if (!root) return this.suggestions; // cannot suggest anything
const children = root.children;
let spread = 0;
for (const letter in children) {
this.traverse(children[letter], word + letter);
spread++;
if (CHILDREN && spread === CHILDREN) break;
}
return this.suggestions;
}
clear() {
...