Skip to content

Commit

Permalink
feat(ktable): make visibility menu scrollable (#2134)
Browse files Browse the repository at this point in the history
* feat(ktable): make visibility menu scrollable

* fix(*): initial scroll styles

* fix(*): feedback

* fix(*): wait for open
  • Loading branch information
kaiarrowood authored and adamdehaven committed Jun 15, 2024
1 parent a880c61 commit 7789ee5
Showing 1 changed file with 81 additions and 22 deletions.
103 changes: 81 additions & 22 deletions src/components/KTable/ColumnVisibilityMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,34 @@
</KTooltip>

<template #items>
<KDropdownItem
v-for="col in columns"
:key="col.key"
class="column-visibility-menu-item"
:data-testid="`column-visibility-menu-item-${col.key}`"
@click.stop="() => {
visibilityMap[col.key] = !visibilityMap[col.key]
isDirty = true
}"
<div
ref="menuItemsRef"
class="menu-items-wrapper"
>
<!-- KLabel must be separate to maintain click handling on the label within the dropdown item -->
<KCheckbox
v-model="visibilityMap[col.key]"
:aria-labelledby="`${tableId}-${col.key}-visibility-checkbox-label`"
:data-testid="`column-visibility-checkbox-${col.key}`"
/>
<KLabel
:id="`${tableId}-${col.key}-visibility-checkbox-label`"
class="visibility-checkbox-label"
<KDropdownItem
v-for="col in columns"
:key="col.key"
class="column-visibility-menu-item"
:data-testid="`column-visibility-menu-item-${col.key}`"
@click.stop="() => {
visibilityMap[col.key] = !visibilityMap[col.key]
isDirty = true
}"
>
{{ col.label }}
</KLabel>
</KDropdownItem>
<!-- KLabel must be separate to maintain click handling on the label within the dropdown item -->
<KCheckbox
v-model="visibilityMap[col.key]"
:aria-labelledby="`${tableId}-${col.key}-visibility-checkbox-label`"
:data-testid="`column-visibility-checkbox-${col.key}`"
/>
<KLabel
:id="`${tableId}-${col.key}-visibility-checkbox-label`"
class="visibility-checkbox-label"
>
{{ col.label }}
</KLabel>
</KDropdownItem>
</div>
<div class="apply-button-wrapper">
<KButton
appearance="tertiary"
Expand All @@ -57,7 +62,7 @@
</template>

<script setup lang="ts">
import { ref, watch, onBeforeMount, type PropType } from 'vue'
import { ref, watch, onBeforeMount, onMounted, type PropType } from 'vue'
import type { TableHeader } from '@/types'
import { TableColumnsIcon } from '@kong/icons'
import KButton from '@/components/KButton/KButton.vue'
Expand Down Expand Up @@ -86,6 +91,7 @@ const props = defineProps({
const visibilityMap = ref<Record<string, boolean>>({})
const isDirty = ref(false)
const menuItemsRef = ref<HTMLDivElement>()
const initVisibilityMap = (): void => {
visibilityMap.value = props.columns.reduce((acc, col: TableHeader) => {
Expand All @@ -103,16 +109,54 @@ const handleApply = (): void => {
}
const handleDropdownToggle = (isOpen: boolean): void => {
// set scroll classes on open
if (isOpen && menuItemsRef.value) {
setTimeout(() => {
if (menuItemsRef.value) {
setOverflowClass(menuItemsRef.value)
}
}, 500)
}
// reset the map if the dropdown is closed without applying changes
if (!isOpen && isDirty.value) {
initVisibilityMap()
}
}
/**
* Fade out the bottom of the menu items when scrollable
*/
const setOverflowClass = (el: HTMLDivElement) => {
const isScrollable = el.scrollHeight > el.clientHeight
// GUARD: If element is not scrollable, remove all classes
if (!isScrollable) {
el.classList.remove('is-bottom-overflowing')
return
}
// Otherwise, the element is overflowing!
// One pixel is added to the height to account for non-integer heights.
const isScrolledToBottom = el.scrollHeight < el.clientHeight + el.scrollTop + 1
el.classList.toggle('is-bottom-overflowing', !isScrolledToBottom)
}
watch(() => props.visibilityPreferences, () => {
initVisibilityMap()
})
onMounted(() => {
if (menuItemsRef.value) {
menuItemsRef.value.addEventListener('scroll', (e) => {
const el = e.currentTarget as HTMLDivElement
setOverflowClass(el)
})
setOverflowClass(menuItemsRef.value)
}
})
onBeforeMount(() => {
// initialize visibility state
initVisibilityMap()
Expand All @@ -123,6 +167,21 @@ onBeforeMount(() => {
.table-column-visibility-menu {
margin-left: var(--kui-space-auto, $kui-space-auto);
.menu-items-wrapper {
$bottom-mask-size: 0px;
-webkit-mask-image: linear-gradient(to bottom, black calc(100% - $bottom-mask-size), transparent 100%);
mask-image: linear-gradient(to bottom, black calc(100% - $bottom-mask-size), transparent 100%);
max-height: 250px;
overflow-y: auto;
&.is-bottom-overflowing {
$bottom-mask-size: 48px;
-webkit-mask-image: linear-gradient(to bottom, black calc(100% - $bottom-mask-size), transparent 100%);
mask-image: linear-gradient(to bottom, black calc(100% - $bottom-mask-size), transparent 100%);
}
}
.apply-button-wrapper {
display: flex;
width: 100%;
Expand Down

0 comments on commit 7789ee5

Please sign in to comment.