Skip to content

Commit 7c032ab

Browse files
authored
Arrows have been added to the Scroller to display/offset non-contained content. (#9188)
Signed-off-by: Alexander Platov <[email protected]>
1 parent 2d38b86 commit 7c032ab

File tree

6 files changed

+108
-13
lines changed

6 files changed

+108
-13
lines changed

packages/ui/src/components/NestedDropdown.svelte

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@
5353
<Label label={selected !== undefined ? selected.label : label} />
5454
</span>
5555
<svelte:fragment slot="iconRight">
56-
<DropdownIcon
57-
size={'small'}
58-
fill={!disabled ? 'var(--primary-button-content-color)' : 'var(--theme-dark-color)'}
59-
/>
56+
<DropdownIcon size={'small'} fill={!disabled ? 'var(--theme-content-color)' : 'var(--theme-dark-color)'} />
6057
</svelte:fragment>
6158
</Button>
6259
</div>

packages/ui/src/components/NestedMenu.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555

5656
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
5757
<div class="menu-space" />
58-
<Scroller>
58+
<Scroller noFade={false} showOverflowArrows>
5959
{#if nestedFrom}
6060
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
6161
<button

packages/ui/src/components/Scroller.svelte

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
import { afterUpdate, beforeUpdate, createEventDispatcher, onDestroy, onMount } from 'svelte'
1818
import { resizeObserver } from '../resize'
1919
import { closeTooltip, tooltipstore } from '../tooltips'
20-
import type { FadeOptions, ScrollParams } from '../types'
20+
import type { FadeOptions, ScrollParams, MouseTargetEvent } from '../types'
2121
import { defaultSP } from '../types'
2222
import { DelayedCaller } from '../utils'
2323
import IconDownOutline from './icons/DownOutline.svelte'
2424
import HalfUpDown from './icons/HalfUpDown.svelte'
2525
import IconUpOutline from './icons/UpOutline.svelte'
26+
import IconNavPrev from './icons/NavPrev.svelte'
2627
2728
export let padding: string | undefined = undefined
2829
export let bottomPadding: string | undefined = undefined
@@ -45,6 +46,7 @@
4546
export let checkForHeaders: boolean = false
4647
export let stickedScrollBars: boolean = false
4748
export let thinScrollBars: boolean = false
49+
export let showOverflowArrows: boolean = false
4850
export let disableOverscroll = false
4951
export let disablePointerEventsOnScroll = false
5052
export let onScroll: ((params: ScrollParams) => void) | undefined = undefined
@@ -74,6 +76,7 @@
7476
let topCrop: 'top' | 'bottom' | 'full' | 'none' = 'none'
7577
let topCropValue: number = 0
7678
let maskH: 'left' | 'right' | 'both' | 'none' = 'none'
79+
let scrollArrows: boolean[] = [false, false, false, false] // [up, right, down, left]
7780
7881
let divHScroll: HTMLElement
7982
let divBar: HTMLElement
@@ -243,7 +246,15 @@
243246
isScrollingByBar = direction
244247
}
245248
246-
const renderFade = () => {
249+
const renderFade = (): void => {
250+
if (showOverflowArrows) {
251+
scrollArrows = [
252+
mask === 'top' || mask === 'both',
253+
maskH === 'left' || maskH === 'both',
254+
mask === 'bottom' || mask === 'both',
255+
maskH === 'right' || maskH === 'both'
256+
]
257+
}
247258
if (divScroll && !noFade) {
248259
const th = shiftTop + (topCrop === 'top' ? 2 * fz - topCropValue : 0)
249260
const tf =
@@ -537,6 +548,24 @@
537548
}
538549
}
539550
551+
const tapToScroll = (event: MouseTargetEvent): void => {
552+
const target = event.currentTarget as HTMLButtonElement
553+
if (!target.hasAttribute('data-direct') || divScroll == null) return
554+
555+
const direct = target.getAttribute('data-direct')
556+
const dir =
557+
direct === 'up'
558+
? { top: -stepScroll }
559+
: direct === 'down'
560+
? { top: stepScroll }
561+
: direct === 'left'
562+
? { left: -stepScroll }
563+
: direct === 'right'
564+
? { left: stepScroll }
565+
: { top: 0, left: 0 }
566+
if (!(dir?.top === 0 && dir?.left === 0)) divScroll.scrollBy({ ...dir, behavior: 'smooth' })
567+
}
568+
540569
$: topButton =
541570
(orientir === 'vertical' && (mask === 'top' || mask === 'both')) ||
542571
(orientir === 'horizontal' && (maskH === 'right' || maskH === 'both'))
@@ -715,9 +744,79 @@
715744
on:pointerleave={checkFade}
716745
/>
717746
{/if}
747+
{#if showOverflowArrows}
748+
{#each ['up', 'right', 'down', 'left'] as dir, i}
749+
<button class="scrollArrow" data-direct={dir} class:shown={scrollArrows[i]} on:click={tapToScroll}>
750+
<IconNavPrev size={'full'} />
751+
</button>
752+
{/each}
753+
{/if}
718754
</div>
719755

720756
<style lang="scss">
757+
.scrollArrow {
758+
position: absolute;
759+
display: none;
760+
justify-content: center;
761+
align-items: center;
762+
margin: 0;
763+
padding: 0;
764+
width: 1rem;
765+
height: 2rem;
766+
color: var(--theme-halfcontent-color);
767+
background-color: var(--theme-popup-color);
768+
border: 1px solid var(--theme-button-border);
769+
border-radius: 0.25rem;
770+
outline: none;
771+
box-shadow: 0 0 0.375rem rgba($color: #000000, $alpha: 0.1);
772+
user-select: none;
773+
-webkit-tap-highlight-color: transparent;
774+
tap-highlight-color: transparent;
775+
776+
&.shown {
777+
display: flex;
778+
}
779+
&:hover,
780+
&:focus {
781+
background-color: var(--theme-popup-hover);
782+
color: var(--theme-content-color);
783+
}
784+
:global(> svg) {
785+
width: 0.5rem;
786+
height: 0.75rem;
787+
pointer-events: none;
788+
}
789+
}
790+
.scrollArrow[data-direct='up'] {
791+
top: var(--scroller-header-height, 0);
792+
left: calc(
793+
(100% - var(--scroller-right-offset, 0) - var(--scroller-left-offset, 0)) / 2 + var(--scroller-left-offset, 0)
794+
);
795+
transform: translateX(-50%) rotate(90deg);
796+
}
797+
.scrollArrow[data-direct='right'] {
798+
top: calc(
799+
(100% - var(--scroller-header-height, 0) - var(--scroller-footer-height, 0)) / 2 +
800+
var(--scroller-header-height, 0)
801+
);
802+
right: calc(var(--scroller-right-offset, 0) + 0.25rem);
803+
transform: translateY(-50%) rotate(180deg);
804+
}
805+
.scrollArrow[data-direct='down'] {
806+
bottom: var(--scroller-footer-height, 0);
807+
left: calc(
808+
(100% - var(--scroller-right-offset, 0) - var(--scroller-left-offset, 0)) / 2 + var(--scroller-left-offset, 0)
809+
);
810+
transform: translateX(-50%) rotate(-90deg);
811+
}
812+
.scrollArrow[data-direct='left'] {
813+
top: calc(
814+
(100% - var(--scroller-header-height, 0) - var(--scroller-footer-height, 0)) / 2 +
815+
var(--scroller-header-height, 0)
816+
);
817+
left: calc(var(--scroller-left-offset, 0) + 0.25rem);
818+
transform: translateY(-50%);
819+
}
721820
.updown-container {
722821
position: absolute;
723822
display: flex;

packages/ui/src/components/icons/NavPrev.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
export let size: 'small' | 'medium' | 'large'
2+
export let size: 'small' | 'medium' | 'large' | 'full'
33
const fill: string = 'currentColor'
44
</script>
55

plugins/hr-resources/src/components/schedule/MonthView.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@
258258
{#if rows.length}
259259
{@const dep = departmentById.get(department)}
260260

261-
<Scroller horizontal fade={{ multipler: { top: headerHeightRem, left: headerWidthRem } }} noFade>
261+
<Scroller horizontal fade={{ multipler: { top: headerHeightRem, left: headerWidthRem } }} shrink showOverflowArrows>
262262
<div
263263
use:resizeObserver={(evt) => {
264264
containerWidth = evt.clientWidth
@@ -409,7 +409,8 @@
409409
$timeline-weekend-stroke-color: var(--theme-calendar-weekend-stroke-color);
410410
411411
.timeline {
412-
width: 100%;
412+
width: max-content;
413+
min-width: 100%;
413414
display: grid;
414415
grid-auto-flow: column;
415416
grid-template-columns: auto 1fr;

plugins/tracker-assets/assets/icons.svg

Lines changed: 1 addition & 3 deletions
Loading

0 commit comments

Comments
 (0)