Last active
May 10, 2021 21:29
-
-
Save mationai/2b39d046ea1efca393623fc8c0af5687 to your computer and use it in GitHub Desktop.
My edited version of ExtendedTable (for https://github.com/dritter/extended-table/issues/10)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import { onMount } from 'svelte' | |
import { deepValue } from '@jsier/deep-value' | |
import stickybits from 'stickybits/dist/stickybits.es' | |
import { sortByDefinition, sortByColumn } from '../../node_modules/extended-table/src/sortBy' | |
import { getCellClasses, getRowClasses, getHeaderClasses } from './tableClassNames' | |
const defaultRowClickHandler = (_) => true | |
export let data = [] | |
export let columns = [] | |
export let config = { | |
multisort: false, | |
} | |
export let onRowClick = defaultRowClickHandler | |
export let style = '' | |
export let iconAsc = '↑' // col not auto-expanded unless icon is text based | |
export let iconDesc = '↓' | |
export let initialSortBy = null // PropertyPath | |
export let initialSortDirection = 'asc' | |
export let showSortIndicatorsOnInitialSort = true | |
export let collapsedPlaceholder = '...' | |
export let stickyHeaders = true | |
export let stickyOffset = 0 | |
export let expandAll = false | |
export let autoCollapse = false | |
export let sortingFunction = null | |
let windowWidth | |
let table | |
if (!sortingFunction) { | |
sortingFunction = sortByColumn | |
} | |
const clearCaches = () => { | |
columns = columns | |
data = data | |
} | |
const onCellClick = (colCfg, d, iCol) => colCfg.clickHandler?.(d, iCol) | |
onMount(() => { | |
const heads = table.querySelectorAll('thead th') | |
if (stickyHeaders) { | |
stickybits(heads, {stickyBitStickyOffset: stickyOffset}) | |
} | |
if (autoCollapse) { | |
const tableRect = table.getBoundingClientRect() | |
const viewportWidth = windowWidth - tableRect.left | |
let cumHeadWidths = 0 | |
for (let i = 0; i < heads.length; i++) { | |
const rect = heads[i].getBoundingClientRect() | |
if (cumHeadWidths + rect.width > viewportWidth) { | |
if (expandAll) { | |
columns | |
.filter((column, index) => index >= (i - 1)) | |
.map((column) => column.hidden = true) | |
columns[i].hidden = false | |
columns[i].collapsed = true | |
} else { | |
columns.filter((column, index) => index >= i) | |
.map((column) => column.collapsed = true) | |
} | |
clearCaches() | |
break | |
} | |
cumHeadWidths += rect.width | |
} | |
} | |
}) | |
if (initialSortBy) { | |
if (showSortIndicatorsOnInitialSort) { | |
const initialSortColumn = columns.find((c) => c.propertyPath === initialSortBy) | |
initialSortColumn.propertyPath = initialSortBy | |
initialSortColumn.direction = initialSortDirection | |
} | |
const def = {} | |
def[initialSortDirection] = (u) => { | |
return deepValue(u, initialSortBy) | |
} | |
sortByDefinition(data, [def]) | |
} | |
const expandColumn = (column) => { | |
if (expandAll) { | |
columns.map((column) => { | |
column.collapsed = false | |
column.hidden = false | |
}) | |
} else { | |
column.collapsed = false | |
} | |
clearCaches() | |
} | |
let slots = new Set($$props.$$slots ? Object.getOwnPropertyNames($$props.$$slots) : []) | |
</script> | |
<style> | |
.mouse-pointer:hover { | |
cursor: pointer; | |
} | |
.overflow-container { | |
max-width: 100vw; | |
max-height: 100vh; /* doesn't work (ht is set on div wrapping the Comp) */ | |
position: relative; | |
} | |
tbody tr:hover { | |
background-color: rgba(0, 0, 0, 0.1); | |
} | |
table td { | |
margin: 0; | |
padding: .5rem .625rem .625rem; | |
} | |
th { | |
background-color: rgb(255, 255, 255); | |
border-bottom: 2px solid rgb(51, 51, 51); | |
font-size: 110%; | |
font-weight: 700; | |
} | |
tbody .row-even { | |
background: rgba(153, 202, 255, 0.15); | |
border-bottom: 0; | |
} | |
tbody .col-even { | |
background: rgba(153, 202, 255, 0.15); | |
} | |
table { | |
border-spacing: 0; | |
display: block; | |
overflow-y: scroll; | |
} | |
.hidden { | |
display: none; | |
} | |
</style> | |
<svelte:window bind:innerWidth={windowWidth} /> | |
<div class="overflow-container"> | |
<table bind:this={table} class="et" {style}> | |
<thead> | |
<tr class='header'> | |
{#each config.columns as cfg, iCol} | |
<th on:click={() => sortingFunction(cfg, columns, data, config.multisort, clearCaches)} | |
class="{getHeaderClasses(iCol, cfg)}" | |
class:hidden={cfg.hidden} | |
> | |
{#if cfg.collapsed} | |
<div on:click|stopPropagation={expandColumn(cfg)}> | |
{@html collapsedPlaceholder} | |
</div> | |
{:else} | |
{@html cfg.title} | |
{#if cfg.direction === 'asc'} | |
{iconAsc} | |
{:else if cfg.direction === 'desc'} | |
{iconDesc} | |
{/if} | |
{/if} | |
</th> | |
{/each} | |
</tr> | |
<slot name='headerRow2'></slot> | |
</thead> | |
<tbody> | |
{#each data as d, iRow} | |
<tr on:click={() => onRowClick(d, iRow)} | |
class='{getRowClasses(d, iRow, config.rows)}' | |
class:mouse-pointer={onRowClick !== defaultRowClickHandler} | |
> | |
{#each config.columns as cfg, iCol} | |
<td on:click={() => onCellClick(cfg, d, iCol)} | |
class="{getCellClasses(d, iCol, iRow, cfg)}" | |
class:hidden={cfg.hidden} | |
> | |
{#if cfg.collapsed} | |
<div class="mouse-pointer" on:click|stopPropagation={expandColumn(cfg)}> | |
{@html collapsedPlaceholder} | |
</div> | |
{:else if data && slots.has('column-0') && iCol===0} | |
<slot name="column-0" data={d} iRow={iRow} iCol={iCol}/> | |
{:else if data && slots.has('column-2nd-last') && iCol===config.columns.length-2} | |
<slot name="column-2nd-last" data={d} iRow={iRow} iCol={iCol}/> | |
{:else if data && slots.has('column-last') && iCol===config.columns.length-1} | |
<slot name="column-last" data={d} iRow={iRow} iCol={iCol}/> | |
{:else if cfg.value} | |
{cfg.value(d, iRow, iCol)} | |
{:else if cfg.propertyPath} | |
{deepValue(d, cfg.propertyPath)} | |
{/if} | |
</td> | |
{/each} | |
</tr> | |
<slot name="extraRow" rowData={d} {iRow}></slot> | |
{/each} | |
</tbody> | |
</table> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { deepValue } from '@jsier/deep-value' | |
const slugEx = new RegExp(/[^a-z0-9\-]/ig) | |
const sluggify = (input='') => (''+input).replace(slugEx, '_') | |
const getOddEvenClass = (index, prefix) => { | |
return index % 2 === 0 ? `${prefix}-even` : `${prefix}-odd` | |
} | |
export const getHeaderClasses = (iCol, cfg) => { | |
const classes = [] | |
if (typeof cfg.propertyPath === 'string') { | |
classes.push('col-head-' + sluggify(cfg.propertyPath)) | |
} | |
if (typeof cfg.headerClassName === 'string') { | |
classes.push(cfg.headerClassName) | |
} | |
if (typeof cfg.headerClassName?.value === 'function') { | |
classes.push(cfg.headerClassName.value(cfg, iCol)) | |
} | |
if (cfg.sortable) { | |
classes.push('mouse-pointer') | |
} | |
return classes.join(' ') | |
} | |
export const getCellClasses = (data, iCol, iRow, cfg) => { | |
const classes = [] | |
if (typeof cfg.propertyPath === 'string') { | |
classes.push(`col-${sluggify(cfg.propertyPath)}`) | |
} | |
if (typeof cfg.className === 'string') { | |
classes.push(cfg.className) | |
} | |
if (typeof cfg.className?.value === 'function') { | |
classes.push(cfg.className.value(data, iCol, iRow)) | |
} | |
if (typeof cfg.className?.propertyPath === 'string') { | |
classes.push(sluggify(deepValue(data, cfg.className.propertyPath))) | |
} | |
classes.push(getOddEvenClass(iCol + 1, 'col')) | |
return classes.join(' ') | |
} | |
export const getRowClasses = (data, iRow, rowsCfg) => { | |
const classes = [] | |
rowsCfg.forEach((cfg) => { | |
if (typeof cfg.className === 'string') { | |
classes.push(cfg.className) | |
} | |
if (typeof cfg.className?.value === 'function') { | |
classes.push(cfg.className.value(data, iRow)) | |
} | |
if (typeof cfg.className?.propertyPath === 'string') { | |
classes.push(sluggify(deepValue(data, cfg.className.propertyPath))) | |
} | |
}) | |
classes.push(getOddEvenClass(iRow + 1, 'row')) | |
return classes.join(' ') | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
const columns = [ | |
{ propertyPath: 'acct', title: 'Acct', sortable: true }, | |
...otherCols, | |
{ title: '...' }, | |
{ title: 'Edit' }, | |
] | |
const config = { | |
columns, | |
rows: [{ | |
className: { | |
value: (d) => css.redGreen(d, 'pctPL', -.2, .2), | |
}, | |
}], | |
} | |
</script> | |
<div> | |
<ExtTable data={rows} {config} style='height:{tableHt};' {onRowClick}> | |
<div slot='column-2nd-last' let:data={d} let:iRow={iRow}> | |
<IconToggler on:click={() => toggleView(d, iRow)} dir={viewStates[iRow]}/> | |
</div> | |
<div slot='column-last' let:data={d} let:iRow={iRow}> | |
<input type=checkbox on:change={(evt) => setChecked(evt, iRow)}/> | |
</div> | |
<tr slot='extraRow' let:rowData={rowData} let:iRow={iRow}> | |
{#if rowData.transactions && viewStates[iRow]==='up'} | |
<td colspan={columns.length}> | |
<Transactions data={rowData}/> | |
</td> | |
{/if} | |
</tr> | |
</ExtTable> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment