Merge pull request #10695 from Budibase/grid-feedback
Grid enhancements from user feedback
This commit is contained in:
commit
3a672b3660
|
@ -37,6 +37,9 @@
|
||||||
.boolean-cell {
|
.boolean-cell {
|
||||||
padding: 2px var(--cell-padding);
|
padding: 2px var(--cell-padding);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.boolean-cell.editable {
|
.boolean-cell.editable {
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
export let selected
|
export let selected
|
||||||
export let rowFocused
|
export let rowFocused
|
||||||
export let rowIdx
|
export let rowIdx
|
||||||
|
export let topRow = false
|
||||||
export let focused
|
export let focused
|
||||||
export let selectedUser
|
export let selectedUser
|
||||||
export let column
|
export let column
|
||||||
|
@ -68,6 +69,7 @@
|
||||||
{highlighted}
|
{highlighted}
|
||||||
{selected}
|
{selected}
|
||||||
{rowIdx}
|
{rowIdx}
|
||||||
|
{topRow}
|
||||||
{focused}
|
{focused}
|
||||||
{selectedUser}
|
{selectedUser}
|
||||||
{readonly}
|
{readonly}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
export let selectedUser = null
|
export let selectedUser = null
|
||||||
export let error = null
|
export let error = null
|
||||||
export let rowIdx
|
export let rowIdx
|
||||||
|
export let topRow = false
|
||||||
export let defaultHeight = false
|
export let defaultHeight = false
|
||||||
export let center = false
|
export let center = false
|
||||||
export let readonly = false
|
export let readonly = false
|
||||||
|
@ -31,13 +32,14 @@
|
||||||
class:readonly
|
class:readonly
|
||||||
class:default-height={defaultHeight}
|
class:default-height={defaultHeight}
|
||||||
class:selected-other={selectedUser != null}
|
class:selected-other={selectedUser != null}
|
||||||
|
class:alt={rowIdx % 2 === 1}
|
||||||
|
class:top={topRow}
|
||||||
on:focus
|
on:focus
|
||||||
on:mousedown
|
on:mousedown
|
||||||
on:mouseup
|
on:mouseup
|
||||||
on:click
|
on:click
|
||||||
on:contextmenu
|
on:contextmenu
|
||||||
{style}
|
{style}
|
||||||
data-row={rowIdx}
|
|
||||||
>
|
>
|
||||||
{#if error}
|
{#if error}
|
||||||
<div class="label">
|
<div class="label">
|
||||||
|
@ -70,6 +72,9 @@
|
||||||
width: 0;
|
width: 0;
|
||||||
--cell-color: transparent;
|
--cell-color: transparent;
|
||||||
}
|
}
|
||||||
|
.cell.alt {
|
||||||
|
--cell-background: var(--cell-background-alt);
|
||||||
|
}
|
||||||
.cell.default-height {
|
.cell.default-height {
|
||||||
height: var(--default-row-height);
|
height: var(--default-row-height);
|
||||||
}
|
}
|
||||||
|
@ -98,8 +103,8 @@
|
||||||
.cell.selected-other:not(.focused):after {
|
.cell.selected-other:not(.focused):after {
|
||||||
border-radius: 0 2px 2px 2px;
|
border-radius: 0 2px 2px 2px;
|
||||||
}
|
}
|
||||||
.cell[data-row="0"].error:after,
|
.cell.top.error:after,
|
||||||
.cell[data-row="0"].selected-other:not(.focused):after {
|
.cell.top.selected-other:not(.focused):after {
|
||||||
border-radius: 2px 2px 2px 0;
|
border-radius: 2px 2px 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +157,7 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
.cell[data-row="0"] .label {
|
.cell.top .label {
|
||||||
bottom: auto;
|
bottom: auto;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
border-radius: 0 2px 2px 2px;
|
border-radius: 0 2px 2px 2px;
|
||||||
|
|
|
@ -21,16 +21,7 @@
|
||||||
svelteDispatch("select")
|
svelteDispatch("select")
|
||||||
const id = row?._id
|
const id = row?._id
|
||||||
if (id) {
|
if (id) {
|
||||||
selectedRows.update(state => {
|
selectedRows.actions.toggleRow(id)
|
||||||
let newState = {
|
|
||||||
...state,
|
|
||||||
[id]: !state[id],
|
|
||||||
}
|
|
||||||
if (!newState[id]) {
|
|
||||||
delete newState[id]
|
|
||||||
}
|
|
||||||
return newState
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +38,7 @@
|
||||||
highlighted={rowFocused || rowHovered}
|
highlighted={rowFocused || rowHovered}
|
||||||
selected={rowSelected}
|
selected={rowSelected}
|
||||||
{defaultHeight}
|
{defaultHeight}
|
||||||
|
rowIdx={row?.__idx}
|
||||||
>
|
>
|
||||||
<div class="gutter">
|
<div class="gutter">
|
||||||
{#if $$slots.default}
|
{#if $$slots.default}
|
||||||
|
|
|
@ -196,7 +196,11 @@
|
||||||
<MenuItem disabled={!canMoveRight} icon="ChevronRight" on:click={moveRight}>
|
<MenuItem disabled={!canMoveRight} icon="ChevronRight" on:click={moveRight}>
|
||||||
Move right
|
Move right
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem icon="VisibilityOff" on:click={hideColumn}>Hide column</MenuItem>
|
<MenuItem
|
||||||
|
disabled={idx === "sticky"}
|
||||||
|
icon="VisibilityOff"
|
||||||
|
on:click={hideColumn}>Hide column</MenuItem
|
||||||
|
>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
export let allowExpandRows = true
|
export let allowExpandRows = true
|
||||||
export let allowEditRows = true
|
export let allowEditRows = true
|
||||||
export let allowDeleteRows = true
|
export let allowDeleteRows = true
|
||||||
|
export let stripeRows = false
|
||||||
|
|
||||||
// Unique identifier for DOM nodes inside this instance
|
// Unique identifier for DOM nodes inside this instance
|
||||||
const rand = Math.random()
|
const rand = Math.random()
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
allowExpandRows,
|
allowExpandRows,
|
||||||
allowEditRows,
|
allowEditRows,
|
||||||
allowDeleteRows,
|
allowDeleteRows,
|
||||||
|
stripeRows,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Build up context
|
// Build up context
|
||||||
|
@ -90,6 +92,7 @@
|
||||||
allowExpandRows,
|
allowExpandRows,
|
||||||
allowEditRows,
|
allowEditRows,
|
||||||
allowDeleteRows,
|
allowDeleteRows,
|
||||||
|
stripeRows,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set context for children to consume
|
// Set context for children to consume
|
||||||
|
@ -107,6 +110,7 @@
|
||||||
id="grid-{rand}"
|
id="grid-{rand}"
|
||||||
class:is-resizing={$isResizing}
|
class:is-resizing={$isResizing}
|
||||||
class:is-reordering={$isReordering}
|
class:is-reordering={$isReordering}
|
||||||
|
class:stripe={$config.stripeRows}
|
||||||
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px; --max-cell-render-width-overflow:{MaxCellRenderWidthOverflow}px; --content-lines:{$contentLines};"
|
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px; --max-cell-render-width-overflow:{MaxCellRenderWidthOverflow}px; --content-lines:{$contentLines};"
|
||||||
>
|
>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
|
@ -169,6 +173,7 @@
|
||||||
/* Variables */
|
/* Variables */
|
||||||
--cell-background: var(--spectrum-global-color-gray-50);
|
--cell-background: var(--spectrum-global-color-gray-50);
|
||||||
--cell-background-hover: var(--spectrum-global-color-gray-100);
|
--cell-background-hover: var(--spectrum-global-color-gray-100);
|
||||||
|
--cell-background-alt: var(--cell-background);
|
||||||
--cell-padding: 8px;
|
--cell-padding: 8px;
|
||||||
--cell-spacing: 4px;
|
--cell-spacing: 4px;
|
||||||
--cell-border: 1px solid var(--spectrum-global-color-gray-200);
|
--cell-border: 1px solid var(--spectrum-global-color-gray-200);
|
||||||
|
@ -185,6 +190,9 @@
|
||||||
.grid.is-reordering :global(*) {
|
.grid.is-reordering :global(*) {
|
||||||
cursor: grabbing !important;
|
cursor: grabbing !important;
|
||||||
}
|
}
|
||||||
|
.grid.stripe {
|
||||||
|
--cell-background-alt: var(--spectrum-global-color-gray-75);
|
||||||
|
}
|
||||||
|
|
||||||
.grid-data-outer,
|
.grid-data-outer,
|
||||||
.grid-data-inner {
|
.grid-data-inner {
|
||||||
|
|
|
@ -36,7 +36,11 @@
|
||||||
<div bind:this={body} class="grid-body">
|
<div bind:this={body} class="grid-body">
|
||||||
<GridScrollWrapper scrollHorizontally scrollVertically wheelInteractive>
|
<GridScrollWrapper scrollHorizontally scrollVertically wheelInteractive>
|
||||||
{#each $renderedRows as row, idx}
|
{#each $renderedRows as row, idx}
|
||||||
<GridRow {row} {idx} invertY={idx >= $rowVerticalInversionIndex} />
|
<GridRow
|
||||||
|
{row}
|
||||||
|
top={idx === 0}
|
||||||
|
invertY={idx >= $rowVerticalInversionIndex}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{#if $config.allowAddRows && $renderedColumns.length}
|
{#if $config.allowAddRows && $renderedColumns.length}
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import DataCell from "../cells/DataCell.svelte"
|
import DataCell from "../cells/DataCell.svelte"
|
||||||
|
|
||||||
export let row
|
export let row
|
||||||
export let idx
|
export let top = false
|
||||||
export let invertY = false
|
export let invertY = false
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -41,7 +41,8 @@
|
||||||
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
||||||
highlighted={rowHovered || rowFocused || reorderSource === column.name}
|
highlighted={rowHovered || rowFocused || reorderSource === column.name}
|
||||||
selected={rowSelected}
|
selected={rowSelected}
|
||||||
rowIdx={idx}
|
rowIdx={row.__idx}
|
||||||
|
topRow={top}
|
||||||
focused={$focusedCellId === cellId}
|
focused={$focusedCellId === cellId}
|
||||||
selectedUser={$selectedCellMap[cellId]}
|
selectedUser={$selectedCellMap[cellId]}
|
||||||
width={column.width}
|
width={column.width}
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
border-right: var(--cell-border);
|
border-right: var(--cell-border);
|
||||||
border-bottom: var(--cell-border);
|
border-bottom: var(--cell-border);
|
||||||
background: var(--spectrum-global-color-gray-100);
|
background: var(--spectrum-global-color-gray-100);
|
||||||
z-index: 20;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.add:hover {
|
.add:hover {
|
||||||
background: var(--spectrum-global-color-gray-200);
|
background: var(--spectrum-global-color-gray-200);
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background-color: var(--spectrum-global-color-gray-200);
|
background-color: var(--spectrum-global-color-gray-300);
|
||||||
color: var(--spectrum-global-color-gray-700);
|
color: var(--spectrum-global-color-gray-700);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
focused={$focusedCellId === cellId}
|
focused={$focusedCellId === cellId}
|
||||||
width={$stickyColumn.width}
|
width={$stickyColumn.width}
|
||||||
{updateValue}
|
{updateValue}
|
||||||
rowIdx={0}
|
topRow={offset === 0}
|
||||||
{invertY}
|
{invertY}
|
||||||
>
|
>
|
||||||
{#if $stickyColumn?.schema?.autocolumn}
|
{#if $stickyColumn?.schema?.autocolumn}
|
||||||
|
@ -193,7 +193,7 @@
|
||||||
row={newRow}
|
row={newRow}
|
||||||
focused={$focusedCellId === cellId}
|
focused={$focusedCellId === cellId}
|
||||||
width={column.width}
|
width={column.width}
|
||||||
rowIdx={0}
|
topRow={offset === 0}
|
||||||
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
||||||
{invertY}
|
{invertY}
|
||||||
>
|
>
|
||||||
|
@ -219,7 +219,7 @@
|
||||||
<Button size="M" secondary newStyles on:click={clear}>
|
<Button size="M" secondary newStyles on:click={clear}>
|
||||||
<div class="button-with-keys">
|
<div class="button-with-keys">
|
||||||
Cancel
|
Cancel
|
||||||
<KeyboardShortcut overlay keybind="Esc" />
|
<KeyboardShortcut keybind="Esc" />
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -82,7 +82,8 @@
|
||||||
{rowFocused}
|
{rowFocused}
|
||||||
selected={rowSelected}
|
selected={rowSelected}
|
||||||
highlighted={rowHovered || rowFocused}
|
highlighted={rowHovered || rowFocused}
|
||||||
rowIdx={idx}
|
rowIdx={row.__idx}
|
||||||
|
topRow={idx === 0}
|
||||||
focused={$focusedCellId === cellId}
|
focused={$focusedCellId === cellId}
|
||||||
selectedUser={$selectedCellMap[cellId]}
|
selectedUser={$selectedCellMap[cellId]}
|
||||||
width={$stickyColumn.width}
|
width={$stickyColumn.width}
|
||||||
|
|
|
@ -224,10 +224,7 @@
|
||||||
if (!id || id === NewRowID) {
|
if (!id || id === NewRowID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectedRows.update(state => {
|
selectedRows.actions.toggleRow(id)
|
||||||
state[id] = !state[id]
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|
|
@ -4,9 +4,10 @@ const reorderInitialState = {
|
||||||
sourceColumn: null,
|
sourceColumn: null,
|
||||||
targetColumn: null,
|
targetColumn: null,
|
||||||
breakpoints: [],
|
breakpoints: [],
|
||||||
initialMouseX: null,
|
|
||||||
scrollLeft: 0,
|
|
||||||
gridLeft: 0,
|
gridLeft: 0,
|
||||||
|
width: 0,
|
||||||
|
latestX: 0,
|
||||||
|
increment: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createStores = () => {
|
export const createStores = () => {
|
||||||
|
@ -23,14 +24,24 @@ export const createStores = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const deriveStores = context => {
|
export const deriveStores = context => {
|
||||||
const { reorder, columns, visibleColumns, scroll, bounds, stickyColumn, ui } =
|
const {
|
||||||
context
|
reorder,
|
||||||
|
columns,
|
||||||
|
visibleColumns,
|
||||||
|
scroll,
|
||||||
|
bounds,
|
||||||
|
stickyColumn,
|
||||||
|
ui,
|
||||||
|
maxScrollLeft,
|
||||||
|
} = context
|
||||||
|
|
||||||
|
let autoScrollInterval
|
||||||
|
let isAutoScrolling
|
||||||
|
|
||||||
// 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) => {
|
||||||
const $visibleColumns = get(visibleColumns)
|
const $visibleColumns = get(visibleColumns)
|
||||||
const $bounds = get(bounds)
|
const $bounds = get(bounds)
|
||||||
const $scroll = get(scroll)
|
|
||||||
const $stickyColumn = get(stickyColumn)
|
const $stickyColumn = get(stickyColumn)
|
||||||
ui.actions.blur()
|
ui.actions.blur()
|
||||||
|
|
||||||
|
@ -51,9 +62,8 @@ export const deriveStores = context => {
|
||||||
sourceColumn: column,
|
sourceColumn: column,
|
||||||
targetColumn: null,
|
targetColumn: null,
|
||||||
breakpoints,
|
breakpoints,
|
||||||
initialMouseX: e.clientX,
|
|
||||||
scrollLeft: $scroll.left,
|
|
||||||
gridLeft: $bounds.left,
|
gridLeft: $bounds.left,
|
||||||
|
width: $bounds.width,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add listeners to handle mouse movement
|
// Add listeners to handle mouse movement
|
||||||
|
@ -66,12 +76,44 @@ export const deriveStores = context => {
|
||||||
|
|
||||||
// Callback when moving the mouse when reordering columns
|
// Callback when moving the mouse when reordering columns
|
||||||
const onReorderMouseMove = e => {
|
const onReorderMouseMove = e => {
|
||||||
|
// Immediately handle the current position
|
||||||
|
const x = e.clientX
|
||||||
|
reorder.update(state => ({
|
||||||
|
...state,
|
||||||
|
latestX: x,
|
||||||
|
}))
|
||||||
|
considerReorderPosition()
|
||||||
|
|
||||||
|
// Check if we need to start auto-scrolling
|
||||||
const $reorder = get(reorder)
|
const $reorder = get(reorder)
|
||||||
|
const proximityCutoff = 140
|
||||||
|
const speedFactor = 8
|
||||||
|
const rightProximity = Math.max(0, $reorder.gridLeft + $reorder.width - x)
|
||||||
|
const leftProximity = Math.max(0, x - $reorder.gridLeft)
|
||||||
|
if (rightProximity < proximityCutoff) {
|
||||||
|
const weight = proximityCutoff - rightProximity
|
||||||
|
const increment = (weight / proximityCutoff) * speedFactor
|
||||||
|
reorder.update(state => ({ ...state, increment }))
|
||||||
|
startAutoScroll()
|
||||||
|
} else if (leftProximity < proximityCutoff) {
|
||||||
|
const weight = -1 * (proximityCutoff - leftProximity)
|
||||||
|
const increment = (weight / proximityCutoff) * speedFactor
|
||||||
|
reorder.update(state => ({ ...state, increment }))
|
||||||
|
startAutoScroll()
|
||||||
|
} else {
|
||||||
|
stopAutoScroll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual logic to consider the current position and determine the new order
|
||||||
|
const considerReorderPosition = () => {
|
||||||
|
const $reorder = get(reorder)
|
||||||
|
const $scroll = get(scroll)
|
||||||
|
|
||||||
// Compute the closest breakpoint to the current position
|
// Compute the closest breakpoint to the current position
|
||||||
let targetColumn
|
let targetColumn
|
||||||
let minDistance = Number.MAX_SAFE_INTEGER
|
let minDistance = Number.MAX_SAFE_INTEGER
|
||||||
const mouseX = e.clientX - $reorder.gridLeft + $reorder.scrollLeft
|
const mouseX = $reorder.latestX - $reorder.gridLeft + $scroll.left
|
||||||
$reorder.breakpoints.forEach(point => {
|
$reorder.breakpoints.forEach(point => {
|
||||||
const distance = Math.abs(point.x - mouseX)
|
const distance = Math.abs(point.x - mouseX)
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
|
@ -79,7 +121,6 @@ export const deriveStores = context => {
|
||||||
targetColumn = point.column
|
targetColumn = point.column
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (targetColumn !== $reorder.targetColumn) {
|
if (targetColumn !== $reorder.targetColumn) {
|
||||||
reorder.update(state => ({
|
reorder.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
|
@ -88,8 +129,35 @@ export const deriveStores = context => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commences auto-scrolling in a certain direction, triggered when the mouse
|
||||||
|
// approaches the edges of the grid
|
||||||
|
const startAutoScroll = () => {
|
||||||
|
if (isAutoScrolling) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isAutoScrolling = true
|
||||||
|
autoScrollInterval = setInterval(() => {
|
||||||
|
const $maxLeft = get(maxScrollLeft)
|
||||||
|
const { increment } = get(reorder)
|
||||||
|
scroll.update(state => ({
|
||||||
|
...state,
|
||||||
|
left: Math.max(0, Math.min($maxLeft, state.left + increment)),
|
||||||
|
}))
|
||||||
|
considerReorderPosition()
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops auto scrolling
|
||||||
|
const stopAutoScroll = () => {
|
||||||
|
isAutoScrolling = false
|
||||||
|
clearInterval(autoScrollInterval)
|
||||||
|
}
|
||||||
|
|
||||||
// Callback when stopping reordering columns
|
// Callback when stopping reordering columns
|
||||||
const stopReordering = async () => {
|
const stopReordering = async () => {
|
||||||
|
// Ensure auto-scrolling is stopped
|
||||||
|
stopAutoScroll()
|
||||||
|
|
||||||
// Swap position of columns
|
// Swap position of columns
|
||||||
let { sourceColumn, targetColumn } = get(reorder)
|
let { sourceColumn, targetColumn } = get(reorder)
|
||||||
moveColumn(sourceColumn, targetColumn)
|
moveColumn(sourceColumn, targetColumn)
|
||||||
|
|
|
@ -25,14 +25,33 @@ export const createStores = () => {
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Toggles whether a certain row ID is selected or not
|
||||||
|
const toggleSelectedRow = id => {
|
||||||
|
selectedRows.update(state => {
|
||||||
|
let newState = {
|
||||||
|
...state,
|
||||||
|
[id]: !state[id],
|
||||||
|
}
|
||||||
|
if (!newState[id]) {
|
||||||
|
delete newState[id]
|
||||||
|
}
|
||||||
|
return newState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
focusedCellId,
|
focusedCellId,
|
||||||
focusedCellAPI,
|
focusedCellAPI,
|
||||||
focusedRowId,
|
focusedRowId,
|
||||||
previousFocusedRowId,
|
previousFocusedRowId,
|
||||||
selectedRows,
|
|
||||||
hoveredRowId,
|
hoveredRowId,
|
||||||
rowHeight,
|
rowHeight,
|
||||||
|
selectedRows: {
|
||||||
|
...selectedRows,
|
||||||
|
actions: {
|
||||||
|
toggleRow: toggleSelectedRow,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue