Add popovers to sheet column headers, improve mouse UX

This commit is contained in:
Andrew Kingston 2023-03-06 15:09:42 +00:00
parent 36e8664605
commit b93f575bca
8 changed files with 90 additions and 62 deletions

View File

@ -19,6 +19,7 @@
export let dismissible = true export let dismissible = true
export let offset = 5 export let offset = 5
export let customHeight export let customHeight
export let animate = true
$: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum" $: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum"
@ -76,7 +77,7 @@
class="spectrum-Popover is-open" class="spectrum-Popover is-open"
role="presentation" role="presentation"
style="height: {customHeight}" style="height: {customHeight}"
transition:fly|local={{ y: -20, duration: 200 }} transition:fly|local={{ y: -20, duration: animate ? 200 : 0 }}
> >
<slot /> <slot />
</div> </div>

View File

@ -228,5 +228,6 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--background); background: var(--background);
overflow: hidden;
} }
</style> </style>

View File

@ -1,15 +1,8 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
const { const { columns, rand, scroll, visibleColumns, stickyColumn } =
visibleRows, getContext("sheet")
columns,
rand,
scroll,
visibleColumns,
cellHeight,
stickyColumn,
} = getContext("sheet")
const MinColumnWidth = 100 const MinColumnWidth = 100
let initialMouseX = null let initialMouseX = null
@ -22,8 +15,6 @@
$: scrollLeft = $scroll.left $: scrollLeft = $scroll.left
$: cutoff = scrollLeft + 40 + ($columns[0]?.width || 0) $: cutoff = scrollLeft + 40 + ($columns[0]?.width || 0)
$: offset = 40 + ($stickyColumn?.width || 0) $: offset = 40 + ($stickyColumn?.width || 0)
$: rowCount = $visibleRows.length
$: contentHeight = (rowCount + 2) * cellHeight
const startResizing = (idx, e) => { const startResizing = (idx, e) => {
// Prevent propagation to stop reordering triggering // Prevent propagation to stop reordering triggering
@ -78,9 +69,9 @@
document.getElementById(`sheet-${rand}`).classList.remove("is-resizing") document.getElementById(`sheet-${rand}`).classList.remove("is-resizing")
} }
const getStyle = (col, offset, scrollLeft, contentHeight) => { const getStyle = (col, offset, scrollLeft) => {
const left = offset + col.left + col.width - scrollLeft const left = offset + col.left + col.width - scrollLeft
return `--left:${left}px; --content-height:${contentHeight}px;` return `--left:${left}px;`
} }
</script> </script>
@ -89,8 +80,7 @@
class="resize-slider sticky" class="resize-slider sticky"
class:visible={columnIdx === "sticky"} class:visible={columnIdx === "sticky"}
on:mousedown={e => startResizing("sticky", e)} on:mousedown={e => startResizing("sticky", e)}
style="--left:{40 + style="--left:{40 + $stickyColumn.width}px;"
$stickyColumn.width}px; --content-height:{contentHeight}px;"
> >
<div class="resize-indicator" /> <div class="resize-indicator" />
</div> </div>
@ -100,7 +90,7 @@
class="resize-slider" class="resize-slider"
class:visible={columnIdx === col.idx} class:visible={columnIdx === col.idx}
on:mousedown={e => startResizing(col.idx, e)} on:mousedown={e => startResizing(col.idx, e)}
style={getStyle(col, offset, scrollLeft, contentHeight)} style={getStyle(col, offset, scrollLeft)}
> >
<div class="resize-indicator" /> <div class="resize-indicator" />
</div> </div>
@ -114,7 +104,7 @@
height: var(--cell-height); height: var(--cell-height);
left: var(--left); left: var(--left);
opacity: 0; opacity: 0;
padding: 0 16px; padding: 0 8px;
transform: translateX(-50%); transform: translateX(-50%);
user-select: none; user-select: none;
} }
@ -122,7 +112,6 @@
.resize-slider.visible { .resize-slider.visible {
cursor: col-resize; cursor: col-resize;
opacity: 1; opacity: 1;
height: min(var(--content-height), 100%);
} }
.resize-slider.sticky { .resize-slider.sticky {
z-index: 2; z-index: 2;

View File

@ -5,6 +5,7 @@
import SheetCell from "./cells/SheetCell.svelte" import SheetCell from "./cells/SheetCell.svelte"
import { getCellRenderer } from "./renderers" import { getCellRenderer } from "./renderers"
import SheetScrollWrapper from "./SheetScrollWrapper.svelte" import SheetScrollWrapper from "./SheetScrollWrapper.svelte"
import HeaderCell from "./cells/HeaderCell.svelte"
const { const {
rows, rows,
@ -67,6 +68,7 @@
<!-- Field headers --> <!-- Field headers -->
<SheetCell <SheetCell
header header
foo
label label
width="40" width="40"
on:click={$config.allowSelectRows && selectAll} on:click={$config.allowSelectRows && selectAll}
@ -77,21 +79,7 @@
</SheetCell> </SheetCell>
{#if $stickyColumn} {#if $stickyColumn}
<SheetCell <HeaderCell column={$stickyColumn} />
header
sticky
width={$stickyColumn.width}
reorderTarget={$reorder.targetColumn === $stickyColumn.name}
>
<Icon
size="S"
name={getIconForField($stickyColumn)}
color="var(--spectrum-global-color-gray-600)"
/>
<span>
{$stickyColumn.name}
</span>
</SheetCell>
{/if} {/if}
</div> </div>

View File

@ -1,56 +1,92 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import SheetCell from "./SheetCell.svelte" import SheetCell from "./SheetCell.svelte"
import { Icon, Popover } from "@budibase/bbui" import { Icon, Popover, Menu, MenuItem } from "@budibase/bbui"
import { getIconForField } from "../utils" import { getIconForField } from "../utils"
export let column export let column
const { reorder } = getContext("sheet") const { reorder, isReordering, rand } = getContext("sheet")
let popover let timeout
let anchor let anchor
let open = false
let isClick = true
const openPopover = () => { const startReordering = e => {
console.log("open") isClick = true
popover.show() timeout = setTimeout(() => {
isClick = false
reorder.actions.startReordering(column.name, e)
}, 250)
}
const stopReordering = () => {
clearTimeout(timeout)
}
const onClick = () => {
if (isClick) {
stopReordering()
open = true
}
} }
</script> </script>
<div class="header-cell" bind:this={anchor}> <div
class="header-cell"
class:open
style="flex: 0 0 {column.width}px;"
bind:this={anchor}
class:disabled={$isReordering}
>
<SheetCell <SheetCell
reorderSource={$reorder.sourceColumn === column.name} reorderSource={$reorder.sourceColumn === column.name}
reorderTarget={$reorder.targetColumn === column.name} reorderTarget={$reorder.targetColumn === column.name}
on:mousedown={e => reorder.actions.startReordering(column.name, e)} on:mousedown={startReordering}
on:click={openPopover} on:mouseup={stopReordering}
on:click={onClick}
width={column.width} width={column.width}
left={column.left} left={column.left}
> >
<div class="content"> <Icon
<Icon size="S"
size="S" name={getIconForField(column)}
name={getIconForField(column)} color="var(--spectrum-global-color-gray-600)"
color="var(--spectrum-global-color-gray-600)" />
/> <div class="name">
<div class="name"> {column.name}
{column.name} asdasdasd asdasdas asdasdasd </div>
</div> <div class="more">
<div class="more"> <Icon size="S" name="MoreVertical" />
<Icon size="S" name="MoreVertical" />
</div>
</div> </div>
</SheetCell> </SheetCell>
</div> </div>
<Popover bind:this={popover} {anchor} align="left" <Popover
>asdsad asdasd asdasd asasa</Popover bind:open
{anchor}
align="left"
offset={0}
popoverTarget={document.getElementById(`sheet-${rand}`)}
animate={false}
> >
<Menu>
<MenuItem icon="Edit">Edit column</MenuItem>
<MenuItem icon="SortOrderUp">Sort ascending</MenuItem>
<MenuItem icon="SortOrderDown">Sort descending</MenuItem>
<MenuItem icon="ArrowLeft">Move left</MenuItem>
<MenuItem icon="ArrowRight">Move right</MenuItem>
<MenuItem icon="Delete">Delete</MenuItem>
</Menu>
</Popover>
<style> <style>
.header-cell { .header-cell {
display: contents; display: flex;
} }
.header-cell:hover :global(.cell) { .header-cell:not(.disabled):hover :global(.cell),
.header-cell:not(.disabled).open :global(.cell) {
cursor: pointer; cursor: pointer;
background: var(--spectrum-global-color-gray-200); background: var(--spectrum-global-color-gray-200);
} }
@ -72,7 +108,8 @@
.more { .more {
display: none; display: none;
} }
.header-cell:hover .more { .header-cell:not(.disabled):hover .more,
.header-cell:not(.disabled).open .more {
display: block; display: block;
} }
</style> </style>

View File

@ -10,6 +10,7 @@
export let center = false export let center = false
export let selectedUser = null export let selectedUser = null
export let rowIdx export let rowIdx
export let foo
$: style = getStyle(width, selectedUser) $: style = getStyle(width, selectedUser)
@ -24,6 +25,7 @@
<div <div
class="cell" class="cell"
class:foo
class:label class:label
class:row-selected={rowSelected} class:row-selected={rowSelected}
class:row-hovered={rowHovered} class:row-hovered={rowHovered}
@ -34,8 +36,9 @@
class:reorder-target={reorderTarget} class:reorder-target={reorderTarget}
class:center class:center
on:focus on:focus
on:click
on:mousedown on:mousedown
on:mouseup
on:click
{style} {style}
data-row={rowIdx} data-row={rowIdx}
> >
@ -113,6 +116,9 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.cell.foo {
background: var(--spectrum-global-color-gray-100);
}
/* Other user email */ /* Other user email */
.user { .user {

View File

@ -1,4 +1,4 @@
import { get, writable } from "svelte/store" import { get, writable, derived } from "svelte/store"
export const createReorderStores = context => { export const createReorderStores = context => {
const { columns, rand, scroll, bounds, stickyColumn } = context const { columns, rand, scroll, bounds, stickyColumn } = context
@ -7,8 +7,11 @@ export const createReorderStores = context => {
targetColumn: null, targetColumn: null,
breakpoints: [], breakpoints: [],
initialMouseX: null, initialMouseX: null,
scrollLeft: 0,
sheetLeft: 0,
} }
const reorder = writable(reorderInitialState) const reorder = writable(reorderInitialState)
const isReordering = derived(reorder, $reorder => !!$reorder.sourceColumn)
// Callback when dragging on a colum header and starting reordering // Callback when dragging on a colum header and starting reordering
const startReordering = (column, e) => { const startReordering = (column, e) => {
@ -115,5 +118,6 @@ export const createReorderStores = context => {
stopReordering, stopReordering,
}, },
}, },
isReordering,
} }
} }

View File

@ -4,6 +4,7 @@ import Koa from "koa"
import Cookies from "cookies" import Cookies from "cookies"
import { userAgent } from "koa-useragent" import { userAgent } from "koa-useragent"
import { auth } from "@budibase/backend-core" import { auth } from "@budibase/backend-core"
import currentApp from "../middleware/currentapp"
export default class Socket { export default class Socket {
io: Server io: Server
@ -25,6 +26,7 @@ export default class Socket {
const middlewares = [ const middlewares = [
userAgent, userAgent,
authenticate, authenticate,
// currentApp,
...(additionalMiddlewares || []), ...(additionalMiddlewares || []),
] ]