(core) Freezing columns on a GridView

Summary:
User can freeze any number of columns, which will not move when a user scrolls grid horizontally.
Main use cases:
- Frozen columns don't move when a user scrolls horizontally
- The number of frozen columns is automatically persisted
- Readonly viewers see frozen columns and can modify them - but the change is not persisted
- On a small screen - frozen columns still moves to the left when scrolled, to reveal at least one column
- There is a single menu option - Toggle freeze - which offers the best action considering selected columns
- When a user clicks a single column - action to freeze/unfreeze is always there
- When a user clicks multiple columns - action is offered only where it makes sens (columns are near the frozen border)

Test Plan: Browser tests

Reviewers: dsagal, paulfitz

Reviewed By: dsagal

Differential Revision: https://phab.getgrist.com/D2852
This commit is contained in:
Jarosław Sadziński
2021-06-18 11:22:27 +02:00
parent 698c9d4e40
commit bdd4d3c46e
8 changed files with 366 additions and 16 deletions

View File

@@ -149,10 +149,21 @@
cursor: pointer;
}
/* Left most shadow - displayed next to row numbers or when columns are frozen - after last frozen column */
.scroll_shadow_left {
height: 100%; /* Just needs to be tall enough to flow off the bottom*/
height: 100%;
width: 0px;
left: 4rem;
/* Unfortunately we need to calculate this using scroll position.
We could use sticky position here, but we would need to move this component inside the
scroll pane. We don't want to do this, because we want the scroll shadow to be render
on top of the scroll bar. Fortunately it doesn't jitter on firefox - where scroll event is asynchronous.
Variables used here:
- frozen-width : total width of frozen columns plus row numbers width
- scroll-offset: current left offset of the scroll pane
- frozen-offset: when frozen columns are wider then the screen, we want them to move left initially,
this value is the position where this movement should stop.
*/
left: calc(4em + (var(--frozen-width, 0) - min(var(--frozen-scroll-offset, 0), var(--frozen-offset, 0))) * 1px);
box-shadow: -6px 0 6px 6px #444;
/* shadow should only show to the right of it (10px should be enough) */
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
@@ -160,6 +171,33 @@
z-index: 3;
}
/* Right shadow - normally not displayed - activated when grid has frozen columns */
.scroll_shadow_frozen {
height: 100%;
width: 0px;
left: 4em;
box-shadow: -8px 0 14px 4px #444;
-webkit-clip-path: polygon(0 0, 10px 0, 10px 100%, 0 100%);
clip-path: polygon(0 0, 28px 0, 24px 100%, 0 100%);
z-index: 3;
position: absolute;
}
/* line that indicates where the frozen columns end */
.frozen_line {
position:absolute;
height: 100%;
width: 2px;
/* this value is the same as for the left shadow - but doesn't need to really on the scroll offset
as this component will be hidden when the scroll starts
*/
left: calc(4em + var(--frozen-width, 0) * 1px);
background-color: #999999;
z-index: 3;
user-select: none;
pointer-events: none
}
.scroll_shadow_top {
left: 0;
height: 0;
@@ -181,6 +219,17 @@
border-right: 1px solid lightgray;
}
.gridview_left_border {
position: absolute;
width: 0px; /* Matches rowid width (+border) */
height: 100%;
z-index: 3;
left: calc(4rem);
border-right: 1px solid var(--grist-color-dark-grey) !important;
user-select: none;
pointer-events: none
}
.gridview_header_backdrop_top {
width: 100%;
height: calc(var(--gridview-header-height) + 1px); /* matches gridview_data_header height (+border) */
@@ -243,6 +292,49 @@
pointer-events: none; /* prevents row drag shadow from stealing row headers clicks */
}
/* ================ Freezing columns */
/* style header and a data field */
.record .field.frozen {
position: sticky;
left: calc(4em + 1px + (var(--frozen-position, 0) - var(--frozen-offset, 0)) * 1px); /* 4em for row number + total width of cells + 1px for border*/
z-index: 1;
}
/* for data field we need to reuse color from record (add-row and zebra stripes) */
.gridview_row .record .field.frozen {
background-color: inherit;
}
/* HACK: add box shadow to fix outline overflow from active cursor */
.gridview_row .record .field.frozen {
box-shadow: 0px 1px 0px white;
}
.gridview_row .record.record-hlines .field.frozen {
box-shadow: 0px 1px 0px var(--grist-color-dark-grey);
}
/* selected field has a transparent color - with frozen fields we can't do it */
.gridview_row .field.frozen.selected {
background-color: var(--grist-color-selection-opaque);
}
/* make room for a frozen line by adding margin to first not frozen field - in header and in data */
.field.frozen + .field:not(.frozen) {
margin-left: 1px;
}
/* printing frozen fields is straightforward - just need to remove transparency */
@media print {
.field.frozen {
background: white !important;
}
.column_names .column_name.frozen {
background: var(--grist-color-light-grey) !important;
}
}
/* Etc */
.g-column-main-menu {