react-icons/bs#BsArrowDownShort JavaScript Examples
The following examples show how to use
react-icons/bs#BsArrowDownShort.
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: LineageFilter.jsx From covince with MIT License | 4 votes |
LineageFilter = (props) => {
const {
allSelected,
className,
emptyMessage,
fixedLayout,
heading = defaultHeading,
isMobile,
sortedLineages,
toggleAll,
toggleLineage
} = props
const isScrolling = useMemo(() => {
return fixedLayout || sortedLineages.length > (isMobile ? 9 : 10)
}, [fixedLayout, sortedLineages, isMobile])
const sections = useMemo(() => {
if (!isScrolling) {
return [sortedLineages]
}
const sectionSize = isMobile ? 9 : 8
const _sections = []
const numSections = Math.ceil(sortedLineages.length / sectionSize) || 1
for (let i = 0; i < numSections; i++) {
const start = i * sectionSize
_sections.push(sortedLineages.slice(start, start + sectionSize))
}
return _sections
}, [sortedLineages, isMobile])
const { nomenclature } = useNomenclature()
const isLarge = useScreen('lg')
const gridStyle = useMemo(() => {
const style = {
scrollSnapAlign: 'start',
scrollSnapStop: 'always'
}
if (isMobile) {
return style
}
const numLineages = sortedLineages.length
const maxColumns = isScrolling ? 4 : 5
const numColumns =
isLarge && fixedLayout
? maxColumns
: Math.max(2, Math.min(Math.ceil(numLineages / 2), maxColumns))
return {
...style,
gridTemplateColumns: `repeat(${numColumns}, minmax(0, 1fr))`
}
}, [sortedLineages, fixedLayout, isScrolling, isMobile, isLarge])
const scrollContainer = useRef()
const userScrolled = useRef(false)
const doScroll = useCallback((direction) => {
const { height } = scrollContainer.current.getBoundingClientRect()
scrollContainer.current.scrollBy({
top: height * direction,
behavior: 'smooth'
})
userScrolled.current = true
}, [])
const sectionRefs = useRef([])
const [currentSection, setCurrentSection] = useState(null)
useEffect(() => {
const callback = entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const index = (sectionRefs.current).indexOf(entry.target)
setCurrentSection(index)
}
})
}
const observer = new IntersectionObserver(callback, {
root: scrollContainer.current,
threshold: 0.6
})
sectionRefs.current.filter(s => s).forEach(section => {
observer.observe(section)
})
return function cleanup () {
observer.disconnect()
}
}, [sections])
const scrollUpBtnRef = useRef(null)
const scrollDownBtnRef = useRef(null)
useEffect(() => {
if (isMobile || userScrolled.current === false) {
return
}
if (currentSection === 0) {
scrollDownBtnRef.current.focus()
} else if (currentSection === sections.length - 1) {
scrollUpBtnRef.current.focus()
}
}, [isMobile, currentSection])
return (
<div className={className}>
<header className='flex justify-between space-x-6'>
{heading}
<div className='flex items-center'>
<label
htmlFor='lineage_toggle_all'
className='pr-2 text-primary text-xs uppercase tracking-wide font-bold leading-5'
>
toggle all
</label>
<Checkbox
className='text-xs text-primary mx-auto flex-row-reverse'
id='lineage_toggle_all'
checked={allSelected}
onChange={toggleAll}
/>
</div>
</header>
<div className='md:flex md:mt-0.5'>
<form
ref={scrollContainer}
className={classNames(
'overflow-auto hide-scrollbars flex-grow -mx-4 md:-mx-2 flex md:flex-col md:h-16',
{ 'md:-mx-1': fixedLayout }
)}
style={{ scrollSnapType: isMobile ? 'x mandatory' : 'y mandatory' }}
>
{sections.map((lineages, i) => (
<section
key={`lineages-${i}`}
ref={el => { sectionRefs.current[i] = el }}
className={classNames(
'w-full h-full flex-shrink-0 flex flex-wrap content-start px-4 md:px-0 md:grid md:gap-0.5 relative',
{ 'md:px-1': fixedLayout }
)}
style={gridStyle}
>
{ lineages.length > 0
? lineages.map(({ lineage, active, colour, title = lineage, primaryText, secondaryText = lineage }) => (
<Checkbox
key={lineage}
className={classNames(
'w-1/3 my-1 h-7 md:my-0',
fixedLayout ? 'md:w-24 md:mx-0.5' : 'md:w-auto md:mx-2',
{
'md:mb-1': isScrolling && nomenclature.length === 0
}
)}
title={title}
style={{ color: colour }}
id={`lineage_filter_${lineage}`}
checked={active}
onChange={() => toggleLineage(lineage)}
>
{primaryText ? <span className={classNames('block text-gray-700 dark:text-gray-100')}>{primaryText}</span> : null}
<span className={classNames({ 'text-xs tracking-wide leading-none text-gray-500 dark:text-gray-300': primaryText })}>{secondaryText}</span>
</Checkbox>
))
: <>
<div className={classNames({ 'lg:w-24 lg:mx-0.5': fixedLayout })} />
<div className='absolute inset-0 flex items-center justify-center'>
{emptyMessage}
</div>
</> }
</section>
))}
</form>
{(sections.length > 1 || (!isMobile && fixedLayout)) && (
isMobile
? <ol className='list-none p-1 flex justify-center space-x-2'>
{ sections.map((_, i) =>
<li
key={`section-indicator-${i}`}
className={classNames(
'rounded-full bg-gray-500 dark:bg-gray-300 w-2 h-2 transition-opacity',
{ 'opacity-50': i !== currentSection || 0 }
)}
/>
)}
</ol>
: <form onSubmit={e => e.preventDefault()}
className={classNames(
'flex flex-col justify-center relative left-1 pb-1 space-y-0.5 md:ml-2',
{ 'lg:ml-0': fixedLayout }
)}
>
<Button
ref={scrollUpBtnRef}
title='Previous lineages'
className='w-6 h-6 !p-0 flex items-center text-gray-700 dark:text-gray-200 transition-opacity disabled:opacity-50'
onClick={() => doScroll(-1)}
disabled={currentSection === 0 || null}
>
<BsArrowUpShort className='fill-current w-6 h-6'/>
</Button>
<Button
ref={scrollDownBtnRef}
title='Next lineages'
className='w-6 h-6 !p-0 flex items-center text-gray-700 dark:text-gray-200 transition-opacity disabled:opacity-50'
onClick={() => doScroll(1)}
disabled={currentSection === sections.length - 1}
>
<BsArrowDownShort className='fill-current w-6 h-6'/>
</Button>
</form>
)}
</div>
</div>
)
}