JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.5/mithril.min.js"></script>
<h4>自動補完2</h4>
<div id="root"></div>
SCSS
.filterInput {
display: inline-block;
box-shadow: 0 1px 1px rgba(160,160,160,0.2) inset;
border-width: 1px;
border-style: solid;
border-color: #c8c8c8;
border-radius: 3px;
position: relative;
padding: 2px;
background-color: #ffffff;
.currentFilters {
display: inline-block;
list-style-type: none;
padding: 0px;
margin: 0px;
li {
display: inline-block;
margin: 0px 3px;
padding: 0px 3px;
border-radius: 2px;
background-color: #d9eafe!important;
box-shadow: 0 0 0 1px #c0dcfd;
a {
margin: 0px 3px;
}
}
}
.form {
margin: 2px;
display: inline-block;
input {
border-style: none;
}
.suggestions {
position: absolute;
background-color: #eeeeee;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1000;
list-style-type: none;
padding: 10px;
margin: 0px;
.selected {
background-color: #d9eafe;
}
}
}
}
JavaScript
'use strict';
// Based on https://gist.github.com/StephanHoyer/ea6d1e9c5ea7a9225639
// ヘルパー関数
function last(array) {
return array.slice(-1)[0];
}
function remove(array, filter) {
const index = array.indexOf(filter);
if (index !== -1) {
array.splice(index, 1);
}
}
const code = {
enter: 13,
backspace: 8,
del: 46,
left: 37,
up: 38,
right: 39,
down: 40
};
function sameAs(filterA) {
return function (filterB) {
return filterA.type === filterB.type && filterA.label === filterB.label;
};
}
function not(fn) {
return function(obj) {
return !fn(obj);
};
}
function emptyArrayFn() {
return [];
}
function minMax(a, b, c) {
return Math.max(a, Math.min(b, c));
}
// 補完コンポーネント
const FilterInput = {
controller: function (options) {
var scope = {};
options = options || {};
options.getSuggestions = options.getSuggestions || emptyArrayFn;
options.getCurrentFilters = options.getCurrentFilters || emptyArrayFn;
scope.currentFilters = options.getCurrentFilters;
scope.inputValue = '';
function exists(filter) {
return scope.currentFilters().some(sameAs(filter));
}
function updateSuggestions() {
if (scope.inputValue) {
scope.suggestions = options.getSuggestions(scope.inputValue).filter(not(exists));
} else {
scope.suggestions = [];
}
}
updateSuggestions();
scope.oninput = function (event) {
scope.inputValue = event.target.value;
delete scope.selectedSuggestion;
delete scope.selectedFilter;
updateSuggestions();
};
scope.add = function (filter) {
return function () {
if (!exists(filter)) {
scope.currentFilters().push(filter);
options.onAddFilter && options.onAddFilter(filter);
scope.inputValue = '';
updateSuggestions();
}
};
};
scope.remove = function (filter) {
return function () {
...