svelte-tably 1.0.0-next.19 → 1.0.0-next.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/column/column.svelte.js +5 -3
- package/dist/table/Table.svelte +192 -142
- package/dist/table/table.svelte.js +0 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {} from 'svelte';
|
|
2
2
|
import { TableState } from '../table/table.svelte.js';
|
|
3
|
-
import {
|
|
3
|
+
import {} from '../utility.svelte.js';
|
|
4
4
|
import { getDefaultHeader } from './Column.svelte';
|
|
5
5
|
export class ColumnState {
|
|
6
6
|
#props = {};
|
|
@@ -13,7 +13,7 @@ export class ColumnState {
|
|
|
13
13
|
header: typeof this.#props.header === 'string' ? getDefaultHeader(this.#props.header) : this.#props.header,
|
|
14
14
|
/** Title is the header-snippet, with header-ctx: `{ header: false }` */
|
|
15
15
|
title: (...args) => {
|
|
16
|
-
const getData = () => this.table.
|
|
16
|
+
const getData = () => this.table.dataState.current;
|
|
17
17
|
return this.snippets.header?.(...[args[0], () => ({
|
|
18
18
|
get header() { return false; },
|
|
19
19
|
get data() {
|
|
@@ -43,7 +43,9 @@ export class ColumnState {
|
|
|
43
43
|
resizeable: this.#props.resizeable ?? true,
|
|
44
44
|
style: this.#props.style,
|
|
45
45
|
class: this.#props.class,
|
|
46
|
-
onclick: this.#props.onclick
|
|
46
|
+
onclick: this.#props.onclick,
|
|
47
|
+
padRow: this.#props.pad === 'row' || this.#props.pad === 'both',
|
|
48
|
+
padHeader: this.#props.pad === 'header' || this.#props.pad === 'both'
|
|
47
49
|
});
|
|
48
50
|
toggleVisiblity() {
|
|
49
51
|
const index = this.table.positions.hidden.indexOf(this);
|
package/dist/table/Table.svelte
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
-->
|
|
10
10
|
|
|
11
11
|
<script module lang="ts">
|
|
12
|
-
|
|
13
12
|
</script>
|
|
14
13
|
|
|
15
14
|
<script lang="ts">
|
|
@@ -18,7 +17,13 @@
|
|
|
18
17
|
import { sineInOut } from 'svelte/easing'
|
|
19
18
|
import reorder, { type ItemState } from 'runic-reorder'
|
|
20
19
|
import { Virtualization } from './virtualization.svelte.js'
|
|
21
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
TableState,
|
|
22
|
+
type HeaderSelectCtx,
|
|
23
|
+
type RowCtx,
|
|
24
|
+
type RowSelectCtx,
|
|
25
|
+
type TableProps
|
|
26
|
+
} from './table.svelte.js'
|
|
22
27
|
import Panel from '../panel/Panel.svelte'
|
|
23
28
|
import Column from '../column/Column.svelte'
|
|
24
29
|
import { assignDescriptors, capitalize, fromProps, mounted, segmentize } from '../utility.svelte.js'
|
|
@@ -28,12 +33,13 @@
|
|
|
28
33
|
import { SizeTween } from '../size-tween.svelte.js'
|
|
29
34
|
import { on } from 'svelte/events'
|
|
30
35
|
import Row from '../row/Row.svelte'
|
|
31
|
-
|
|
32
36
|
|
|
33
37
|
type T = $$Generic<Record<PropertyKey, unknown>>
|
|
34
38
|
|
|
35
|
-
type ConstructorReturnType<T extends new (...args: any[]) => any> =
|
|
36
|
-
|
|
39
|
+
type ConstructorReturnType<T extends new (...args: any[]) => any> =
|
|
40
|
+
T extends new (...args: any[]) => infer K ? K : never
|
|
41
|
+
type ConstructorParams<T extends new (...args: any[]) => any> =
|
|
42
|
+
T extends new (...args: infer K) => any ? K : never
|
|
37
43
|
|
|
38
44
|
type ContentCtx<T extends Record<PropertyKey, unknown>> = {
|
|
39
45
|
Column: {
|
|
@@ -57,9 +63,9 @@
|
|
|
57
63
|
}: TableProps<T> & { content?: ContentSnippet } = $props()
|
|
58
64
|
|
|
59
65
|
const properties = fromProps(restProps, {
|
|
60
|
-
selected: [() => _selected, v => _selected = v],
|
|
61
|
-
panel: [() => _panel, v => _panel = v],
|
|
62
|
-
data: [() => _data, v => _data = v]
|
|
66
|
+
selected: [() => _selected, (v) => (_selected = v)],
|
|
67
|
+
panel: [() => _panel, (v) => (_panel = v)],
|
|
68
|
+
data: [() => _data, (v) => (_data = v)]
|
|
63
69
|
}) as TableProps<T>
|
|
64
70
|
|
|
65
71
|
const mount = mounted()
|
|
@@ -70,14 +76,15 @@
|
|
|
70
76
|
'headers' | 'statusbar' | 'rows' | 'virtualTop' | 'virtualBottom' | 'selects',
|
|
71
77
|
HTMLElement
|
|
72
78
|
>
|
|
73
|
-
|
|
79
|
+
|
|
74
80
|
const table = new TableState<T>(properties) as TableState<T>
|
|
75
|
-
|
|
81
|
+
|
|
76
82
|
const virtualization = new Virtualization(table)
|
|
77
|
-
|
|
83
|
+
|
|
78
84
|
const panelTween = new SizeTween(() => !!properties.panel)
|
|
79
85
|
|
|
80
86
|
let hoveredRow: T | null = $state(null)
|
|
87
|
+
let hoveredColumn: ColumnState | null = $state(null)
|
|
81
88
|
|
|
82
89
|
/** Order of columns */
|
|
83
90
|
const fixed = $derived(table.positions.fixed)
|
|
@@ -97,15 +104,16 @@
|
|
|
97
104
|
const style = $derived.by(() => {
|
|
98
105
|
if (!mount.isMounted) return ''
|
|
99
106
|
|
|
100
|
-
const context = table.row?.snippets.context ? table.row?.options.context.width : ''
|
|
107
|
+
const context = table.row?.snippets.context ? table.row?.options.context.width : ''
|
|
101
108
|
|
|
102
|
-
const templateColumns =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
const templateColumns =
|
|
110
|
+
columns
|
|
111
|
+
.map((column, i, arr) => {
|
|
112
|
+
const width = getWidth(column.id)
|
|
113
|
+
if (i === arr.length - 1) return `minmax(${width}px, 1fr)`
|
|
114
|
+
return `${width}px`
|
|
115
|
+
})
|
|
116
|
+
.join(' ') + context
|
|
109
117
|
|
|
110
118
|
const theadTempla3teColumns = `
|
|
111
119
|
#${table.id} > thead > tr,
|
|
@@ -134,11 +142,17 @@
|
|
|
134
142
|
})
|
|
135
143
|
.join('')
|
|
136
144
|
|
|
137
|
-
const columnStyling = columns
|
|
145
|
+
const columnStyling = columns
|
|
146
|
+
.map((column) =>
|
|
147
|
+
!column.options.style ?
|
|
148
|
+
''
|
|
149
|
+
: `
|
|
138
150
|
[data-area-class='${table.id}'] .column[data-column='${column.id}'] {
|
|
139
151
|
${column.options.style}
|
|
140
152
|
}
|
|
141
|
-
`
|
|
153
|
+
`
|
|
154
|
+
)
|
|
155
|
+
.join('')
|
|
142
156
|
|
|
143
157
|
return theadTempla3teColumns + tbodyTemplateColumns + stickyLeft + columnStyling
|
|
144
158
|
})
|
|
@@ -153,15 +167,19 @@
|
|
|
153
167
|
|
|
154
168
|
const observer = new MutationObserver(() => {
|
|
155
169
|
const width = parseFloat(node.style.width)
|
|
156
|
-
if(width === columnWidths[key]) return
|
|
170
|
+
if (width === columnWidths[key]) return
|
|
157
171
|
columnWidths[key] = width
|
|
158
|
-
if(!mouseup) {
|
|
172
|
+
if (!mouseup) {
|
|
159
173
|
mouseup = true
|
|
160
|
-
window.addEventListener(
|
|
161
|
-
|
|
162
|
-
e
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
window.addEventListener(
|
|
175
|
+
'click',
|
|
176
|
+
(e) => {
|
|
177
|
+
e.preventDefault()
|
|
178
|
+
e.stopPropagation()
|
|
179
|
+
mouseup = false
|
|
180
|
+
},
|
|
181
|
+
{ once: true, capture: true }
|
|
182
|
+
)
|
|
165
183
|
}
|
|
166
184
|
})
|
|
167
185
|
|
|
@@ -187,7 +205,6 @@
|
|
|
187
205
|
elements.statusbar.scrollLeft = target.scrollLeft
|
|
188
206
|
}
|
|
189
207
|
|
|
190
|
-
|
|
191
208
|
// * --- CSV --- *
|
|
192
209
|
let csv = $state(false) as false | { selected?: boolean }
|
|
193
210
|
let csvElement = $state() as undefined | HTMLTableElement
|
|
@@ -200,11 +217,11 @@
|
|
|
200
217
|
export async function toCSV(opts: CSVOptions = {}) {
|
|
201
218
|
csv = { selected: !!opts.selected }
|
|
202
219
|
let resolve: (value: HTMLTableElement) => void
|
|
203
|
-
const promise = new Promise<HTMLTableElement>(r => resolve = r)
|
|
220
|
+
const promise = new Promise<HTMLTableElement>((r) => (resolve = r))
|
|
204
221
|
|
|
205
222
|
const clean = $effect.root(() => {
|
|
206
223
|
$effect(() => {
|
|
207
|
-
if(csvElement) {
|
|
224
|
+
if (csvElement) {
|
|
208
225
|
resolve(csvElement)
|
|
209
226
|
}
|
|
210
227
|
})
|
|
@@ -213,86 +230,80 @@
|
|
|
213
230
|
let table = await promise
|
|
214
231
|
clean()
|
|
215
232
|
|
|
216
|
-
const separator = opts.semicolon ?
|
|
233
|
+
const separator = opts.semicolon ? ';' : ','
|
|
217
234
|
const rows = Array.from(table.rows)
|
|
218
235
|
const csvRows = []
|
|
219
236
|
|
|
220
237
|
for (const row of rows) {
|
|
221
238
|
const cells = Array.from(row.cells)
|
|
222
|
-
const csvCells = cells.map(cell => {
|
|
239
|
+
const csvCells = cells.map((cell) => {
|
|
223
240
|
let text = cell.textContent?.trim() || ''
|
|
224
241
|
|
|
225
242
|
// Escape double quotes and wrap in quotes if needed
|
|
226
|
-
if(text.includes('"')) {
|
|
243
|
+
if (text.includes('"')) {
|
|
227
244
|
text = text.replace(/"/g, '""')
|
|
228
245
|
}
|
|
229
|
-
if(text.includes(separator) || text.includes('"') || text.includes('\n')) {
|
|
246
|
+
if (text.includes(separator) || text.includes('"') || text.includes('\n')) {
|
|
230
247
|
text = `"${text}"`
|
|
231
248
|
}
|
|
232
|
-
|
|
249
|
+
|
|
233
250
|
return text
|
|
234
251
|
})
|
|
235
252
|
csvRows.push(csvCells.join(separator))
|
|
236
253
|
}
|
|
237
254
|
|
|
238
255
|
csv = false
|
|
239
|
-
return csvRows.join(
|
|
256
|
+
return csvRows.join('\n')
|
|
240
257
|
}
|
|
241
258
|
// * --- CSV --- *
|
|
242
259
|
|
|
243
|
-
|
|
244
260
|
let expandedRow = $state([]) as T[]
|
|
245
261
|
let expandTick = false
|
|
246
262
|
function toggleExpand(item: T, value?: boolean) {
|
|
247
|
-
if(expandTick) return
|
|
263
|
+
if (expandTick) return
|
|
248
264
|
expandTick = true
|
|
249
|
-
requestAnimationFrame(() => expandTick = false)
|
|
265
|
+
requestAnimationFrame(() => (expandTick = false))
|
|
250
266
|
|
|
251
267
|
let indexOf = expandedRow.indexOf(item)
|
|
252
|
-
if(value === undefined) {
|
|
268
|
+
if (value === undefined) {
|
|
253
269
|
value = indexOf === -1
|
|
254
270
|
}
|
|
255
|
-
if(!value) {
|
|
271
|
+
if (!value) {
|
|
256
272
|
expandedRow.splice(indexOf, 1)
|
|
257
273
|
return
|
|
258
274
|
}
|
|
259
|
-
if(table.expandable?.options.multiple === true) {
|
|
275
|
+
if (table.expandable?.options.multiple === true) {
|
|
260
276
|
expandedRow.push(item)
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
277
|
+
} else {
|
|
263
278
|
expandedRow[0] = item
|
|
264
279
|
}
|
|
265
280
|
}
|
|
266
281
|
|
|
267
282
|
function addRowColumnEvents(
|
|
268
|
-
node: HTMLTableColElement,
|
|
283
|
+
node: HTMLTableColElement,
|
|
269
284
|
opts: ['header' | 'row' | 'statusbar', ColumnState, () => RowColumnCtx<T, any>]
|
|
270
285
|
) {
|
|
271
286
|
const [where, column, value] = opts
|
|
272
|
-
if(where !== 'row') return
|
|
273
|
-
if(column.options.onclick) {
|
|
274
|
-
$effect(() => on(node, 'click', e => column.options.onclick!(e, value())))
|
|
287
|
+
if (where !== 'row') return
|
|
288
|
+
if (column.options.onclick) {
|
|
289
|
+
$effect(() => on(node, 'click', (e) => column.options.onclick!(e, value())))
|
|
275
290
|
}
|
|
276
291
|
}
|
|
277
292
|
|
|
278
|
-
function addRowEvents(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
) {
|
|
282
|
-
if(table.row?.events.onclick) {
|
|
283
|
-
$effect(() => on(node, 'click', e => table.row?.events.onclick!(e, ctx)))
|
|
293
|
+
function addRowEvents(node: HTMLTableRowElement, ctx: RowCtx<T>) {
|
|
294
|
+
if (table.row?.events.onclick) {
|
|
295
|
+
$effect(() => on(node, 'click', (e) => table.row?.events.onclick!(e, ctx)))
|
|
284
296
|
}
|
|
285
|
-
if(table.row?.events.oncontextmenu) {
|
|
286
|
-
$effect(() => on(node, 'contextmenu', e => table.row?.events.oncontextmenu!(e, ctx)))
|
|
297
|
+
if (table.row?.events.oncontextmenu) {
|
|
298
|
+
$effect(() => on(node, 'contextmenu', (e) => table.row?.events.oncontextmenu!(e, ctx)))
|
|
287
299
|
}
|
|
288
300
|
}
|
|
289
|
-
|
|
290
301
|
</script>
|
|
291
302
|
|
|
292
303
|
<!---------------------------------------------------->
|
|
293
304
|
|
|
294
305
|
{#if csv !== false}
|
|
295
|
-
{@const renderedColumns = columns.filter(v => v.id !== '__fixed')}
|
|
306
|
+
{@const renderedColumns = columns.filter((v) => v.id !== '__fixed')}
|
|
296
307
|
<table bind:this={csvElement} hidden>
|
|
297
308
|
<thead>
|
|
298
309
|
<tr>
|
|
@@ -311,10 +322,15 @@
|
|
|
311
322
|
{@render column.snippets.row(row, {
|
|
312
323
|
index: i,
|
|
313
324
|
value: column.options.value?.(row),
|
|
314
|
-
|
|
315
|
-
|
|
325
|
+
columnHovered: false,
|
|
326
|
+
rowHovered: false,
|
|
327
|
+
itemState: {
|
|
328
|
+
index: i,
|
|
329
|
+
dragging: false,
|
|
330
|
+
positioning: false
|
|
331
|
+
} as ItemState<any>,
|
|
316
332
|
selected: false,
|
|
317
|
-
expanded: false
|
|
333
|
+
expanded: false,
|
|
318
334
|
})}
|
|
319
335
|
{:else}
|
|
320
336
|
{column.options.value?.(row)}
|
|
@@ -348,7 +364,7 @@
|
|
|
348
364
|
{/snippet}
|
|
349
365
|
|
|
350
366
|
{#snippet dragSnippet()}
|
|
351
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" style=
|
|
367
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" style="opacity: .3">
|
|
352
368
|
<path
|
|
353
369
|
fill="currentColor"
|
|
354
370
|
d="M5.5 5a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3m0 4.5a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3m1.5 3a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0M10.5 5a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3M12 8a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0m-1.5 6a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3"
|
|
@@ -374,9 +390,12 @@
|
|
|
374
390
|
class:fixed={true}
|
|
375
391
|
use:addRowColumnEvents={[where, column, () => args[1]]}
|
|
376
392
|
data-column={column.id}
|
|
393
|
+
class:pad={(isHeader && column.options.padHeader) || (!isHeader && column.options.padRow)}
|
|
377
394
|
class:header={isHeader}
|
|
378
395
|
class:sortable
|
|
379
396
|
use:conditional={[isHeader, (node) => table.dataState.sortAction(node, column.id)]}
|
|
397
|
+
onpointerenter={() => (hoveredColumn = column)}
|
|
398
|
+
onpointerleave={() => (hoveredColumn = null)}
|
|
380
399
|
>
|
|
381
400
|
{@render renderable(column)?.(args[0], args[1])}
|
|
382
401
|
{#if isHeader && table.dataState.sortby === column.id && sortable}
|
|
@@ -399,11 +418,14 @@
|
|
|
399
418
|
use:addRowColumnEvents={[where, column, () => args[1]]}
|
|
400
419
|
use:observeColumnWidth={isHeader}
|
|
401
420
|
data-column={column.id}
|
|
421
|
+
class:pad={(isHeader && column.options.padHeader) || (!isHeader && column.options.padRow)}
|
|
402
422
|
class:header={isHeader}
|
|
403
423
|
class:resizeable={isHeader && column.options.resizeable && table.options.resizeable}
|
|
404
424
|
class:border={i == sticky.length - 1}
|
|
405
425
|
class:sortable
|
|
406
426
|
use:conditional={[isHeader, (node) => table.dataState.sortAction(node, column.id)]}
|
|
427
|
+
onpointerenter={() => (hoveredColumn = column)}
|
|
428
|
+
onpointerleave={() => (hoveredColumn = null)}
|
|
407
429
|
>
|
|
408
430
|
{@render renderable(column)?.(args[0], args[1])}
|
|
409
431
|
{#if isHeader && table.dataState.sortby === column.id && sortable}
|
|
@@ -423,11 +445,14 @@
|
|
|
423
445
|
class={column.options.class ?? ''}
|
|
424
446
|
class:column={true}
|
|
425
447
|
data-column={column.id}
|
|
448
|
+
class:pad={(isHeader && column.options.padHeader) || (!isHeader && column.options.padRow)}
|
|
426
449
|
use:addRowColumnEvents={[where, column, () => args[1]]}
|
|
427
450
|
use:observeColumnWidth={isHeader}
|
|
428
451
|
class:resizeable={isHeader && column.options.resizeable && table.options.resizeable}
|
|
429
452
|
class:sortable
|
|
430
453
|
use:conditional={[isHeader, (node) => table.dataState.sortAction(node, column.id)]}
|
|
454
|
+
onpointerenter={() => (hoveredColumn = column)}
|
|
455
|
+
onpointerleave={() => (hoveredColumn = null)}
|
|
431
456
|
>
|
|
432
457
|
{@render renderable(column)?.(args[0], args[1])}
|
|
433
458
|
{#if isHeader && table.dataState.sortby === column.id && sortable}
|
|
@@ -451,7 +476,7 @@
|
|
|
451
476
|
get index() {
|
|
452
477
|
return index
|
|
453
478
|
},
|
|
454
|
-
get
|
|
479
|
+
get rowHovered() {
|
|
455
480
|
return hoveredRow === item
|
|
456
481
|
},
|
|
457
482
|
get selected() {
|
|
@@ -476,20 +501,19 @@
|
|
|
476
501
|
<tr
|
|
477
502
|
aria-rowindex={index + 1}
|
|
478
503
|
style:opacity={itemState?.positioning ? 0 : 1}
|
|
479
|
-
class=
|
|
504
|
+
class="row"
|
|
480
505
|
class:dragging={itemState?.dragging}
|
|
481
506
|
class:selected={table.selected?.includes(item)}
|
|
482
507
|
class:first={index === 0}
|
|
483
508
|
class:last={index === virtualization.area.length - 1}
|
|
484
|
-
{...
|
|
485
|
-
{...(itemState?.dragging ? { 'data-svelte-tably': table.id } : {})}
|
|
509
|
+
{...itemState?.dragging ? { 'data-svelte-tably': table.id } : {}}
|
|
486
510
|
onpointerenter={() => (hoveredRow = item)}
|
|
487
511
|
onpointerleave={() => (hoveredRow = null)}
|
|
488
512
|
use:addRowEvents={ctx}
|
|
489
513
|
onclick={(e) => {
|
|
490
514
|
if (table.expandable?.options.click === true) {
|
|
491
515
|
let target = e.target as HTMLElement
|
|
492
|
-
if(['INPUT', 'TEXTAREA', 'BUTTON', 'A'].includes(target.tagName)) {
|
|
516
|
+
if (['INPUT', 'TEXTAREA', 'BUTTON', 'A'].includes(target.tagName)) {
|
|
493
517
|
return
|
|
494
518
|
}
|
|
495
519
|
ctx.expanded = !ctx.expanded
|
|
@@ -501,11 +525,17 @@
|
|
|
501
525
|
(column) => {
|
|
502
526
|
return [
|
|
503
527
|
item,
|
|
504
|
-
assignDescriptors(
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
528
|
+
assignDescriptors(
|
|
529
|
+
{
|
|
530
|
+
get value() {
|
|
531
|
+
return column.options.value ? column.options.value(item) : undefined
|
|
532
|
+
},
|
|
533
|
+
get columnHovered() {
|
|
534
|
+
return hoveredColumn === column
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
ctx
|
|
538
|
+
)
|
|
509
539
|
]
|
|
510
540
|
},
|
|
511
541
|
'row'
|
|
@@ -513,9 +543,11 @@
|
|
|
513
543
|
{#if table.row?.snippets.context}
|
|
514
544
|
{#if table.row?.snippets.contextHeader || !table.row?.options.context.hover || hoveredRow === item}
|
|
515
545
|
<td
|
|
516
|
-
class=
|
|
546
|
+
class="context-col"
|
|
517
547
|
class:hover={!table.row?.snippets.contextHeader && table.row?.options.context.hover}
|
|
518
|
-
class:hidden={table.row?.options.context.hover &&
|
|
548
|
+
class:hidden={table.row?.options.context.hover &&
|
|
549
|
+
table.row?.snippets.contextHeader &&
|
|
550
|
+
hoveredRow !== item}
|
|
519
551
|
>
|
|
520
552
|
{@render table.row?.snippets.context?.(item, ctx)}
|
|
521
553
|
</td>
|
|
@@ -523,19 +555,15 @@
|
|
|
523
555
|
{/if}
|
|
524
556
|
</tr>
|
|
525
557
|
|
|
526
|
-
{@const expandableTween = new SizeTween(
|
|
527
|
-
|
|
528
|
-
|
|
558
|
+
{@const expandableTween = new SizeTween(() => table.expandable && expandedRow.includes(item), {
|
|
559
|
+
min: 1,
|
|
560
|
+
duration: table.expandable?.options.slide.duration,
|
|
561
|
+
easing: table.expandable?.options.slide.easing
|
|
562
|
+
})}
|
|
529
563
|
{#if expandableTween.current > 0}
|
|
530
|
-
<tr class=
|
|
531
|
-
<td
|
|
532
|
-
|
|
533
|
-
style='height: {expandableTween.current}px'
|
|
534
|
-
>
|
|
535
|
-
<div
|
|
536
|
-
bind:offsetHeight={expandableTween.size}
|
|
537
|
-
style='width: {tbody.width - 3}px'
|
|
538
|
-
>
|
|
564
|
+
<tr class="expandable" style="height: {expandableTween.current}px">
|
|
565
|
+
<td colspan={columns.length} style="height: {expandableTween.current}px">
|
|
566
|
+
<div bind:offsetHeight={expandableTween.size} style="width: {tbody.width - 3}px">
|
|
539
567
|
{@render table.expandable!.snippets.content?.(item, ctx)}
|
|
540
568
|
</div>
|
|
541
569
|
</td>
|
|
@@ -545,35 +573,39 @@
|
|
|
545
573
|
|
|
546
574
|
<table
|
|
547
575
|
id={table.id}
|
|
548
|
-
class=
|
|
549
|
-
style=
|
|
576
|
+
class="table svelte-tably"
|
|
577
|
+
style="--t: {virtualization.virtualTop}px; --b: {virtualization.virtualBottom}px;"
|
|
550
578
|
aria-rowcount={table.data.length}
|
|
551
579
|
>
|
|
552
|
-
{#if columns.some(v => v.snippets.header)}
|
|
553
|
-
<thead class=
|
|
554
|
-
<tr style=
|
|
580
|
+
{#if columns.some((v) => v.snippets.header)}
|
|
581
|
+
<thead class="headers" bind:this={elements.headers}>
|
|
582
|
+
<tr style="min-width: {tbody.width}px">
|
|
555
583
|
{@render columnsSnippet(
|
|
556
584
|
(column) => column.snippets.header,
|
|
557
|
-
() => [
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
585
|
+
() => [
|
|
586
|
+
{
|
|
587
|
+
get header() {
|
|
588
|
+
return true
|
|
589
|
+
},
|
|
590
|
+
get data() {
|
|
591
|
+
return table.data
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
],
|
|
561
595
|
'header'
|
|
562
596
|
)}
|
|
563
597
|
{#if table.row?.snippets.contextHeader}
|
|
564
|
-
<th
|
|
565
|
-
class='context-col'
|
|
566
|
-
>
|
|
598
|
+
<th class="context-col">
|
|
567
599
|
{@render table.row?.snippets.contextHeader()}
|
|
568
600
|
</th>
|
|
569
601
|
{/if}
|
|
570
602
|
</tr>
|
|
571
|
-
<tr style=
|
|
603
|
+
<tr style="width:400px;background:none;pointer-events:none;"></tr>
|
|
572
604
|
</thead>
|
|
573
605
|
{/if}
|
|
574
606
|
|
|
575
607
|
<tbody
|
|
576
|
-
class=
|
|
608
|
+
class="content"
|
|
577
609
|
use:reorderArea={{ axis: 'y', class: table.id }}
|
|
578
610
|
bind:this={virtualization.viewport.element}
|
|
579
611
|
onscrollcapture={onscroll}
|
|
@@ -599,28 +631,29 @@
|
|
|
599
631
|
{/if}
|
|
600
632
|
</tbody>
|
|
601
633
|
|
|
602
|
-
{#if columns.some(v => v.snippets.statusbar)}
|
|
603
|
-
<tfoot class=
|
|
634
|
+
{#if columns.some((v) => v.snippets.statusbar)}
|
|
635
|
+
<tfoot class="statusbar" bind:this={elements.statusbar}>
|
|
604
636
|
<tr>
|
|
605
637
|
{@render columnsSnippet(
|
|
606
638
|
(column) => column.snippets.statusbar,
|
|
607
|
-
() => [
|
|
608
|
-
|
|
609
|
-
|
|
639
|
+
() => [
|
|
640
|
+
{
|
|
641
|
+
get data() {
|
|
642
|
+
return table.data
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
],
|
|
610
646
|
'statusbar'
|
|
611
647
|
)}
|
|
612
648
|
</tr>
|
|
613
|
-
<tr style=
|
|
649
|
+
<tr style="width:400px;background:none;pointer-events:none;"></tr>
|
|
614
650
|
</tfoot>
|
|
615
651
|
{/if}
|
|
616
652
|
|
|
617
|
-
<caption
|
|
618
|
-
class='panel'
|
|
619
|
-
style='width: {panelTween.current}px;'
|
|
620
|
-
>
|
|
653
|
+
<caption class="panel" style="width: {panelTween.current}px;">
|
|
621
654
|
{#if properties.panel && properties.panel in table.panels}
|
|
622
655
|
<div
|
|
623
|
-
class=
|
|
656
|
+
class="panel-content"
|
|
624
657
|
bind:offsetWidth={panelTween.size}
|
|
625
658
|
in:fly={{ x: 100, easing: sineInOut, duration: 300 }}
|
|
626
659
|
out:fly={{ x: 100, duration: 200, easing: sineInOut }}
|
|
@@ -636,18 +669,25 @@
|
|
|
636
669
|
</div>
|
|
637
670
|
{/if}
|
|
638
671
|
</caption>
|
|
639
|
-
<caption
|
|
640
|
-
|
|
672
|
+
<caption
|
|
673
|
+
class="backdrop"
|
|
674
|
+
aria-hidden={properties.panel && table.panels[properties.panel]?.backdrop ? false : true}
|
|
675
|
+
>
|
|
676
|
+
<button
|
|
677
|
+
aria-label="Panel backdrop"
|
|
678
|
+
class="btn-backdrop"
|
|
679
|
+
tabindex="-1"
|
|
680
|
+
onclick={() => (properties.panel = undefined)}
|
|
641
681
|
></button>
|
|
642
682
|
</caption>
|
|
643
683
|
</table>
|
|
644
684
|
|
|
645
685
|
{#snippet headerSelected(ctx: HeaderSelectCtx<T>)}
|
|
646
|
-
<input type=
|
|
686
|
+
<input type="checkbox" indeterminate={ctx.indeterminate} bind:checked={ctx.isSelected} />
|
|
647
687
|
{/snippet}
|
|
648
688
|
|
|
649
689
|
{#snippet rowSelected(ctx: RowSelectCtx<T>)}
|
|
650
|
-
<input type=
|
|
690
|
+
<input type="checkbox" bind:checked={ctx.isSelected} tabindex="-1" />
|
|
651
691
|
{/snippet}
|
|
652
692
|
|
|
653
693
|
{#if table.options.select || table.options.reorderable || table.expandable}
|
|
@@ -661,20 +701,22 @@
|
|
|
661
701
|
} = typeof select === 'boolean' ? {} : select}
|
|
662
702
|
{#if show !== 'never' || reorderable || expandable?.options.chevron !== 'never'}
|
|
663
703
|
<Column
|
|
664
|
-
id=
|
|
704
|
+
id="__fixed"
|
|
665
705
|
{table}
|
|
666
706
|
fixed
|
|
667
|
-
width={Math.max(
|
|
668
|
-
|
|
669
|
-
+
|
|
670
|
-
|
|
707
|
+
width={Math.max(
|
|
708
|
+
48,
|
|
709
|
+
0 +
|
|
710
|
+
(select && show !== 'never' ? 34 : 0) +
|
|
711
|
+
(reorderable ? 34 : 0) +
|
|
712
|
+
(expandable && expandable?.options.chevron !== 'never' ? 34 : 0)
|
|
671
713
|
)}
|
|
672
714
|
resizeable={false}
|
|
673
715
|
>
|
|
674
716
|
{#snippet header()}
|
|
675
|
-
<div class=
|
|
717
|
+
<div class="__fixed">
|
|
676
718
|
{#if reorderable}
|
|
677
|
-
<span style=
|
|
719
|
+
<span style="width: 16px; display: flex; align-items: center;"></span>
|
|
678
720
|
{/if}
|
|
679
721
|
{#if select}
|
|
680
722
|
{@render headerSnippet({
|
|
@@ -702,15 +744,15 @@
|
|
|
702
744
|
</div>
|
|
703
745
|
{/snippet}
|
|
704
746
|
{#snippet row(item, row)}
|
|
705
|
-
<div class=
|
|
747
|
+
<div class="__fixed">
|
|
706
748
|
{#if reorderable && row.itemState}
|
|
707
|
-
<span style=
|
|
708
|
-
{#if (row.
|
|
749
|
+
<span style="width: 16px; display: flex; align-items: center;" use:row.itemState.handle>
|
|
750
|
+
{#if (row.rowHovered && !row.itemState.area.isTarget) || row.itemState.dragging}
|
|
709
751
|
{@render dragSnippet()}
|
|
710
752
|
{/if}
|
|
711
753
|
</span>
|
|
712
754
|
{/if}
|
|
713
|
-
{#if select && (row.selected || show === 'always' || (row.
|
|
755
|
+
{#if select && (row.selected || show === 'always' || (row.rowHovered && show === 'hover') || row.expanded)}
|
|
714
756
|
{@render rowSnippet({
|
|
715
757
|
get isSelected() {
|
|
716
758
|
return row.selected
|
|
@@ -730,8 +772,8 @@
|
|
|
730
772
|
})}
|
|
731
773
|
{/if}
|
|
732
774
|
{#if expandable && expandable?.options.chevron !== 'never'}
|
|
733
|
-
<button class=
|
|
734
|
-
{#if row.expanded || expandable.options.chevron === 'always' || (row.
|
|
775
|
+
<button class="expand-row" tabindex="-1" onclick={() => (row.expanded = !row.expanded)}>
|
|
776
|
+
{#if row.expanded || expandable.options.chevron === 'always' || (row.rowHovered && expandable.options.chevron === 'hover')}
|
|
735
777
|
{@render chevronSnippet(row.expanded ? 180 : 90)}
|
|
736
778
|
{/if}
|
|
737
779
|
</button>
|
|
@@ -746,13 +788,11 @@
|
|
|
746
788
|
{#each Object.keys(table.data[0] || {}) as key}
|
|
747
789
|
<Column
|
|
748
790
|
id={key}
|
|
749
|
-
value={r => r[key]}
|
|
791
|
+
value={(r) => r[key]}
|
|
750
792
|
header={capitalize(segmentize(key))}
|
|
751
|
-
sort={
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
: (a, b) => String(a).localeCompare(String(b))
|
|
755
|
-
}
|
|
793
|
+
sort={typeof table.data[0]?.[key] === 'number' ?
|
|
794
|
+
(a, b) => a - b
|
|
795
|
+
: (a, b) => String(a).localeCompare(String(b))}
|
|
756
796
|
/>
|
|
757
797
|
{/each}
|
|
758
798
|
{/if}
|
|
@@ -817,10 +857,10 @@
|
|
|
817
857
|
position: relative;
|
|
818
858
|
overflow: visible;
|
|
819
859
|
}
|
|
820
|
-
|
|
860
|
+
|
|
821
861
|
.expandable {
|
|
822
862
|
position: relative;
|
|
823
|
-
|
|
863
|
+
|
|
824
864
|
& > td {
|
|
825
865
|
position: sticky;
|
|
826
866
|
left: 1px;
|
|
@@ -1011,7 +1051,8 @@
|
|
|
1011
1051
|
border-bottom: 1px solid var(--tably-border);
|
|
1012
1052
|
}
|
|
1013
1053
|
.headers > tr {
|
|
1014
|
-
> .column,
|
|
1054
|
+
> .column,
|
|
1055
|
+
> .context-col {
|
|
1015
1056
|
border-bottom: 1px solid var(--tably-border);
|
|
1016
1057
|
border-left: 1px solid var(--tably-border-grid);
|
|
1017
1058
|
}
|
|
@@ -1048,19 +1089,28 @@
|
|
|
1048
1089
|
|
|
1049
1090
|
& > .column {
|
|
1050
1091
|
display: flex;
|
|
1051
|
-
padding-left: var(--tably-padding-x);
|
|
1052
1092
|
overflow: hidden;
|
|
1093
|
+
|
|
1094
|
+
&:not(.pad), &.pad > :global(*:first-child) {
|
|
1095
|
+
padding-left: var(--tably-padding-x);
|
|
1096
|
+
}
|
|
1053
1097
|
}
|
|
1054
1098
|
|
|
1055
1099
|
& > *:last-child:not(.context-col) {
|
|
1056
1100
|
width: 100%;
|
|
1057
|
-
|
|
1101
|
+
|
|
1102
|
+
&:not(.pad), &.pad > :global(*:first-child) {
|
|
1103
|
+
padding-right: var(--tably-padding-x);
|
|
1104
|
+
}
|
|
1058
1105
|
}
|
|
1059
1106
|
}
|
|
1060
1107
|
|
|
1061
1108
|
.row > .column {
|
|
1062
1109
|
background-color: var(--tably-bg);
|
|
1063
|
-
|
|
1110
|
+
&:not(.pad), &.pad > :global(*:first-child) {
|
|
1111
|
+
padding-top: var(--tably-padding-y);
|
|
1112
|
+
padding-bottom: var(--tably-padding-y);
|
|
1113
|
+
}
|
|
1064
1114
|
}
|
|
1065
1115
|
|
|
1066
1116
|
:global(#runic-drag .row) {
|
|
@@ -1079,7 +1129,7 @@
|
|
|
1079
1129
|
height: 100%;
|
|
1080
1130
|
overflow: hidden;
|
|
1081
1131
|
border-left: 1px solid var(--tably-border);
|
|
1082
|
-
|
|
1132
|
+
|
|
1083
1133
|
z-index: 4;
|
|
1084
1134
|
|
|
1085
1135
|
> .panel-content {
|
|
@@ -28,7 +28,6 @@ export class TableState {
|
|
|
28
28
|
filters: this.#props.reorderable ? false : (this.#props.filters ?? []),
|
|
29
29
|
resizeable: this.#props.resizeable ?? true,
|
|
30
30
|
reorderable: this.#props.reorderable ?? false,
|
|
31
|
-
href: this.#props.href,
|
|
32
31
|
select: this.#props.select ?? false,
|
|
33
32
|
auto: this.#props.auto ?? false
|
|
34
33
|
});
|