Add drag and drop column reordering
This commit is contained in:
parent
8da1e507b1
commit
35dcd51322
|
@ -8,6 +8,7 @@
|
||||||
import MultiSelectCell from "./MultiSelectCell.svelte"
|
import MultiSelectCell from "./MultiSelectCell.svelte"
|
||||||
import NumberCell from "./NumberCell.svelte"
|
import NumberCell from "./NumberCell.svelte"
|
||||||
import RelationshipCell from "./RelationshipCell.svelte"
|
import RelationshipCell from "./RelationshipCell.svelte"
|
||||||
|
import { getColor } from "./utils.js"
|
||||||
|
|
||||||
export let table
|
export let table
|
||||||
export let filter
|
export let filter
|
||||||
|
@ -20,8 +21,9 @@
|
||||||
const limit = 100
|
const limit = 100
|
||||||
const defaultWidth = 160
|
const defaultWidth = 160
|
||||||
const minWidth = 100
|
const minWidth = 100
|
||||||
|
const rand = Math.random()
|
||||||
|
|
||||||
let widths
|
let fieldConfigs = []
|
||||||
let hoveredRow
|
let hoveredRow
|
||||||
let selectedCell
|
let selectedCell
|
||||||
let selectedRows = {}
|
let selectedRows = {}
|
||||||
|
@ -29,6 +31,22 @@
|
||||||
let changeCache = {}
|
let changeCache = {}
|
||||||
let newRows = []
|
let newRows = []
|
||||||
|
|
||||||
|
// State for resizing columns
|
||||||
|
let resizeInitialX
|
||||||
|
let resizeInitialWidth
|
||||||
|
let resizeFieldIndex
|
||||||
|
|
||||||
|
// State for reordering columns
|
||||||
|
let isReordering = false
|
||||||
|
let reorderFieldIndex
|
||||||
|
let reorderBreakpoints
|
||||||
|
let reorderPlaceholderX
|
||||||
|
let reorderPlaceholderInitialX
|
||||||
|
let reorderPlaceholderWidth
|
||||||
|
let reorderInitialX
|
||||||
|
let reorderPlaceholderHeight
|
||||||
|
let reorderCandidateFieldIdx
|
||||||
|
|
||||||
$: query = LuceneUtils.buildLuceneQuery(filter)
|
$: query = LuceneUtils.buildLuceneQuery(filter)
|
||||||
$: fetch = createFetch(table)
|
$: fetch = createFetch(table)
|
||||||
$: fetch.update({
|
$: fetch.update({
|
||||||
|
@ -37,12 +55,8 @@
|
||||||
query,
|
query,
|
||||||
limit,
|
limit,
|
||||||
})
|
})
|
||||||
$: schema = $fetch.schema
|
$: updateFieldConfig($fetch)
|
||||||
$: primaryDisplay = $fetch.definition?.primaryDisplay
|
$: gridStyles = getGridStyles(fieldConfigs)
|
||||||
$: fields = getFields(schema, primaryDisplay)
|
|
||||||
$: fieldCount = fields.length
|
|
||||||
$: fieldCount, initWidths()
|
|
||||||
$: gridStyles = getGridStyles(widths)
|
|
||||||
$: rowCount = $fetch.rows?.length || 0
|
$: rowCount = $fetch.rows?.length || 0
|
||||||
$: selectedRowCount = Object.values(selectedRows).filter(x => !!x).length
|
$: selectedRowCount = Object.values(selectedRows).filter(x => !!x).length
|
||||||
$: rows = getSortedRows($fetch.rows, newRows)
|
$: rows = getSortedRows($fetch.rows, newRows)
|
||||||
|
@ -61,19 +75,25 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFields = (schema, primaryDisplay) => {
|
const updateFieldConfig = ({ schema, definition }) => {
|
||||||
let fields = Object.keys(schema || {})
|
// Generate first time config if required
|
||||||
if (primaryDisplay) {
|
if (!fieldConfigs.length && schema) {
|
||||||
fields = [primaryDisplay, ...fields.filter(x => x !== primaryDisplay)]
|
let fields = Object.keys(schema || {})
|
||||||
|
const primaryDisplay = definition?.primaryDisplay
|
||||||
|
if (primaryDisplay) {
|
||||||
|
fields = [primaryDisplay, ...fields.filter(x => x !== primaryDisplay)]
|
||||||
|
}
|
||||||
|
fieldConfigs = fields.map(field => ({
|
||||||
|
name: field,
|
||||||
|
width: defaultWidth,
|
||||||
|
schema: schema[field],
|
||||||
|
primaryDisplay: field === primaryDisplay,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
return fields
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initWidths = () => {
|
const getGridStyles = fieldConfig => {
|
||||||
widths = fields.map(() => defaultWidth)
|
const widths = fieldConfig?.map(x => x.width)
|
||||||
}
|
|
||||||
|
|
||||||
const getGridStyles = widths => {
|
|
||||||
if (!widths?.length) {
|
if (!widths?.length) {
|
||||||
return "--grid: 1fr;"
|
return "--grid: 1fr;"
|
||||||
}
|
}
|
||||||
|
@ -88,7 +108,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCellForField = field => {
|
const getCellForField = field => {
|
||||||
const type = schema?.[field]?.type
|
const type = field.schema.type
|
||||||
if (type === "options") {
|
if (type === "options") {
|
||||||
return OptionsCell
|
return OptionsCell
|
||||||
} else if (type === "datetime") {
|
} else if (type === "datetime") {
|
||||||
|
@ -104,7 +124,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const getIconForField = field => {
|
const getIconForField = field => {
|
||||||
const type = schema?.[field]?.type
|
const type = field.schema.type
|
||||||
if (type === "options") {
|
if (type === "options") {
|
||||||
return "ChevronDown"
|
return "ChevronDown"
|
||||||
} else if (type === "datetime") {
|
} else if (type === "datetime") {
|
||||||
|
@ -133,10 +153,10 @@
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (row[field] === value) {
|
if (row[field.name] === value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
changeCache[rowId] = { [field]: value }
|
changeCache[rowId] = { [field.name]: value }
|
||||||
await API.saveRow({
|
await API.saveRow({
|
||||||
...row,
|
...row,
|
||||||
...changeCache[rowId],
|
...changeCache[rowId],
|
||||||
|
@ -164,11 +184,6 @@
|
||||||
rows: rowsToDelete,
|
rows: rowsToDelete,
|
||||||
})
|
})
|
||||||
await fetch.refresh()
|
await fetch.refresh()
|
||||||
// notificationStore.actions.success(
|
|
||||||
// `${selectedRowCount} row${
|
|
||||||
// selectedRowCount === 1 ? "" : "s"
|
|
||||||
// } deleted successfully`
|
|
||||||
// )
|
|
||||||
|
|
||||||
// Refresh state
|
// Refresh state
|
||||||
selectedCell = null
|
selectedCell = null
|
||||||
|
@ -188,7 +203,7 @@
|
||||||
|
|
||||||
const addRow = async field => {
|
const addRow = async field => {
|
||||||
const res = await API.saveRow({ tableId: table.tableId })
|
const res = await API.saveRow({ tableId: table.tableId })
|
||||||
selectedCell = `${res._id}-${field}`
|
selectedCell = `${res._id}-${field.name}`
|
||||||
newRows.push(res._id)
|
newRows.push(res._id)
|
||||||
await fetch.refresh()
|
await fetch.refresh()
|
||||||
}
|
}
|
||||||
|
@ -203,31 +218,101 @@
|
||||||
return sortedRows
|
return sortedRows
|
||||||
}
|
}
|
||||||
|
|
||||||
let resizeInitialX
|
const startReordering = (fieldIdx, e) => {
|
||||||
let resizeInitialWidth
|
isReordering = true
|
||||||
let resizeFieldIndex
|
reorderFieldIndex = fieldIdx
|
||||||
|
|
||||||
|
let breakpoints = []
|
||||||
|
fieldConfigs.forEach((config, idx) => {
|
||||||
|
const header = document.getElementById(`sheet-${rand}-header-${idx}`)
|
||||||
|
const bounds = header.getBoundingClientRect()
|
||||||
|
breakpoints.push(bounds.x)
|
||||||
|
if (idx === fieldConfigs.length - 1) {
|
||||||
|
breakpoints.push(bounds.x + bounds.width)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reorderBreakpoints = breakpoints
|
||||||
|
const self = document.getElementById(`sheet-${rand}-header-${fieldIdx}`)
|
||||||
|
const selfBounds = self.getBoundingClientRect()
|
||||||
|
const body = document.getElementById(`sheet-${rand}-body`)
|
||||||
|
const bodyBounds = body.getBoundingClientRect()
|
||||||
|
reorderPlaceholderInitialX = selfBounds.x - bodyBounds.x
|
||||||
|
reorderPlaceholderX = reorderPlaceholderInitialX
|
||||||
|
reorderPlaceholderWidth = selfBounds.width
|
||||||
|
reorderInitialX = e.clientX
|
||||||
|
reorderPlaceholderHeight = (rows.length + 2) * 32
|
||||||
|
onReorderMove(e)
|
||||||
|
document.addEventListener("mousemove", onReorderMove)
|
||||||
|
document.addEventListener("mouseup", stopReordering)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onReorderMove = e => {
|
||||||
|
if (!isReordering) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reorderPlaceholderX =
|
||||||
|
e.clientX - reorderInitialX + reorderPlaceholderInitialX
|
||||||
|
reorderPlaceholderX = Math.max(0, reorderPlaceholderX)
|
||||||
|
let candidateFieldIdx
|
||||||
|
let minDistance = Number.MAX_SAFE_INTEGER
|
||||||
|
reorderBreakpoints.forEach((point, idx) => {
|
||||||
|
const distance = Math.abs(point - e.clientX)
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance
|
||||||
|
candidateFieldIdx = idx
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reorderCandidateFieldIdx = candidateFieldIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopReordering = () => {
|
||||||
|
const newConfigs = fieldConfigs.slice()
|
||||||
|
const removed = newConfigs.splice(reorderFieldIndex, 1)
|
||||||
|
if (--reorderCandidateFieldIdx < reorderFieldIndex) {
|
||||||
|
reorderCandidateFieldIdx++
|
||||||
|
}
|
||||||
|
newConfigs.splice(reorderCandidateFieldIdx, 0, removed[0])
|
||||||
|
fieldConfigs = newConfigs
|
||||||
|
|
||||||
|
isReordering = false
|
||||||
|
reorderFieldIndex = null
|
||||||
|
reorderBreakpoints = null
|
||||||
|
reorderPlaceholderX = null
|
||||||
|
reorderPlaceholderInitialX = null
|
||||||
|
reorderPlaceholderWidth = null
|
||||||
|
reorderInitialX = null
|
||||||
|
reorderPlaceholderHeight = null
|
||||||
|
reorderCandidateFieldIdx = null
|
||||||
|
|
||||||
|
document.removeEventListener("mousemove", onReorderMove)
|
||||||
|
document.removeEventListener("mouseup", stopReordering)
|
||||||
|
}
|
||||||
|
|
||||||
const startResizing = (fieldIdx, e) => {
|
const startResizing = (fieldIdx, e) => {
|
||||||
|
e.stopPropagation()
|
||||||
resizeInitialX = e.clientX
|
resizeInitialX = e.clientX
|
||||||
resizeInitialWidth = widths[fieldIdx]
|
resizeInitialWidth = fieldConfigs[fieldIdx].width
|
||||||
resizeFieldIndex = fieldIdx
|
resizeFieldIndex = fieldIdx
|
||||||
document.addEventListener("mousemove", onResize)
|
document.addEventListener("mousemove", onResizeMove)
|
||||||
document.addEventListener("mouseup", stopResizing)
|
document.addEventListener("mouseup", stopResizing)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onResize = e => {
|
const onResizeMove = e => {
|
||||||
const dx = e.clientX - resizeInitialX
|
const dx = e.clientX - resizeInitialX
|
||||||
widths[resizeFieldIndex] = Math.max(minWidth, resizeInitialWidth + dx)
|
fieldConfigs[resizeFieldIndex].width = Math.max(
|
||||||
|
minWidth,
|
||||||
|
resizeInitialWidth + dx
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopResizing = () => {
|
const stopResizing = () => {
|
||||||
document.removeEventListener("mousemove", onResize)
|
document.removeEventListener("mousemove", onResizeMove)
|
||||||
document.removeEventListener("mouseup", stopResizing)
|
document.removeEventListener("mouseup", stopResizing)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles}>
|
||||||
<div class="wrapper">
|
<div class="wrapper" style="--highlight-color:{getColor(0)}">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<ActionButton icon="Filter" size="S">Filter</ActionButton>
|
<ActionButton icon="Filter" size="S">Filter</ActionButton>
|
||||||
|
@ -251,6 +336,7 @@
|
||||||
on:scroll={handleScroll}
|
on:scroll={handleScroll}
|
||||||
style={gridStyles}
|
style={gridStyles}
|
||||||
on:click|self={() => (selectedCell = null)}
|
on:click|self={() => (selectedCell = null)}
|
||||||
|
id={`sheet-${rand}-body`}
|
||||||
>
|
>
|
||||||
<!-- Field headers -->
|
<!-- Field headers -->
|
||||||
<div class="header cell label" on:click={selectAll}>
|
<div class="header cell label" on:click={selectAll}>
|
||||||
|
@ -259,11 +345,15 @@
|
||||||
checked={rowCount && selectedRowCount === rowCount}
|
checked={rowCount && selectedRowCount === rowCount}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#each fields as field, fieldIdx}
|
{#each fieldConfigs as field, fieldIdx}
|
||||||
<div
|
<div
|
||||||
class="header cell"
|
class="header cell"
|
||||||
class:sticky={fieldIdx === 0}
|
class:sticky={fieldIdx === 0}
|
||||||
class:shadow={horizontallyScrolled}
|
class:shadow={horizontallyScrolled}
|
||||||
|
class:reordering={reorderFieldIndex === fieldIdx}
|
||||||
|
class:reorder-candidate={reorderCandidateFieldIdx === fieldIdx}
|
||||||
|
on:mousedown={e => startReordering(fieldIdx, e)}
|
||||||
|
id={`sheet-${rand}-header-${fieldIdx}`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
size="S"
|
size="S"
|
||||||
|
@ -271,13 +361,17 @@
|
||||||
color="var(--spectrum-global-color-gray-600)"
|
color="var(--spectrum-global-color-gray-600)"
|
||||||
/>
|
/>
|
||||||
<span>
|
<span>
|
||||||
{field}
|
{field.name}
|
||||||
</span>
|
</span>
|
||||||
<div class="slider" on:mousedown={e => startResizing(fieldIdx, e)} />
|
<div class="slider" on:mousedown={e => startResizing(fieldIdx, e)} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
<!-- Horizontal spacer -->
|
<!-- Horizontal spacer -->
|
||||||
<div />
|
<div
|
||||||
|
class="header cell spacer"
|
||||||
|
class:reorder-candidate={reorderCandidateFieldIdx ===
|
||||||
|
fieldConfigs.length}
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- All real rows -->
|
<!-- All real rows -->
|
||||||
{#each rows as row, rowIdx (row._id)}
|
{#each rows as row, rowIdx (row._id)}
|
||||||
|
@ -300,31 +394,39 @@
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#each fields as field, fieldIdx}
|
{#each fieldConfigs as field, fieldIdx}
|
||||||
{@const cellIdx = `${row._id}-${field}`}
|
{@const cellIdx = `${row._id}-${field.name}`}
|
||||||
<div
|
{#key cellIdx}
|
||||||
class="cell"
|
<div
|
||||||
class:row-selected={rowSelected}
|
class="cell"
|
||||||
class:sticky={field === primaryDisplay}
|
class:row-selected={rowSelected}
|
||||||
class:hovered={rowHovered}
|
class:sticky={fieldIdx === 0}
|
||||||
class:selected={selectedCell === cellIdx}
|
class:hovered={rowHovered}
|
||||||
class:shadow={horizontallyScrolled}
|
class:selected={selectedCell === cellIdx}
|
||||||
on:focus
|
class:shadow={horizontallyScrolled}
|
||||||
on:mouseover={() => (hoveredRow = row._id)}
|
class:reordering={reorderFieldIndex === fieldIdx}
|
||||||
on:click={() => (selectedCell = cellIdx)}
|
class:reorder-candidate={reorderCandidateFieldIdx === fieldIdx}
|
||||||
>
|
on:focus
|
||||||
<svelte:component
|
on:mouseover={() => (hoveredRow = row._id)}
|
||||||
this={getCellForField(field)}
|
on:click={() => (selectedCell = cellIdx)}
|
||||||
value={data[field]}
|
>
|
||||||
schema={schema[field]}
|
<svelte:component
|
||||||
selected={selectedCell === cellIdx}
|
this={getCellForField(field)}
|
||||||
onChange={val => handleChange(row._id, field, val)}
|
value={data[field.name]}
|
||||||
readonly={schema[field]?.autocolumn}
|
schema={field.schema}
|
||||||
/>
|
selected={selectedCell === cellIdx}
|
||||||
</div>
|
onChange={val => handleChange(row._id, field, val)}
|
||||||
|
readonly={field.schema.autocolumn}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/key}
|
||||||
{/each}
|
{/each}
|
||||||
<!-- Horizontal spacer -->
|
<!-- Horizontal spacer -->
|
||||||
<div />
|
<div
|
||||||
|
class="cell spacer"
|
||||||
|
class:reorder-candidate={reorderCandidateFieldIdx ===
|
||||||
|
fieldConfigs.length}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- New row placeholder -->
|
<!-- New row placeholder -->
|
||||||
|
@ -337,23 +439,37 @@
|
||||||
>
|
>
|
||||||
<Icon hoverable name="Add" size="S" />
|
<Icon hoverable name="Add" size="S" />
|
||||||
</div>
|
</div>
|
||||||
{#each fields as field, fieldIdx}
|
{#each fieldConfigs as field, fieldIdx}
|
||||||
<div
|
<div
|
||||||
class="cell new"
|
class="cell new"
|
||||||
class:sticky={field === primaryDisplay}
|
class:sticky={fieldIdx === 0}
|
||||||
class:shadow={horizontallyScrolled}
|
class:shadow={horizontallyScrolled}
|
||||||
class:hovered={hoveredRow === "new"}
|
class:hovered={hoveredRow === "new"}
|
||||||
|
class:reordering={reorderFieldIndex === fieldIdx}
|
||||||
|
class:reorder-candidate={reorderCandidateFieldIdx === fieldIdx}
|
||||||
on:click={() => addRow(field)}
|
on:click={() => addRow(field)}
|
||||||
on:focus
|
on:focus
|
||||||
on:mouseover={() => (hoveredRow = "new")}
|
on:mouseover={() => (hoveredRow = "new")}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
<!-- Horizontal spacer -->
|
<!-- Horizontal spacer -->
|
||||||
<div />
|
<div
|
||||||
|
class="cell spacer"
|
||||||
|
class:reorder-candidate={reorderCandidateFieldIdx ===
|
||||||
|
fieldConfigs.length}
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Vertical spacer -->
|
<!-- Vertical spacer -->
|
||||||
<div class="vertical-spacer" />
|
<div class="vertical-spacer" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Reorder placeholder -->
|
||||||
|
{#if isReordering}
|
||||||
|
<div
|
||||||
|
class="reorder-placeholder"
|
||||||
|
style="--x:{reorderPlaceholderX}px;--width:{reorderPlaceholderWidth}px;--height:{reorderPlaceholderHeight}px;"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -365,6 +481,7 @@
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
border: 1px solid var(--spectrum-global-color-gray-400);
|
border: 1px solid var(--spectrum-global-color-gray-400);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
/* Variables */
|
/* Variables */
|
||||||
--cell-background: var(--spectrum-global-color-gray-50);
|
--cell-background: var(--spectrum-global-color-gray-50);
|
||||||
|
@ -427,10 +544,14 @@
|
||||||
fill: var(--spectrum-global-color-red-600);
|
fill: var(--spectrum-global-color-red-600);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cells */
|
||||||
.cell {
|
.cell {
|
||||||
height: var(--cell-height);
|
height: var(--cell-height);
|
||||||
border-bottom: 1px solid var(--spectrum-global-color-gray-300);
|
border-style: solid;
|
||||||
border-right: 1px solid var(--spectrum-global-color-gray-300);
|
border-color: var(--spectrum-global-color-gray-300);
|
||||||
|
border-width: 0;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-width: 1px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
|
@ -440,6 +561,7 @@
|
||||||
gap: var(--cell-spacing);
|
gap: var(--cell-spacing);
|
||||||
background: var(--cell-background);
|
background: var(--cell-background);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
transition: border-color 130ms ease-out;
|
||||||
}
|
}
|
||||||
.cell.hovered {
|
.cell.hovered {
|
||||||
background: var(--cell-background-hover);
|
background: var(--cell-background-hover);
|
||||||
|
@ -454,21 +576,18 @@
|
||||||
.cell:hover {
|
.cell:hover {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.cell.sticky {
|
|
||||||
position: sticky;
|
|
||||||
left: 40px;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.cell.sticky.selected {
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
.cell.row-selected {
|
.cell.row-selected {
|
||||||
background-color: rgb(224, 242, 255);
|
background-color: rgb(224, 242, 255);
|
||||||
}
|
}
|
||||||
.cell.new:hover {
|
.cell.new:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.cell.spacer {
|
||||||
|
background: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header cells */
|
||||||
.header {
|
.header {
|
||||||
background: var(--spectrum-global-color-gray-200);
|
background: var(--spectrum-global-color-gray-200);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
@ -488,6 +607,36 @@
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sticky styles */
|
||||||
|
.sticky {
|
||||||
|
position: sticky;
|
||||||
|
left: 40px;
|
||||||
|
z-index: 2;
|
||||||
|
border-left-color: transparent;
|
||||||
|
}
|
||||||
|
.sticky.selected {
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
.sticky.shadow {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
.sticky.shadow:after {
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
left: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reordering styles */
|
||||||
|
.cell.reordering {
|
||||||
|
background: var(--spectrum-global-color-gray-200);
|
||||||
|
}
|
||||||
|
.cell.reorder-candidate {
|
||||||
|
border-left-color: var(--spectrum-global-color-blue-400);
|
||||||
|
}
|
||||||
|
|
||||||
/* Column resizing */
|
/* Column resizing */
|
||||||
.slider {
|
.slider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -514,15 +663,6 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sticky.shadow:after {
|
|
||||||
content: " ";
|
|
||||||
position: absolute;
|
|
||||||
width: 10px;
|
|
||||||
left: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: linear-gradient(to right, rgba(0, 0, 0, 0.08), transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
|
@ -542,4 +682,14 @@
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
.reorder-placeholder {
|
||||||
|
height: min(calc(100% - 36px), var(--height));
|
||||||
|
width: var(--width);
|
||||||
|
left: var(--x);
|
||||||
|
position: absolute;
|
||||||
|
top: 36px;
|
||||||
|
background: var(--spectrum-global-color-blue-400);
|
||||||
|
opacity: 0.2;
|
||||||
|
z-index: 7;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue