Browse Source

Merge pull request #4101 from nocodb/feat/scroll-improvement

feat: better scroll for borders and sticky header
pull/4137/head
Pranav C 2 years ago committed by GitHub
parent
commit
bc890b1245
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 101
      packages/nc-gui/components/smartsheet/Grid.vue
  2. 2
      packages/nc-gui/composables/useMultiSelect/index.ts

101
packages/nc-gui/components/smartsheet/Grid.vue

@ -88,6 +88,8 @@ const expandedFormDlg = ref(false)
const expandedFormRow = ref<Row>() const expandedFormRow = ref<Row>()
const expandedFormRowState = ref<Record<string, any>>() const expandedFormRowState = ref<Record<string, any>>()
const tbodyEl = ref<HTMLElement>() const tbodyEl = ref<HTMLElement>()
const gridWrapper = ref<HTMLElement>()
const tableHead = ref<HTMLElement>()
const { const {
isLoading, isLoading,
@ -107,6 +109,55 @@ const { getMeta } = useMetas()
const { loadGridViewColumns, updateWidth, resizingColWidth, resizingCol } = useGridViewColumnWidth(view) const { loadGridViewColumns, updateWidth, resizingColWidth, resizingCol } = useGridViewColumnWidth(view)
const getContainerScrollForElement = (
el: HTMLElement,
container: HTMLElement,
offset?: {
top?: number
bottom?: number
left?: number
right?: number
},
) => {
const childPos = el.getBoundingClientRect()
const parentPos = container.getBoundingClientRect()
const relativePos = {
top: childPos.top - parentPos.top,
right: childPos.right - parentPos.right,
bottom: childPos.bottom - parentPos.bottom,
left: childPos.left - parentPos.left,
}
const scroll = {
top: 0,
left: 0,
}
/*
* If the element is to the right of the container, scroll right (positive)
* If the element is to the left of the container, scroll left (negative)
*/
scroll.left =
relativePos.right + (offset?.right || 0) > 0
? container.scrollLeft + relativePos.right + (offset?.right || 0)
: relativePos.left - (offset?.left || 0) < 0
? container.scrollLeft + relativePos.left - (offset?.left || 0)
: container.scrollLeft
/*
* If the element is below the container, scroll down (positive)
* If the element is above the container, scroll up (negative)
*/
scroll.top =
relativePos.bottom + (offset?.bottom || 0) > 0
? container.scrollTop + relativePos.bottom + (offset?.bottom || 0)
: relativePos.top - (offset?.top || 0) < 0
? container.scrollTop + relativePos.top - (offset?.top || 0)
: container.scrollTop
return scroll
}
const { selectCell, selectBlock, selectedRange, clearRangeRows, startSelectRange, selected } = useMultiSelect( const { selectCell, selectBlock, selectedRange, clearRangeRows, startSelectRange, selected } = useMultiSelect(
fields, fields,
data, data,
@ -114,16 +165,48 @@ const { selectCell, selectBlock, selectedRange, clearRangeRows, startSelectRange
isPkAvail, isPkAvail,
clearCell, clearCell,
makeEditable, makeEditable,
() => { (row?: number | null, col?: number | null) => {
if (selected.row !== null && selected.col !== null) { row = row ?? selected.row
col = col ?? selected.col
if (row !== undefined && col !== undefined && row !== null && col !== null) {
// get active cell // get active cell
const td = tbodyEl.value?.querySelectorAll('tr')[selected.row]?.querySelectorAll('td')[selected.col + 1] const rows = tbodyEl.value?.querySelectorAll('tr')
if (!td) return const cols = rows?.[row].querySelectorAll('td')
const td = cols?.[col === 0 ? 0 : col + 1]
if (!td || !gridWrapper.value) return
const { height: headerHeight } = tableHead.value!.getBoundingClientRect()
const tdScroll = getContainerScrollForElement(td, gridWrapper.value, { top: headerHeight, bottom: 9, right: 9 })
if (rows && row === rows.length - 2) {
// if last row make 'Add New Row' visible
gridWrapper.value.scrollTo({
top: gridWrapper.value.scrollHeight,
left:
cols && col === cols.length - 2 // if corner cell
? gridWrapper.value.scrollWidth
: tdScroll.left,
behavior: 'smooth',
})
return
}
if (cols && col === cols.length - 2) {
// if last column make 'Add New Column' visible
gridWrapper.value.scrollTo({
top: tdScroll.top,
left: gridWrapper.value.scrollWidth,
behavior: 'smooth',
})
return
}
// scroll into the active cell // scroll into the active cell
td.scrollIntoView({ gridWrapper.value.scrollTo({
top: tdScroll.top,
left: tdScroll.left,
behavior: 'smooth', behavior: 'smooth',
block: 'nearest',
inline: 'nearest',
}) })
} }
}, },
@ -381,7 +464,7 @@ watch(
</div> </div>
</general-overlay> </general-overlay>
<div class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull"> <div ref="gridWrapper" class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull">
<a-dropdown <a-dropdown
v-model:visible="contextMenu" v-model:visible="contextMenu"
:trigger="isSqlView ? [] : ['contextmenu']" :trigger="isSqlView ? [] : ['contextmenu']"
@ -392,7 +475,7 @@ watch(
class="xc-row-table nc-grid backgroundColorDefault !h-auto bg-white" class="xc-row-table nc-grid backgroundColorDefault !h-auto bg-white"
@contextmenu="showContextMenu" @contextmenu="showContextMenu"
> >
<thead> <thead ref="tableHead">
<tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]"> <tr class="nc-grid-header border-1 bg-gray-100 sticky top[-1px]">
<th> <th>
<div class="w-full h-full bg-gray-100 flex min-w-[70px] pl-5 pr-1 items-center"> <div class="w-full h-full bg-gray-100 flex min-w-[70px] pl-5 pr-1 items-center">

2
packages/nc-gui/composables/useMultiSelect/index.ts

@ -17,7 +17,7 @@ export function useMultiSelect(
isPkAvail: MaybeRef<boolean>, isPkAvail: MaybeRef<boolean>,
clearCell: Function, clearCell: Function,
makeEditable: Function, makeEditable: Function,
scrollToActiveCell?: () => void, scrollToActiveCell?: (row?: number | null, col?: number | null) => void,
) { ) {
const { t } = useI18n() const { t } = useI18n()

Loading…
Cancel
Save