Fix some scroll issues and add shadow to sticky column
This commit is contained in:
parent
ca96a61cde
commit
15dffb0f40
9 changed files with 117 additions and 92 deletions
|
@ -5,8 +5,7 @@
|
|||
import { getIconForField } from "./utils"
|
||||
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
||||
|
||||
const { visibleColumns, reorder, selectedRows, rows } =
|
||||
getContext("spreadsheet")
|
||||
const { visibleColumns, reorder } = getContext("spreadsheet")
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<script>
|
||||
import SheetCell from "./SheetCell.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const { visibleColumns, cellHeight, rows, selectedCellId, reorder } =
|
||||
const { visibleColumns, hoveredRowId, rows, selectedCellId, reorder } =
|
||||
getContext("spreadsheet")
|
||||
|
||||
$: rowHovered = $hoveredRowId === "new"
|
||||
|
||||
const addRow = async field => {
|
||||
const newRow = await rows.actions.addRow()
|
||||
if (newRow) {
|
||||
|
@ -14,9 +15,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="row new">
|
||||
<div class="row" on:mouseover={() => ($hoveredRowId = "new")}>
|
||||
{#each $visibleColumns as column}
|
||||
<SheetCell
|
||||
{rowHovered}
|
||||
on:click={() => addRow(column)}
|
||||
width={column.width}
|
||||
left={column.left}
|
||||
|
@ -30,8 +32,7 @@
|
|||
.row {
|
||||
display: flex;
|
||||
}
|
||||
:global(.sheet:not(.is-resizing):not(.is-reordering) .row:hover .cell) {
|
||||
background: var(--cell-background-hover);
|
||||
.row:hover :global(.cell) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
const tableIdStore = writable()
|
||||
const selectedCellId = writable()
|
||||
const selectedRows = writable({})
|
||||
const hoveredRowId = writable()
|
||||
const scroll = writable({
|
||||
left: 0,
|
||||
top: 0,
|
||||
|
@ -51,6 +52,7 @@
|
|||
cellHeight,
|
||||
bounds,
|
||||
scroll,
|
||||
hoveredRowId,
|
||||
tableId: tableIdStore,
|
||||
}
|
||||
const { rows, schema } = createRowsStore(context)
|
||||
|
@ -114,7 +116,7 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-items: flex-start;
|
||||
align-items: stretch;
|
||||
align-items: flex-start;
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
position: relative;
|
||||
|
@ -124,5 +126,6 @@
|
|||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
<script>
|
||||
import { getContext, onMount } from "svelte"
|
||||
import { Utils } from "../../utils"
|
||||
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
||||
|
||||
const { columns, selectedCellId, cellHeight, rows, bounds, scroll } =
|
||||
getContext("spreadsheet")
|
||||
|
||||
const padding = 180
|
||||
const { selectedCellId, hoveredRowId, bounds } = getContext("spreadsheet")
|
||||
|
||||
let ref
|
||||
|
||||
$: scrollLeft = $scroll.left
|
||||
$: scrollTop = $scroll.top
|
||||
|
||||
onMount(() => {
|
||||
// Observe and record the height of the body
|
||||
const observer = new ResizeObserver(() => {
|
||||
|
@ -28,8 +21,8 @@
|
|||
<div
|
||||
bind:this={ref}
|
||||
class="sheet-body"
|
||||
class:horizontally-scrolled={scrollLeft > 0}
|
||||
on:click|self={() => ($selectedCellId = null)}
|
||||
on:mouseleave={() => ($hoveredRowId = null)}
|
||||
>
|
||||
<SheetScrollWrapper>
|
||||
<slot />
|
||||
|
@ -44,20 +37,4 @@
|
|||
overflow: hidden;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.sheet-body::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Add shadow to sticky cells when horizontally scrolled */
|
||||
.horizontally-scrolled :global(.cell.sticky) {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
.horizontally-scrolled :global(.cell.sticky:after) {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
left: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<svelte:options immutable={true} />
|
||||
|
||||
<script>
|
||||
export let header = false
|
||||
export let label = false
|
||||
export let rowSelected = false
|
||||
export let rowHovered = false
|
||||
export let sticky = false
|
||||
export let selected = false
|
||||
export let reorderSource = false
|
||||
|
@ -16,12 +15,12 @@
|
|||
class:header
|
||||
class:label
|
||||
class:row-selected={rowSelected}
|
||||
class:row-hovered={rowHovered}
|
||||
class:sticky
|
||||
class:selected
|
||||
class:reorder-source={reorderSource}
|
||||
class:reorder-target={reorderTarget}
|
||||
on:focus
|
||||
on:mouseenter
|
||||
on:click
|
||||
on:mousedown
|
||||
style="--width:{width}px;"
|
||||
|
@ -64,6 +63,9 @@
|
|||
.cell.row-selected {
|
||||
background-color: var(--spectrum-global-color-gray-100);
|
||||
}
|
||||
.cell.row-hovered {
|
||||
background: var(--cell-background-hover);
|
||||
}
|
||||
|
||||
/* Header cells */
|
||||
.cell.header {
|
||||
|
|
|
@ -7,17 +7,25 @@
|
|||
|
||||
export let row
|
||||
|
||||
const { selectedCellId, reorder, selectedRows, rows, visibleColumns } =
|
||||
getContext("spreadsheet")
|
||||
const {
|
||||
selectedCellId,
|
||||
reorder,
|
||||
selectedRows,
|
||||
rows,
|
||||
visibleColumns,
|
||||
hoveredRowId,
|
||||
} = getContext("spreadsheet")
|
||||
|
||||
$: rowSelected = !!$selectedRows[row._id]
|
||||
$: rowHovered = $hoveredRowId === row._id
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
<div class="row" on:mouseover={() => ($hoveredRowId = row._id)}>
|
||||
{#each $visibleColumns as column (column.name)}
|
||||
{@const cellIdx = `${row._id}-${column.name}`}
|
||||
<SheetCell
|
||||
{rowSelected}
|
||||
{rowHovered}
|
||||
selected={$selectedCellId === cellIdx}
|
||||
reorderSource={$reorder.columnIdx === column.idx}
|
||||
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
||||
|
@ -41,7 +49,4 @@
|
|||
.row {
|
||||
display: flex;
|
||||
}
|
||||
:global(.sheet:not(.is-resizing):not(.is-reordering) .row:hover .cell) {
|
||||
background: var(--cell-background-hover);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -69,11 +69,11 @@
|
|||
const offset = deltaY * step
|
||||
let newScrollTop = scrollTop
|
||||
newScrollTop += offset
|
||||
newScrollTop = Math.max(0, newScrollTop)
|
||||
newScrollTop = Math.min(
|
||||
newScrollTop,
|
||||
($rows.length + 1) * cellHeight - $bounds.height
|
||||
)
|
||||
newScrollTop = Math.max(0, newScrollTop)
|
||||
scroll.update(state => ({
|
||||
...state,
|
||||
top: newScrollTop,
|
||||
|
@ -91,6 +91,8 @@
|
|||
|
||||
<style>
|
||||
.scroll-wrapper {
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
background: var(--background-alt);
|
||||
transform: translate3d(var(--offset-x), var(--offset-y), 0);
|
||||
overflow: hidden;
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
import { getCellComponent } from "./utils"
|
||||
import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
|
||||
|
||||
const { rows, selectedRows, stickyColumn, visibleRows, selectedCellId } =
|
||||
getContext("spreadsheet")
|
||||
const {
|
||||
rows,
|
||||
selectedRows,
|
||||
stickyColumn,
|
||||
visibleRows,
|
||||
selectedCellId,
|
||||
hoveredRowId,
|
||||
scroll,
|
||||
} = getContext("spreadsheet")
|
||||
|
||||
$: scrollLeft = $scroll.left
|
||||
$: rowCount = $rows.length
|
||||
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
|
||||
$: width = 40 + $stickyColumn?.width || 0
|
||||
|
@ -41,7 +49,11 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<div class="sticky-column" style="--width:{width}px;">
|
||||
<div
|
||||
class="sticky-column"
|
||||
style="--width:{width}px;"
|
||||
class:scrolled={scrollLeft > 0}
|
||||
>
|
||||
<div class="row">
|
||||
<!-- Field headers -->
|
||||
<SheetCell header label on:click={selectAll} width="40" left="0">
|
||||
|
@ -67,70 +79,96 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
<SheetScrollWrapper scrollHorizontally={false}>
|
||||
{#each $visibleRows as row}
|
||||
{@const rowSelected = !!$selectedRows[row._id]}
|
||||
<div class="row">
|
||||
<div on:mouseleave={() => ($hoveredRowId = null)}>
|
||||
<SheetScrollWrapper scrollHorizontally={false}>
|
||||
{#each $visibleRows as row}
|
||||
{@const rowSelected = !!$selectedRows[row._id]}
|
||||
{@const rowHovered = $hoveredRowId === row._id}
|
||||
<div class="row" on:mouseenter={() => ($hoveredRowId = row._id)}>
|
||||
<SheetCell
|
||||
label
|
||||
{rowSelected}
|
||||
{rowHovered}
|
||||
on:click={() => selectRow(row._id)}
|
||||
width="40"
|
||||
>
|
||||
<div class="checkbox" class:visible={rowSelected || rowHovered}>
|
||||
<Checkbox value={rowSelected} />
|
||||
</div>
|
||||
<div class="number" class:visible={!(rowSelected || rowHovered)}>
|
||||
{row.__idx + 1}
|
||||
</div>
|
||||
</SheetCell>
|
||||
|
||||
{#if $stickyColumn}
|
||||
{@const cellIdx = `${row._id}-${$stickyColumn.name}`}
|
||||
<SheetCell
|
||||
{rowSelected}
|
||||
{rowHovered}
|
||||
sticky
|
||||
selected={$selectedCellId === cellIdx}
|
||||
on:click={() => ($selectedCellId = cellIdx)}
|
||||
width={$stickyColumn.width}
|
||||
left="40"
|
||||
>
|
||||
<svelte:component
|
||||
this={getCellComponent($stickyColumn)}
|
||||
value={row[$stickyColumn.name]}
|
||||
schema={$stickyColumn.schema}
|
||||
selected={$selectedCellId === cellIdx}
|
||||
onChange={val =>
|
||||
rows.actions.updateRow(row._id, $stickyColumn, val)}
|
||||
readonly={$stickyColumn.schema.autocolumn}
|
||||
/>
|
||||
</SheetCell>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="row new" on:mouseover={() => ($hoveredRowId = "new")}>
|
||||
<SheetCell
|
||||
rowHovered={$hoveredRowId === "new"}
|
||||
label
|
||||
{rowSelected}
|
||||
on:click={() => selectRow(row._id)}
|
||||
on:click={addRow}
|
||||
width="40"
|
||||
>
|
||||
<div class="checkbox" class:visible={rowSelected}>
|
||||
<Checkbox value={rowSelected} />
|
||||
</div>
|
||||
<div class="number" class:visible={!rowSelected}>
|
||||
{row.__idx + 1}
|
||||
</div>
|
||||
<Icon hoverable name="Add" size="S" />
|
||||
</SheetCell>
|
||||
|
||||
{#if $stickyColumn}
|
||||
{@const cellIdx = `${row._id}-${$stickyColumn.name}`}
|
||||
<SheetCell
|
||||
{rowSelected}
|
||||
sticky
|
||||
selected={$selectedCellId === cellIdx}
|
||||
on:click={() => ($selectedCellId = cellIdx)}
|
||||
on:click={addRow}
|
||||
width={$stickyColumn.width}
|
||||
left="40"
|
||||
>
|
||||
<svelte:component
|
||||
this={getCellComponent($stickyColumn)}
|
||||
value={row[$stickyColumn.name]}
|
||||
schema={$stickyColumn.schema}
|
||||
selected={$selectedCellId === cellIdx}
|
||||
onChange={val =>
|
||||
rows.actions.updateRow(row._id, $stickyColumn, val)}
|
||||
readonly={$stickyColumn.schema.autocolumn}
|
||||
/>
|
||||
</SheetCell>
|
||||
rowHovered={$hoveredRowId === "new"}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div class="row">
|
||||
<SheetCell label on:click={addRow} width="40">
|
||||
<Icon hoverable name="Add" size="S" />
|
||||
</SheetCell>
|
||||
{#if $stickyColumn}
|
||||
<SheetCell on:click={addRow} width={$stickyColumn.width} left="40" />
|
||||
{/if}
|
||||
</div>
|
||||
</SheetScrollWrapper>
|
||||
</SheetScrollWrapper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-column {
|
||||
flex: 0 0 var(--width);
|
||||
z-index: 20;
|
||||
overflow: visible;
|
||||
border-right: 1px solid var(--spectrum-global-color-gray-200);
|
||||
}
|
||||
.sticky-column.scrolled {
|
||||
box-shadow: 1px -4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.sticky-column :global(.cell) {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
.row.new:hover :global(.cell) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Styles for label cell */
|
||||
.checkbox {
|
||||
|
@ -140,12 +178,9 @@
|
|||
display: none;
|
||||
color: var(--spectrum-global-color-gray-500);
|
||||
}
|
||||
.row:hover .checkbox,
|
||||
.checkbox.visible {
|
||||
display: flex;
|
||||
}
|
||||
.checkbox.visible,
|
||||
.number.visible {
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
.row:hover .number {
|
||||
display: none;
|
||||
|
|
|
@ -6,6 +6,7 @@ export const createColumnsStores = context => {
|
|||
const columns = writable([])
|
||||
const stickyColumn = writable(null)
|
||||
|
||||
// Merge new schema fields with existing schema in order to preserve widths
|
||||
schema.subscribe($schema => {
|
||||
const currentColumns = get(columns)
|
||||
if (!$schema) {
|
||||
|
|
Loading…
Reference in a new issue