react-icons/bs#BsX JavaScript Examples
The following examples show how to use
react-icons/bs#BsX.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: LineageTree.jsx From covince with MIT License | 4 votes |
LineageTree = (props) => {
const {
action,
Branch = DefaultBranch,
branchProps,
className,
colourPalette,
darkMode,
header,
lineageToColourIndex,
maxLineages = colourPalette.length,
nextColourIndex,
numberSelected,
submit,
// external tree state
search, setSearch, preset,
scrollPosition, setScrollPosition,
isLoading, nodeIndex, topology, toggleOpen
} = props
const inputRef = React.useRef()
const scrollRef = React.useRef()
React.useEffect(() => {
if (inputRef.current) inputRef.current.focus()
if (scrollRef.current && scrollPosition) {
scrollRef.current.scrollTo(scrollPosition)
}
}, [])
React.useLayoutEffect(() => {
const scrollingElement = scrollRef.current // cache for use in cleanup
return () => setScrollPosition({
top: scrollingElement.scrollTop,
left: scrollingElement.scrollLeft
})
}, [scrollRef])
const toggleSelect = useCallback((lineage) => {
const nextValues = { ...lineageToColourIndex }
if (lineage in nextValues) {
delete nextValues[lineage]
} else {
nextValues[lineage] = nextColourIndex
}
submit(nextValues)
}, [lineageToColourIndex, colourPalette])
const setColour = useCallback((lineage, colourIndex) => {
const update = {
...lineageToColourIndex,
[lineage]: colourIndex.toString()
}
submit(update)
}, [lineageToColourIndex])
const lightOrDarkPalette = useMemo(() =>
colourPalette.map(item => item[darkMode ? 'dark' : 'light'])
, [colourPalette, darkMode])
const lineageToColour = useMemo(() => {
return Object.fromEntries(
Object.entries(lineageToColourIndex).map(
([lineage, colourIndex]) =>
[lineage, lightOrDarkPalette[colourIndex]]
)
)
}, [lineageToColourIndex, lightOrDarkPalette])
return (
<>
{header}
<div className={classNames('flex flex-col', className)}>
<form className='flex justify-between items-end space-x-3' onSubmit={e => { e.preventDefault() }}>
<div className='flex items-center space-x-1'>
<Input
ref={inputRef}
className='w-48'
placeholder='Filter lineages'
value={search}
onChange={e => setSearch(e.target.value)}
/>
{ search.length > 0 &&
<button
onClick={() => { setSearch(''); inputRef.current.focus() }}
className='w-7 h-7 md:w-5 md:h-5 flex justify-center items-center rounded border border-transparent focus:primary-ring no-webkit-tap'
>
<BsX className='flex-shrink-0 w-7 h-7 md:w-5 md:h-5 text-gray-700 dark:text-gray-300' />
</button> }
</div>
{action}
</form>
<LoadingOverlay
className='flex-grow mt-2'
loading={isLoading}
>
<ul ref={scrollRef} className='overflow-scroll gutterless-scrollbars absolute inset-0 pl-1 -mr-1.5'>
{nodeIndex && topology.map(node =>
<Branch
Branch={Branch}
colourPalette={lightOrDarkPalette}
index={nodeIndex}
key={node.name}
node={node}
preset={preset}
search={search.toLowerCase()}
selectDisabled={numberSelected >= maxLineages}
setColour={setColour}
toggleOpen={toggleOpen}
toggleSelect={toggleSelect}
values={lineageToColour}
{...branchProps}
/>
)}
</ul>
</LoadingOverlay>
</div>
</>
)
}
Example #2
Source File: SearchMutations.jsx From covince with MIT License | 4 votes |
ManageSelection = ({ muts, mode = 'single', addingMut, setAddingMut, removeMutation }) => {
let content
if (muts.length === 0) {
content =
<p className='text-subheading text-sm flex items-center h-10 border border-gray-200 dark:border-gray-500 rounded px-3'>
select mutation below
</p>
} else if (mode === 'multi') {
content = (
<div className='flex xl:flex-row-reverse items-center self-center space-x-2 xl:gap-2'>
<Popover as='div' className='relative'>
<Popover.Button
as={Button}
className='inline-flex items-center justify-center px-3 h-10 whitespace-nowrap'
>
{muts.length} mutation{muts.length === 1 ? '' : 's'}
<BsChevronDoubleDown className='ml-2 h-4 w-4' />
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Popover.Panel
className={`
absolute z-20 top-full left-0 xl:left-auto xl:right-0 mt-2 origin-top-left xl:origin-top-right font-medium py-1
bg-white rounded shadow-md ring-1 ring-black ring-opacity-5
focus:outline-none dark:bg-gray-600 dark:text-white dark:ring-gray-500
`}
as='ul'
>
{muts.map((mut, idx) =>
<li
key={mut}
className={classNames(
'py-1.5 pl-3 md:pl-4 pr-2 flex items-center hover:bg-gray-100 dark:hover:bg-gray-700',
{ 'border-t-2 border-dotted border-gray-300 dark:border-gray-400': !addingMut && muts.length > 1 && idx === muts.length - 1 }
)}
>
<span className='mr-3'>{mut}</span>
<button
className={`
text-subheading ml-auto rounded border border-transparent
active:primary-ring active:bg-white dark:active:bg-gray-600
focus:outline-none focus-visible:primary-ring
`}
title='Remove mutation'
onClick={() => removeMutation(idx)}
>
<BsX className='h-5 w-5' />
</button>
</li>
)}
</Popover.Panel>
</Transition>
</Popover>
<Button
className='pl-3 pr-1.5 self-center flex items-center h-10'
onClick={() => setAddingMut(!addingMut)}
title={addingMut ? 'Cancel next mutation' : 'Add next mutation'}
>
<span className='pr-0.5'>{ addingMut ? 'cancel' : 'Add' }</span>
{ addingMut
? <BsX className='w-5 h-5 opacity-70' />
: <BsPlus className='w-5 h-5' /> }
</Button>
</div>
)
} else {
content = (
<div className='border border-gray-200 dark:border-gray-500 rounded p-1.5'>
<span className='px-1.5 mr-1.5'>{muts[0]}</span>
<Button
className='py-0.5 px-1.5 self-center'
onClick={removeMutation}
title='Remove mutation'
>
remove
</Button>
</div>
)
}
return (
<section
className='flex items-center max-w-max text-sm leading-6'
>
<h3 className='text-subheading font-bold uppercase text-xs tracking-wider leading-6 sr-only'>
Selected:
</h3>
{content}
</section>
)
}
Example #3
Source File: SearchMutations.jsx From covince with MIT License | 4 votes |
SearchMutations = props => {
const {
api_url,
lineageToColourIndex,
nextColourIndex,
onClose,
queryParams,
submit
} = props
const isLarge = useScreen('lg')
const lineage = useMemo(() => props.lineage, [])
const pangoClade = useMemo(() => expandLineage(lineage), [lineage])
const genes = useMemo(() => props.genes.sort(), [])
const { lineageToMutations, getMutationQueryUpdate } = useMutations()
const currentMuts = lineageToMutations[lineage]
const splitMuts = currentMuts ? currentMuts.split('+') : []
const [addingMut, setAddingMut] = useState()
const pangoCladeForApi = useMemo(() =>
splitMuts.length > 0 && addingMut
? `${pangoClade}+${currentMuts}`
: [pangoClade, ...splitMuts.slice(0, -1)].join('+')
, [lineage, addingMut, currentMuts])
const selectedLineages = useMemo(() => Object.keys(lineageToColourIndex).concat(lineage), [lineageToColourIndex])
const { unaliasedToAliased, expandedLineages, topology, denominatorLineages } = useLineagesForAPI(selectedLineages)
const excludedLineages = useMemo(() =>
getExcludedLineages(expandedLineages, topology, pangoClade).filter(l => !(l.startsWith(`${pangoClade}+`)))
, [selectedLineages])
const lineagesForApi = useMemo(() => Array.from(new Set([
...denominatorLineages,
...excludedLineages,
pangoCladeForApi
])), [selectedLineages, pangoCladeForApi])
const applyMutations = React.useCallback((nextMuts) => {
const mutationUpdate = getMutationQueryUpdate(lineage, nextMuts)
const lineageUpdate = { ...lineageToColourIndex }
const newKey = `${lineage}+${nextMuts}`
const replacing = currentMuts ? `${lineage}+${currentMuts}` : null
if (replacing) {
if (nextMuts) {
lineageUpdate[newKey] = lineageToColourIndex[replacing]
}
delete lineageUpdate[replacing]
} else {
lineageUpdate[newKey] = nextColourIndex
}
submit(lineageUpdate, mutationUpdate)
setAddingMut(false)
}, [getMutationQueryUpdate, lineageToColourIndex])
const removeMutation = React.useCallback((idx = splitMuts.length - 1) => {
const nextMuts = [...splitMuts]
nextMuts.splice(idx, 1)
applyMutations(nextMuts.join('+'))
}, [currentMuts])
const selectMutation = React.useCallback((mut) => {
if (splitMuts.includes(mut)) {
applyMutations(splitMuts.filter(m => m !== mut).join('+'))
} else {
applyMutations([
...(addingMut ? splitMuts : splitMuts.slice(0, -1)),
mut
].join('+'))
}
}, [currentMuts, addingMut])
const [{ gene = '', mutationFilter = '' }, updateQuery] = useQueryAsState()
const debouncedfilter = useDebouncedValue(mutationFilter, 250)
const excludedLineageString = useMemo(() => {
return excludedLineages.map(l => unaliasedToAliased[l]).join(', ')
}, [excludedLineages])
const excludedTitle = useMemo(() => {
return excludedLineages.length > 1 || excludedLineageString.includes('+') ? excludedLineageString : null
}, [excludedLineages])
return (
<>
<header className='md:flex items-baseline md:h-6 pl-3 md:pl-0 pr-11 md:pr-9 lg:pr-0 relative'>
<Heading className='truncate flex-shrink-0'>
Mutations in {lineage}
</Heading>
{ excludedLineages.length > 0 &&
<p className={classNames('text-sm text-subheading truncate mr-1.5 md:ml-2', { 'cursor-help': excludedTitle })} title={excludedTitle}>
excluding { excludedLineages.length === 1 ? excludedLineageString : `${excludedLineages.length} sublineages` }
</p> }
<button
className='!p-0 absolute border border-transparent focus:primary-ring rounded -top-0.5 right-2 md:right-0'
onClick={onClose}
title='Back to Lineages'
>
<BsX className='h-7 w-7' />
</button>
{/* { isLarge
? <Button className='h-6 px-2 ml-auto flex items-center whitespace-nowrap' onClick={onClose}>
Back to Lineages
</Button>
: <button
className='!p-0 absolute border border-transparent focus:primary-ring rounded -top-0.5 right-2 md:right-0'
onClick={onClose}
title='Back to Lineages'
>
<BsX className='h-7 w-7' />
</button> } */}
</header>
<div className='px-3 md:px-0 mt-3 mb-1.5 space-y-3 xl:space-y-0 xl:flex flex-row-reverse items-center xl:justify-between'>
<ManageSelection
muts={splitMuts}
mode={props.mutationMode}
addingMut={addingMut}
setAddingMut={setAddingMut}
removeMutation={removeMutation}
/>
<form className='lg:mr-3' onSubmit={e => e.preventDefault()}>
<div className='flex items-center space-x-1.5'>
<Select responsive value={gene} onChange={e => updateQuery({ gene: e.target.value })} className='!flex-shrink-0'>
<option value=''>(gene)</option>
{genes.map(g => <option key={g} value={g}>{g}</option>)}
</Select>
<p>:</p>
<Input
onChange={e => updateQuery({ mutationFilter: e.target.value.toUpperCase() }, 'replace')}
placeholder='filter mutations'
value={mutationFilter}
className='flex-shrink'
/>
{ (gene || mutationFilter) &&
<button
className='rounded border border-transparent focus:primary-ring text-subheading'
title='Reset filter'
onClick={() => updateQuery({ gene: undefined, mutationFilter: undefined })}
>
<BsX className='h-5 w-5' />
</button> }
</div>
</form>
</div>
<MutationsList
api_url={api_url}
dates={props.dates}
filter={debouncedfilter}
gene={gene}
isLarge={isLarge}
lineagesForApi={lineagesForApi}
pangoClade={pangoCladeForApi}
queryParams={queryParams}
selected={splitMuts}
selectMutation={selectMutation}
/>
</>
)
}