Added hyperlink type, ScrollerBar (#2353)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov
2022-11-04 13:07:27 +07:00
committed by GitHub
parent 47f5237fc9
commit 35e4fcd8aa
19 changed files with 311 additions and 182 deletions
@@ -17,8 +17,8 @@
import { Ref, SortingOrder } from '@hcengineering/core'
import { createQuery } from '@hcengineering/presentation'
import task, { SpaceWithStates, State } from '@hcengineering/task'
import { getPlatformColor } from '@hcengineering/ui'
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
import { getPlatformColor, ScrollerBar } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import StatesBarElement from './StatesBarElement.svelte'
import type { StatesBarPosition } from '../..'
@@ -27,18 +27,7 @@
export let gap: 'none' | 'small' | 'big' = 'small'
let states: State[] = []
let divScroll: HTMLElement
let divBar: HTMLElement
let isScrolling: boolean = false
let dX: number
let timer: number
let maskLeft: boolean = false
let maskRight: boolean = false
let mask: 'left' | 'right' | 'both' | 'none' = 'none'
let stepStyle: string
$: stepStyle = gap === 'small' ? 'gap-1' : gap === 'big' ? 'gap-2' : ''
const dispatch = createEventDispatcher()
@@ -56,77 +45,6 @@
}
)
const checkBar = (): void => {
if (divBar && divScroll) {
const trackW = divScroll.clientWidth
const scrollW = divScroll.scrollWidth
const proc = scrollW / trackW
divBar.style.width = divScroll.clientWidth / proc + 'px'
divBar.style.left = divScroll.scrollLeft / proc + 'px'
if (mask === 'none') divBar.style.visibility = 'hidden'
else {
divBar.style.visibility = 'visible'
if (divBar) {
if (timer) {
clearTimeout(timer)
divBar.style.opacity = '1'
}
timer = setTimeout(() => {
if (divBar) divBar.style.opacity = '0'
}, 2000)
}
}
if (divScroll.clientWidth >= divScroll.scrollWidth) divBar.style.visibility = 'hidden'
}
}
const onScroll = (event: MouseEvent): void => {
if (isScrolling && divBar && divScroll) {
const rectScroll = divScroll.getBoundingClientRect()
let X = event.clientX - dX
if (X < rectScroll.left) X = rectScroll.left
if (X > rectScroll.right - divBar.clientWidth) X = rectScroll.right - divBar.clientWidth
divBar.style.left = X - rectScroll.x + 'px'
const leftBar = X - rectScroll.x
const widthScroll = rectScroll.width - divBar.clientWidth
const procBar = leftBar / widthScroll
divScroll.scrollLeft = (divScroll.scrollWidth - divScroll.clientWidth) * procBar
}
}
const onScrollEnd = (event: MouseEvent): void => {
const el: HTMLElement = event.currentTarget as HTMLElement
if (el && isScrolling) {
document.removeEventListener('mousemove', onScroll)
document.body.style.userSelect = 'auto'
document.body.style.webkitUserSelect = 'auto'
}
document.removeEventListener('mouseup', onScrollEnd)
isScrolling = false
}
const onScrollStart = (event: MouseEvent): void => {
const el: HTMLElement = event.currentTarget as HTMLElement
if (el && divScroll) {
dX = event.clientX - el.getBoundingClientRect().x
document.addEventListener('mouseup', onScrollEnd)
document.addEventListener('mousemove', onScroll)
document.body.style.userSelect = 'none'
document.body.style.webkitUserSelect = 'none'
isScrolling = true
}
}
const checkMask = (): void => {
maskLeft = !!(divScroll && divScroll.scrollLeft > 1)
maskRight = !!(divScroll && divScroll.scrollWidth - divScroll.scrollLeft - divScroll.clientWidth > 1)
if (maskLeft || maskRight) {
if (maskLeft && maskRight) mask = 'both'
else if (maskLeft) mask = 'left'
else if (maskRight) mask = 'right'
} else mask = 'none'
if (!isScrolling) checkBar()
}
const selectItem = (ev: Event, item: State): void => {
const el: HTMLElement = ev.currentTarget as HTMLElement
const rect = el.getBoundingClientRect()
@@ -149,100 +67,18 @@
else if (n === states.length - 1) return 'end'
else return 'middle'
}
onMount(() => {
if (divScroll) {
const observer = new IntersectionObserver(() => checkMask(), { root: null, threshold: 0.1 })
const tempEl = divScroll.querySelector('*') as HTMLElement
if (tempEl) observer.observe(tempEl)
checkMask()
divScroll.addEventListener('scroll', checkMask)
}
})
onDestroy(() => {
if (divScroll) divScroll.removeEventListener('scroll', checkMask)
})
const _resize = (): void => checkMask()
</script>
<svelte:window on:resize={_resize} />
<div class="statesbar-container">
<div bind:this={divScroll} class="antiStatesBar mask-{mask} {stepStyle}">
{#each states as item, i (item._id)}
<StatesBarElement
label={item.title}
position={getPosition(i)}
selected={item._id === state}
color={getPlatformColor(item.color)}
on:click={(ev) => {
if (item._id !== state) selectItem(ev, item)
}}
/>
{/each}
</div>
<div
class="bar"
class:hovered={isScrolling}
bind:this={divBar}
on:mousedown={onScrollStart}
on:mouseleave={checkMask}
/>
<div class="track" class:hovered={isScrolling} />
</div>
<style lang="scss">
.statesbar-container {
position: relative;
min-width: 0;
}
.track {
visibility: hidden;
position: absolute;
bottom: -8px;
left: 0;
height: 5px;
transform-origin: center;
transform: scaleX(0);
transition: all 0.1s ease-in-out;
background-color: var(--scrollbar-track-color);
border-radius: 0.25rem;
}
.bar {
visibility: hidden;
position: absolute;
bottom: -8px;
left: 0;
height: 5px;
min-width: 2rem;
max-width: calc(100% - 12px);
transform-origin: center;
transform: scaleY(0.5);
background-color: var(--scrollbar-bar-color);
border-radius: 0.125rem;
opacity: 0;
box-shadow: 0 0 1px 1px var(--board-bg-color);
cursor: pointer;
z-index: 1;
transition: all 0.15s;
&:hover,
&.hovered {
background-color: var(--scrollbar-bar-hover);
transform: scaleY(1);
border-radius: 0.25rem;
opacity: 1 !important;
box-shadow: 0 0 1px black;
& + .track {
visibility: visible;
left: 0;
transform: scaleY(1);
}
}
&.hovered {
transition: none;
}
}
</style>
<ScrollerBar {gap} bind:scroller={divScroll}>
{#each states as item, i (item._id)}
<StatesBarElement
label={item.title}
position={getPosition(i)}
selected={item._id === state}
color={getPlatformColor(item.color)}
on:click={(ev) => {
if (item._id !== state) selectItem(ev, item)
}}
/>
{/each}
</ScrollerBar>