This commit is contained in:
shibafu
2020-05-17 17:11:35 +09:00
parent 0ca16459a4
commit 196819270b
7 changed files with 183 additions and 3 deletions

View File

@@ -2,6 +2,9 @@ import Vue from 'vue';
import TagInput from './components/TagInput.vue';
import MetadataPreview from './components/MetadataPreview.vue';
import { fetchGet, ResponseError } from './fetch';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import TagInput2 from './components/TagInput2';
export const bus = new Vue({ name: 'EventBus' });
@@ -66,3 +69,8 @@ new Vue({
},
},
});
ReactDOM.render(
React.createElement(TagInput2, { id: 'tagInput2', name: 'tags2', value: '', isInvalid: false }),
document.querySelector('#tagInput2')
);

View File

@@ -0,0 +1,10 @@
:local {
.tag-item {
cursor: pointer;
}
.tag-input {
border: 0;
outline: 0;
}
}

View File

@@ -0,0 +1,76 @@
import * as React from 'react';
import { useState, useRef } from 'react';
import * as classNames from 'classnames';
const styles = require('./TagInput.scss'); // TODO: 読めてない
type TagInputProps = {
id: string;
name: string;
value: string;
isInvalid: boolean;
};
const TagInput: React.FC<TagInputProps> = ({ id, name, value, isInvalid }) => {
const [tags, setTags] = useState(value.trim() !== '' ? value.trim().split(' ') : []);
const [buffer, setBuffer] = useState('');
const containerClass = classNames('form-control', 'h-auto', { 'is-invalid': isInvalid });
const inputRef = useRef<HTMLInputElement>(null);
const removeTag = (index: number) => {
setTags(tags.filter((v, i) => i != index));
};
const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (buffer.trim() !== '') {
switch (event.key) {
case 'Tab':
case 'Enter':
case ' ':
if ((event as any).isComposing !== true) {
setTags(tags.concat(buffer.trim()));
setBuffer('');
}
event.preventDefault();
break;
case 'Unidentified':
// 実際にテキストボックスに入力されている文字を見に行く (フォールバック処理)
const nativeEvent = event.nativeEvent;
if (nativeEvent.srcElement && (nativeEvent.srcElement as HTMLInputElement).value.slice(-1) == ' ') {
setTags(tags.concat(buffer.trim()));
setBuffer('');
event.preventDefault();
}
break;
}
} else if (event.key === 'Enter') {
// 誤爆防止
event.preventDefault();
}
};
return (
<div className={containerClass} onClick={() => inputRef.current?.focus()}>
<input name={name} type="hidden" value={tags.join(' ')} />
<ul className="list-inline d-inline">
{tags.map((tag, i) => (
<li
key={i}
className={classNames('list-inline-item', 'badge', 'badge-primary', styles.tagItem)}
onClick={() => removeTag(i)}
>
<span className="oi oi-tag" /> {tag} | x
</li>
))}
</ul>
<input
id={id}
ref={inputRef}
type="text"
className={styles.tagInput}
value={buffer}
onChange={(e) => setBuffer(e.target.value)}
onKeyDown={onKeyDown}
/>
</div>
);
};
export default TagInput;

View File

@@ -40,6 +40,7 @@
<div class="form-group col-sm-12">
<label for="tagInput"><span class="oi oi-tags"></span> タグ</label>
<tag-input id="tagInput" name="tags" value="{{ old('tags') ?? $defaults['tags'] }}" :is-invalid="{{ $errors->has('tags') ? 'true' : 'false' }}"></tag-input>
<div id="tagInput2"></div>
<small class="form-text text-muted">
Tab, Enter, 半角スペースのいずれかで入力確定します。
</small>