wip
This commit is contained in:
		| @@ -73,5 +73,13 @@ | ||||
|       "composer fix", | ||||
|       "git add" | ||||
|     ] | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@types/classnames": "^2.2.10", | ||||
|     "@types/react": "^16.9.35", | ||||
|     "@types/react-dom": "^16.9.8", | ||||
|     "classnames": "^2.2.6", | ||||
|     "react": "^16.13.1", | ||||
|     "react-dom": "^16.13.1" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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') | ||||
| ); | ||||
|   | ||||
							
								
								
									
										10
									
								
								resources/assets/js/components/TagInput.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/assets/js/components/TagInput.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| :local { | ||||
|     .tag-item { | ||||
|         cursor: pointer; | ||||
|     } | ||||
|  | ||||
|     .tag-input { | ||||
|         border: 0; | ||||
|         outline: 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								resources/assets/js/components/TagInput2.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								resources/assets/js/components/TagInput2.tsx
									
									
									
									
									
										Normal 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; | ||||
| @@ -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> | ||||
|   | ||||
| @@ -5,7 +5,8 @@ | ||||
|     "module": "es2015", | ||||
|     "moduleResolution": "node", | ||||
|     "strict": true, | ||||
|     "experimentalDecorators": true | ||||
|     "experimentalDecorators": true, | ||||
|     "jsx": "react" | ||||
|   }, | ||||
|   "include": [ | ||||
|     "resources/assets/js/**/*" | ||||
|   | ||||
							
								
								
									
										78
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -772,6 +772,11 @@ | ||||
|   dependencies: | ||||
|     moment "^2.10.2" | ||||
|  | ||||
| "@types/classnames@^2.2.10": | ||||
|   version "2.2.10" | ||||
|   resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999" | ||||
|   integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ== | ||||
|  | ||||
| "@types/color-name@^1.1.1": | ||||
|   version "1.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" | ||||
| @@ -828,6 +833,11 @@ | ||||
|   resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.0.tgz#4e498dbf355795a611a87ae5ef811a8660d42662" | ||||
|   integrity sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ== | ||||
|  | ||||
| "@types/prop-types@*": | ||||
|   version "15.7.3" | ||||
|   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" | ||||
|   integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== | ||||
|  | ||||
| "@types/q@^1.5.1": | ||||
|   version "1.5.2" | ||||
|   resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" | ||||
| @@ -838,6 +848,21 @@ | ||||
|   resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a" | ||||
|   integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== | ||||
|  | ||||
| "@types/react-dom@^16.9.8": | ||||
|   version "16.9.8" | ||||
|   resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" | ||||
|   integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== | ||||
|   dependencies: | ||||
|     "@types/react" "*" | ||||
|  | ||||
| "@types/react@*", "@types/react@^16.9.35": | ||||
|   version "16.9.46" | ||||
|   resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.46.tgz#f0326cd7adceda74148baa9bff6e918632f5069e" | ||||
|   integrity sha512-dbHzO3aAq1lB3jRQuNpuZ/mnu+CdD3H0WVaaBQA8LTT3S33xhVBUj232T8M3tAhSWJs/D/UqORYUlJNl/8VQZg== | ||||
|   dependencies: | ||||
|     "@types/prop-types" "*" | ||||
|     csstype "^3.0.2" | ||||
|  | ||||
| "@types/sizzle@*": | ||||
|   version "2.3.2" | ||||
|   resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" | ||||
| @@ -1937,6 +1962,11 @@ class-utils@^0.3.5: | ||||
|     isobject "^3.0.0" | ||||
|     static-extend "^0.1.1" | ||||
|  | ||||
| classnames@^2.2.6: | ||||
|   version "2.2.6" | ||||
|   resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" | ||||
|   integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== | ||||
|  | ||||
| clean-css@4.2.x, clean-css@^4.1.3: | ||||
|   version "4.2.2" | ||||
|   resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.2.tgz#8519abda724b3e759bc79d196369906925d81a3f" | ||||
| @@ -2489,6 +2519,11 @@ csso@^4.0.2: | ||||
|   dependencies: | ||||
|     css-tree "1.0.0-alpha.37" | ||||
|  | ||||
| csstype@^3.0.2: | ||||
|   version "3.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.2.tgz#ee5ff8f208c8cd613b389f7b222c9801ca62b3f7" | ||||
|   integrity sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw== | ||||
|  | ||||
| currently-unhandled@^0.4.1: | ||||
|   version "0.4.1" | ||||
|   resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" | ||||
| @@ -4988,7 +5023,7 @@ longest-streak@^2.0.1: | ||||
|   resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" | ||||
|   integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== | ||||
|  | ||||
| loose-envify@^1.0.0: | ||||
| loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: | ||||
|   version "1.4.0" | ||||
|   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" | ||||
|   integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== | ||||
| @@ -6499,6 +6534,15 @@ promise-inflight@^1.0.1: | ||||
|   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" | ||||
|   integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= | ||||
|  | ||||
| prop-types@^15.6.2: | ||||
|   version "15.7.2" | ||||
|   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" | ||||
|   integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== | ||||
|   dependencies: | ||||
|     loose-envify "^1.4.0" | ||||
|     object-assign "^4.1.1" | ||||
|     react-is "^16.8.1" | ||||
|  | ||||
| property-expr@^1.5.0: | ||||
|   version "1.5.1" | ||||
|   resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" | ||||
| @@ -6639,6 +6683,30 @@ raw-body@2.4.0: | ||||
|     iconv-lite "0.4.24" | ||||
|     unpipe "1.0.0" | ||||
|  | ||||
| react-dom@^16.13.1: | ||||
|   version "16.13.1" | ||||
|   resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" | ||||
|   integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== | ||||
|   dependencies: | ||||
|     loose-envify "^1.1.0" | ||||
|     object-assign "^4.1.1" | ||||
|     prop-types "^15.6.2" | ||||
|     scheduler "^0.19.1" | ||||
|  | ||||
| react-is@^16.8.1: | ||||
|   version "16.13.1" | ||||
|   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" | ||||
|   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== | ||||
|  | ||||
| react@^16.13.1: | ||||
|   version "16.13.1" | ||||
|   resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" | ||||
|   integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== | ||||
|   dependencies: | ||||
|     loose-envify "^1.1.0" | ||||
|     object-assign "^4.1.1" | ||||
|     prop-types "^15.6.2" | ||||
|  | ||||
| read-pkg-up@^3.0.0: | ||||
|   version "3.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" | ||||
| @@ -7091,6 +7159,14 @@ sax@~1.2.4: | ||||
|   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" | ||||
|   integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== | ||||
|  | ||||
| scheduler@^0.19.1: | ||||
|   version "0.19.1" | ||||
|   resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" | ||||
|   integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== | ||||
|   dependencies: | ||||
|     loose-envify "^1.1.0" | ||||
|     object-assign "^4.1.1" | ||||
|  | ||||
| schema-utils@^0.4.5: | ||||
|   version "0.4.7" | ||||
|   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 shibafu
					shibafu