1
0
Fork 0
mirror of synced 2024-07-14 18:55:45 +12:00

Add resizable rows

This commit is contained in:
Andrew Kingston 2023-03-31 20:33:08 +01:00
parent a0299d4c7c
commit fcb8b9e9b1
19 changed files with 108 additions and 46 deletions

View file

@ -122,7 +122,7 @@
flex-direction: row;
justify-content: flex-start;
align-items: center;
height: calc(var(--cell-height) - 12px);
height: calc(var(--row-height) - 12px);
padding: 0 8px;
color: var(--spectrum-global-color-gray-800);
border: 1px solid var(--spectrum-global-color-gray-300);
@ -133,7 +133,7 @@
user-select: none;
}
img {
height: calc(var(--cell-height) - 12px);
height: calc(var(--row-height) - 12px);
max-width: 64px;
}
.dropzone {

View file

@ -92,7 +92,7 @@
top: -1px;
left: -1px;
width: calc(100% + 100px);
height: calc(5 * var(--cell-height) + 1px);
height: calc(5 * var(--row-height) + 1px);
border: var(--cell-border);
box-shadow: inset 0 0 0 2px var(--spectrum-global-color-blue-400);
}

View file

@ -192,7 +192,7 @@
top: 0;
}
.option {
flex: 0 0 var(--cell-height);
flex: 0 0 var(--row-height);
padding: 0 var(--cell-padding);
display: flex;
flex-direction: row;
@ -202,7 +202,7 @@
background-color: var(--cell-background-hover);
}
.option:first-child {
flex: 0 0 calc(var(--cell-height) - 1px);
flex: 0 0 calc(var(--row-height) - 1px);
}
.option:hover,
.option.focused {

View file

@ -316,7 +316,7 @@
}
.result {
padding: 0 var(--cell-padding);
flex: 0 0 var(--cell-height);
flex: 0 0 var(--row-height);
display: flex;
gap: var(--cell-spacing);
justify-content: space-between;
@ -331,7 +331,7 @@
}
.search {
flex: 0 0 calc(var(--cell-height) - 1px);
flex: 0 0 calc(var(--row-height) - 1px);
display: flex;
align-items: center;
margin: 0 var(--cell-padding);
@ -349,7 +349,7 @@
color: var(--spectrum-global-color-gray-600);
font-size: 12px;
padding: var(--cell-padding);
flex: 0 0 var(--cell-height);
flex: 0 0 var(--row-height);
display: flex;
align-items: center;
white-space: nowrap;

View file

@ -54,7 +54,7 @@
<style>
/* Cells */
.cell {
height: var(--cell-height);
height: var(--row-height);
border-bottom: var(--cell-border);
border-right: var(--cell-border);
display: flex;
@ -123,7 +123,7 @@
right: 0;
background: var(--spectrum-global-color-blue-400);
width: 2px;
height: calc(var(--cell-height) + 2px);
height: calc(var(--row-height) + 2px);
}
/* Other user email */

View file

@ -0,0 +1,58 @@
<script>
import { getContext } from "svelte"
import { ActionButton, Popover } from "@budibase/bbui"
const { rowHeight } = getContext("sheet")
const sizeOptions = [
{
label: "Small",
size: 36,
},
{
label: "Medium",
size: 54,
},
{
label: "Large",
size: 72,
},
]
let open = false
let anchor
</script>
<div bind:this={anchor}>
<ActionButton
icon="LineHeight"
quiet
size="M"
on:click={() => (open = !open)}
selected={open}
>
Row height
</ActionButton>
</div>
<Popover bind:open {anchor} align="left">
<div class="content">
{#each sizeOptions as option}
<ActionButton
quiet
selected={$rowHeight === option.size}
on:click={() => rowHeight.set(option.size)}
>
{option.label}
</ActionButton>
{/each}
</div>
</Popover>
<style>
.content {
padding: 12px;
display: flex;
align-items: center;
gap: 8px;
}
</style>

View file

@ -33,7 +33,7 @@
border-bottom: var(--cell-border);
position: relative;
z-index: 2;
height: var(--cell-height);
height: var(--row-height);
}
.row {
display: flex;
@ -42,7 +42,7 @@
position: absolute;
right: 0;
top: 0;
height: var(--cell-height);
height: var(--row-height);
background: var(--spectrum-global-color-gray-100);
display: grid;
place-items: center;

View file

@ -149,7 +149,7 @@
.container {
pointer-events: none;
position: absolute;
top: var(--cell-height);
top: var(--row-height);
transform: translateY(-100%);
z-index: 1;
transition: transform 130ms ease-out;

View file

@ -40,7 +40,6 @@
export let allowEditRows = true
// Sheet constants
const cellHeight = 36
const gutterWidth = 72
const rand = Math.random()
@ -60,7 +59,6 @@
let context = {
API: API || createAPIClient(),
rand,
cellHeight,
gutterWidth,
config,
tableId: tableIdStore,
@ -81,7 +79,7 @@
context = { ...context, ...createWheelStores(context) }
// Reference some stores for local use
const { isResizing, isReordering, ui, loaded } = context
const { isResizing, isReordering, ui, loaded, rowHeight } = context
// Keep stores up to date
$: tableIdStore.set(tableId)
@ -109,7 +107,7 @@
id="sheet-{rand}"
class:is-resizing={$isResizing}
class:is-reordering={$isReordering}
style="--cell-height:{cellHeight}px; --gutter-width:{gutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px;"
style="--row-height:{$rowHeight}px; --gutter-width:{gutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px;"
>
<div class="controls">
<div class="controls-left">

View file

@ -4,14 +4,13 @@
import SheetRow from "./SheetRow.svelte"
import { MaxCellRenderHeight } from "../lib/constants"
const { bounds, renderedRows, visualRowCapacity, cellHeight } =
const { bounds, renderedRows, visualRowCapacity, rowHeight } =
getContext("sheet")
let body
$: inversionIdx =
$visualRowCapacity - Math.ceil(MaxCellRenderHeight / cellHeight) - 2
$: console.log(inversionIdx)
$visualRowCapacity - Math.ceil(MaxCellRenderHeight / $rowHeight) - 2
onMount(() => {
// Observe and record the height of the body

View file

@ -2,8 +2,10 @@
import SortButton from "../controls/SortButton.svelte"
import HideColumnsButton from "../controls/HideColumnsButton.svelte"
import AddRowButton from "../controls/AddRowButton.svelte"
import RowHeightButton from "../controls/RowHeightButton.svelte"
</script>
<AddRowButton />
<HideColumnsButton />
<SortButton />
<RowHeightButton />

View file

@ -2,7 +2,7 @@
import { getContext } from "svelte"
const {
cellHeight,
rowHeight,
scroll,
visibleColumns,
renderedColumns,
@ -15,11 +15,11 @@
export let wheelInteractive = true
$: hiddenWidths = calculateHiddenWidths($renderedColumns)
$: style = generateStyle($scroll, hiddenWidths)
$: style = generateStyle($scroll, $rowHeight, hiddenWidths)
const generateStyle = (scroll, hiddenWidths) => {
const generateStyle = (scroll, rowHeight, hiddenWidths) => {
const offsetX = scrollHorizontally ? -1 * scroll.left + hiddenWidths : 0
const offsetY = scrollVertically ? -1 * (scroll.top % cellHeight) : 0
const offsetY = scrollVertically ? -1 * (scroll.top % rowHeight) : 0
return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);`
}

View file

@ -51,8 +51,8 @@
.resize-slider {
position: absolute;
top: 0;
z-index: 1;
height: var(--cell-height);
z-index: 2;
height: var(--row-height);
opacity: 0;
padding: 0 8px;
transform: translateX(-50%);
@ -64,7 +64,7 @@
opacity: 1;
}
.resize-slider.sticky {
z-index: 2;
z-index: 3;
}
.resize-indicator {
margin-left: -1px;

View file

@ -5,7 +5,7 @@
const {
scroll,
bounds,
cellHeight,
rowHeight,
contentHeight,
maxScrollTop,
contentWidth,
@ -35,7 +35,7 @@
$: renderHeight = height - 2 * barOffset
$: barHeight = Math.max(50, (height / $contentHeight) * renderHeight)
$: availHeight = renderHeight - barHeight
$: barTop = barOffset + cellHeight + availHeight * (scrollTop / $maxScrollTop)
$: barTop = barOffset + $rowHeight + availHeight * (scrollTop / $maxScrollTop)
// Calculate H scrollbar size and offset
$: renderWidth = $screenWidth - 2 * barOffset

View file

@ -6,7 +6,7 @@ export const createMaxScrollStores = context => {
visibleColumns,
stickyColumn,
bounds,
cellHeight,
rowHeight,
scroll,
selectedCellRow,
selectedCellId,
@ -23,8 +23,8 @@ export const createMaxScrollStores = context => {
const height = derived(bounds, $bounds => $bounds.height, 0)
const width = derived(bounds, $bounds => $bounds.width, 0)
const contentHeight = derived(
rows,
$rows => $rows.length * cellHeight + padding,
[rows, rowHeight],
([$rows, $rowHeight]) => $rows.length * $rowHeight + padding,
0
)
const maxScrollTop = derived(
@ -94,12 +94,13 @@ export const createMaxScrollStores = context => {
}
const $scroll = get(scroll)
const $bounds = get(bounds)
const $rowHeight = get(rowHeight)
const scrollBarOffset = 16
// Ensure row is not below bottom of screen
const rowYPos = row.__idx * cellHeight
const rowYPos = row.__idx * $rowHeight
const bottomCutoff =
$scroll.top + $bounds.height - cellHeight - scrollBarOffset
$scroll.top + $bounds.height - $rowHeight - scrollBarOffset
let delta = rowYPos - bottomCutoff
if (delta > 0) {
scroll.update(state => ({

View file

@ -1,7 +1,7 @@
import { writable, get } from "svelte/store"
export const createMenuStores = context => {
const { bounds, selectedCellId, stickyColumn, cellHeight } = context
const { bounds, selectedCellId, stickyColumn, rowHeight } = context
const menu = writable({
x: 0,
y: 0,
@ -12,11 +12,12 @@ export const createMenuStores = context => {
const open = (cellId, e) => {
const $bounds = get(bounds)
const $stickyColumn = get(stickyColumn)
const $rowHeight = get(rowHeight)
e.preventDefault()
selectedCellId.set(cellId)
menu.set({
left: e.clientX - $bounds.left + 44 + ($stickyColumn?.width || 0),
top: e.clientY - $bounds.top + cellHeight + 4,
top: e.clientY - $bounds.top + $rowHeight + 4,
visible: true,
})
}

View file

@ -6,6 +6,7 @@ export const createUIStores = context => {
const selectedRows = writable({})
const hoveredRowId = writable(null)
const selectedCellAPI = writable(null)
const rowHeight = writable(36)
// Derive the row that contains the selected cell.
const selectedCellRow = derived(
@ -92,6 +93,7 @@ export const createUIStores = context => {
hoveredRowId,
selectedCellRow,
selectedCellAPI,
rowHeight,
ui: {
actions: {
blur,

View file

@ -1,7 +1,7 @@
import { derived, get } from "svelte/store"
export const createViewportStores = context => {
const { cellHeight, visibleColumns, rows, scroll, bounds } = context
const { rowHeight, visibleColumns, rows, scroll, bounds } = context
const scrollTop = derived(scroll, $scroll => $scroll.top, 0)
const scrollLeft = derived(scroll, $scroll => $scroll.left, 0)
@ -13,16 +13,16 @@ export const createViewportStores = context => {
// Split into multiple stores containing primitives to optimise invalidation
// as much as possible
const scrolledRowCount = derived(
scrollTop,
$scrollTop => {
return Math.floor($scrollTop / cellHeight)
[scrollTop, rowHeight],
([$scrollTop, $rowHeight]) => {
return Math.floor($scrollTop / $rowHeight)
},
0
)
const visualRowCapacity = derived(
height,
$height => {
return Math.ceil($height / cellHeight) + 1
[height, rowHeight],
([$height, $rowHeight]) => {
return Math.ceil($height / $rowHeight) + 1
},
0
)

View file

@ -9,7 +9,7 @@ export const createWheelStores = context => {
renderedRows,
bounds,
scroll,
cellHeight,
rowHeight,
} = context
// Handles a wheel even and updates the scroll offsets
@ -22,6 +22,7 @@ export const createWheelStores = context => {
}
const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => {
const { top, left } = get(scroll)
const $rowHeight = get(rowHeight)
// Calculate new scroll top
let newScrollTop = top + deltaY
@ -38,8 +39,8 @@ export const createWheelStores = context => {
})
// Hover row under cursor
const y = clientY - get(bounds).top + (newScrollTop % cellHeight)
const hoveredRow = get(renderedRows)[Math.floor(y / cellHeight)]
const y = clientY - get(bounds).top + (newScrollTop % $rowHeight)
const hoveredRow = get(renderedRows)[Math.floor(y / $rowHeight)]
hoveredRowId.set(hoveredRow?._id)
})