react-bootstrap-tagsinput
Version:
A chip input field using bootstrap.
1 lines • 4.49 kB
JavaScript
var __rest=this&&this.__rest||function(s,e){var t={};for(var p in s)if(Object.prototype.hasOwnProperty.call(s,p)&&e.indexOf(p)<0)t[p]=s[p];if(s!=null&&typeof Object.getOwnPropertySymbols==="function")for(var i=0,p=Object.getOwnPropertySymbols(s);i<p.length;i++){if(e.indexOf(p[i])<0&&Object.prototype.propertyIsEnumerable.call(s,p[i]))t[p[i]]=s[p[i]]}return t};import React,{useEffect,useLayoutEffect,useRef,useState}from"react";import classnames from"classnames";export default function Cancel(props){return React.createElement("svg",Object.assign({width:"24",height:"24",viewBox:"0 0 24 24"},props),React.createElement("path",{d:"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41z"}))}export const InputTags=_a=>{var{placeholder,values,onTags,name,className,elementClassName}=_a,rest=__rest(_a,["placeholder","values","onTags","name","className","elementClassName"]);const[terms,setTerms]=useState(values||[]);const[value,setValue]=useState("");const[focusIndex,setFocusIndex]=useState(-1);const inputRef=useRef(null);const forceInputFocus=()=>{if(inputRef.current&&focusIndex===-1){inputRef.current.focus()}};useLayoutEffect(()=>{if(terms.length===0){setFocusIndex(-1)}onTags({values:terms,name:name})},[terms.length]);useEffect(()=>{setTerms(values||[])},[values]);useEffect(()=>{forceInputFocus()},[focusIndex,inputRef.current]);const onchange=event=>{setValue(event.currentTarget.value)};const onkeydown=event=>{const{key}=event;const currentValue=value.trim();if(key==="Tab"&¤tValue!==""){event.preventDefault();setTerms([...terms,currentValue.replace(",","")]);setValue("");setFocusIndex(-1)}};const onkeyup=event=>{const{key}=event;const currentValue=value.trim();const valueLength=currentValue.length;const currentTarget=event.currentTarget.selectionEnd||0;const isEndOfText=currentTarget>valueLength;const isStartOfText=currentTarget===0;const isPossibletermsMove=terms.length>0;const isPossibleAddKeys=key==="Enter"||key===" "||key==="Tab"||key===",";if(isPossibleAddKeys&¤tValue!==""){event.preventDefault();setTerms([...terms,currentValue.replace(",","")]);setValue("");setFocusIndex(-1)}else if(isStartOfText&&(key==="Backspace"||key==="ArrowLeft")&&isPossibletermsMove){event.preventDefault();setFocusIndex(terms.length-1)}else if(isEndOfText&&key==="ArrowRight"&&isPossibletermsMove){event.preventDefault();setFocusIndex(0)}};const handleRemove=(index,focus)=>{setTerms(terms.filter((_,i)=>i!==index));if(focus){setFocusIndex(Math.max(focusIndex-1,0))}else{forceInputFocus()}};const setSelectedIndex=index=>{if(index<terms.length&&index>-1){setFocusIndex(index)}else{setFocusIndex(-1)}};return React.createElement("div",{className:"form-control h-auto d-inline-flex flex-wrap"},terms.map((item,index)=>{const focus=focusIndex===index;return React.createElement(Element,{key:`${item}${index}`,value:item,index:index,onRemove:handleRemove,focus:focus,onSelectedIndex:setSelectedIndex,className:elementClassName})}),React.createElement("input",Object.assign({"data-testid":"input-tags",ref:inputRef,type:"text",className:classnames("border-0 w-auto flex-fill input-tags",className),placeholder:placeholder,"aria-label":placeholder,value:value,onChange:onchange,onKeyUp:onkeyup,onKeyDown:onkeydown,autoFocus:true,name:name},rest)))};const Element=props=>{const[focus,setFocus]=useState(false);const onclick=()=>{props.onRemove(props.index,focus)};const ref=useRef(null);useLayoutEffect(()=>{if(ref.current&&props.focus){ref.current.focus()}},[props.focus]);const onkeydown=event=>{const{key}=event;event.preventDefault();if(key==="Backspace"||key==="Delete"){props.onRemove(props.index,props.focus)}else if(key==="ArrowLeft"){props.onSelectedIndex(props.index-1)}else if(key==="ArrowRight"){props.onSelectedIndex(props.index+1)}};return React.createElement("div",{"data-testid":"tag-element",ref:ref,tabIndex:0,className:classnames("badge bg-secondary bg-gradient me-1 pe-1 justify-content-between",props.className),onKeyUp:onkeydown,onFocus:()=>{setFocus(true)},onBlur:()=>{setFocus(false)}},props.value,React.createElement("button",{"data-testid":"tag-clean-element","aria-label":"remove path fragment",tabIndex:-1,className:"border-0 bg-transparent ps-auto pe-0",style:{outline:0},onClick:onclick},React.createElement(Cancel,{style:{fill:"var(--bs-white)",opacity:1},width:18,height:18})))};