svelte-tably 1.0.0-next.12 → 1.0.0-next.13
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/README.md +3 -3
- package/dist/expandable/Expandable.svelte +24 -0
- package/dist/expandable/Expandable.svelte.d.ts +25 -0
- package/dist/expandable/expandable.svelte.js +20 -0
- package/dist/size-tween.svelte.d.ts +14 -0
- package/dist/size-tween.svelte.js +30 -0
- package/dist/table/Table.svelte +175 -32
- package/dist/table/Table.svelte.d.ts +8 -1
- package/dist/table/table.svelte.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -19,8 +19,8 @@ A high performant, feature rich, dynamic table
|
|
|
19
19
|
- [x] filtering
|
|
20
20
|
- [x] reorderable table
|
|
21
21
|
- [ ] row context-menu
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
22
|
+
- [x] Expandable rows
|
|
23
|
+
- [x] to CSV
|
|
24
24
|
|
|
25
25
|
### Usage Notes
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ A high performant, feature rich, dynamic table
|
|
|
34
34
|
])
|
|
35
35
|
|
|
36
36
|
let activePanel = $state('columns') as string | undefined
|
|
37
|
-
|
|
37
|
+
let selected = $state([]) as typeof data
|
|
38
38
|
</script>
|
|
39
39
|
|
|
40
40
|
<Table {data} panel={activePanel} select bind:selected>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- @component
|
|
2
|
+
|
|
3
|
+
This is a description, \
|
|
4
|
+
on how to use this.
|
|
5
|
+
|
|
6
|
+
@example
|
|
7
|
+
<Component />
|
|
8
|
+
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang='ts'>
|
|
12
|
+
|
|
13
|
+
import { ExpandableState, type ExpandableProps } from './expandable.svelte.js'
|
|
14
|
+
import type { AnyRecord } from '../utility.svelte.js'
|
|
15
|
+
import { fromProps } from '../utility.svelte.js'
|
|
16
|
+
|
|
17
|
+
type T = $$Generic<AnyRecord>
|
|
18
|
+
|
|
19
|
+
let { ...restProps }: ExpandableProps<T> = $props()
|
|
20
|
+
|
|
21
|
+
const properties = fromProps(restProps)
|
|
22
|
+
new ExpandableState<T>(properties)
|
|
23
|
+
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AnyRecord } from '../utility.svelte.js';
|
|
2
|
+
declare class __sveltets_Render<T extends AnyRecord> {
|
|
3
|
+
props(): ExpandableProps<T_1>;
|
|
4
|
+
events(): {};
|
|
5
|
+
slots(): {};
|
|
6
|
+
bindings(): "";
|
|
7
|
+
exports(): {};
|
|
8
|
+
}
|
|
9
|
+
interface $$IsomorphicComponent {
|
|
10
|
+
new <T extends AnyRecord>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
11
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
12
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
13
|
+
<T extends AnyRecord>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
14
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* This is a description, \
|
|
18
|
+
* on how to use this.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <Component />
|
|
22
|
+
*/
|
|
23
|
+
declare const Expandable: $$IsomorphicComponent;
|
|
24
|
+
type Expandable<T extends AnyRecord> = InstanceType<typeof Expandable<T>>;
|
|
25
|
+
export default Expandable;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { TableState } from '../table/table.svelte.js';
|
|
2
|
+
export class ExpandableState {
|
|
3
|
+
#table;
|
|
4
|
+
#props = $state({});
|
|
5
|
+
snippets = $derived({
|
|
6
|
+
content: this.#props.content
|
|
7
|
+
});
|
|
8
|
+
options = $derived({
|
|
9
|
+
slide: this.#props.slide ?? 200
|
|
10
|
+
});
|
|
11
|
+
constructor(props) {
|
|
12
|
+
this.#props = props;
|
|
13
|
+
this.#table = TableState.getContext();
|
|
14
|
+
if (!this.#table) {
|
|
15
|
+
throw new Error('svelte-tably: Expandable must be associated with a Table');
|
|
16
|
+
}
|
|
17
|
+
this.#table.expandable = this;
|
|
18
|
+
$effect(() => () => this.#table.expandable === this && (this.#table.expandable = undefined));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface SizeOptions {
|
|
2
|
+
min?: number;
|
|
3
|
+
duration?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class SizeTween {
|
|
6
|
+
#private;
|
|
7
|
+
current: number;
|
|
8
|
+
transitioning: boolean;
|
|
9
|
+
/** bind:offsetWidth bind:offsetHeight */
|
|
10
|
+
size: number;
|
|
11
|
+
set target(value: number);
|
|
12
|
+
constructor(cb: () => boolean | undefined, opts?: SizeOptions);
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { tick, untrack } from 'svelte';
|
|
2
|
+
import { sineInOut } from 'svelte/easing';
|
|
3
|
+
import { Tween } from 'svelte/motion';
|
|
4
|
+
export class SizeTween {
|
|
5
|
+
#tweenOptions = { duration: 300, easing: sineInOut };
|
|
6
|
+
#tween = new Tween(0, this.#tweenOptions);
|
|
7
|
+
current = $derived(this.#tween.current);
|
|
8
|
+
transitioning = $state(false);
|
|
9
|
+
/** bind:offsetWidth bind:offsetHeight */
|
|
10
|
+
size = $state(0);
|
|
11
|
+
set target(value) {
|
|
12
|
+
this.transitioning = true;
|
|
13
|
+
this.#tween.set(value, this.#tweenOptions).then(() => this.transitioning = false);
|
|
14
|
+
}
|
|
15
|
+
constructor(cb, opts = {}) {
|
|
16
|
+
if ('duration' in opts) {
|
|
17
|
+
this.#tweenOptions.duration = opts.duration;
|
|
18
|
+
}
|
|
19
|
+
untrack(() => {
|
|
20
|
+
if (cb()) {
|
|
21
|
+
requestAnimationFrame(() => {
|
|
22
|
+
this.#tween.set(Math.max(this.size, opts.min ?? 0), { duration: 0 });
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
$effect.pre(() => {
|
|
27
|
+
this.target = cb() ? Math.max(this.size, opts.min ?? 0) : 0;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/table/Table.svelte
CHANGED
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
import { fromProps, mounted } from '../utility.svelte.js'
|
|
25
25
|
import { conditional } from '../conditional.svelte.js'
|
|
26
26
|
import { ColumnState } from '../column/column.svelte.js'
|
|
27
|
+
import Expandable from '../expandable/Expandable.svelte'
|
|
28
|
+
import { SizeTween } from '../size-tween.svelte.js'
|
|
27
29
|
|
|
28
30
|
type T = $$Generic<Record<PropertyKey, unknown>>
|
|
29
31
|
|
|
@@ -35,7 +37,8 @@
|
|
|
35
37
|
new <V>(...args: ConstructorParams<typeof Column<T, V>>): ConstructorReturnType<typeof Column<T, V>>
|
|
36
38
|
<V>(...args: Parameters<typeof Column<T, V>>): ReturnType<typeof Column<T, V>>
|
|
37
39
|
}
|
|
38
|
-
Panel: typeof Panel
|
|
40
|
+
Panel: typeof Panel<T>
|
|
41
|
+
Expandable: typeof Expandable<T>
|
|
39
42
|
readonly table: TableState<T>
|
|
40
43
|
readonly data: T[]
|
|
41
44
|
}
|
|
@@ -70,7 +73,7 @@
|
|
|
70
73
|
|
|
71
74
|
const virtualization = new Virtualization(table)
|
|
72
75
|
|
|
73
|
-
const panelTween = new
|
|
76
|
+
const panelTween = new SizeTween(() => !!properties.panel)
|
|
74
77
|
|
|
75
78
|
let hoveredRow: T | null = $state(null)
|
|
76
79
|
|
|
@@ -111,6 +114,7 @@
|
|
|
111
114
|
.map((column, i, arr) => {
|
|
112
115
|
sum += getWidth(arr[i - 1]?.id, i === 0 ? 0 : undefined)
|
|
113
116
|
return `
|
|
117
|
+
#${table.id} .column.sticky[data-column='${column.id}'],
|
|
114
118
|
[data-svelte-tably='${table.id}'] .column.sticky[data-column='${column.id}'] {
|
|
115
119
|
left: ${sum}px;
|
|
116
120
|
}
|
|
@@ -147,6 +151,9 @@
|
|
|
147
151
|
return { destroy: () => observer.disconnect() }
|
|
148
152
|
}
|
|
149
153
|
|
|
154
|
+
let tbody = $state({
|
|
155
|
+
width: 0
|
|
156
|
+
})
|
|
150
157
|
async function onscroll() {
|
|
151
158
|
const target = virtualization.viewport.element!
|
|
152
159
|
if (target.scrollTop !== virtualization.scrollTop) {
|
|
@@ -161,10 +168,100 @@
|
|
|
161
168
|
elements.headers.scrollLeft = target.scrollLeft
|
|
162
169
|
elements.statusbar.scrollLeft = target.scrollLeft
|
|
163
170
|
}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
// * --- CSV --- *
|
|
174
|
+
let csv = $state(false) as false | { selected?: boolean }
|
|
175
|
+
let csvElement = $state() as undefined | HTMLTableElement
|
|
176
|
+
interface CSVOptions {
|
|
177
|
+
/** Semi-colons as separator? */
|
|
178
|
+
semicolon?: boolean
|
|
179
|
+
/** Only selected rows */
|
|
180
|
+
selected?: boolean
|
|
181
|
+
}
|
|
182
|
+
export async function toCSV(opts: CSVOptions = {}) {
|
|
183
|
+
csv = { selected: !!opts.selected }
|
|
184
|
+
let resolve: (value: HTMLTableElement) => void
|
|
185
|
+
const promise = new Promise<HTMLTableElement>(r => resolve = r)
|
|
186
|
+
|
|
187
|
+
const clean = $effect.root(() => {
|
|
188
|
+
$effect(() => {
|
|
189
|
+
if(csvElement) {
|
|
190
|
+
resolve(csvElement)
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
let table = await promise
|
|
196
|
+
clean()
|
|
197
|
+
|
|
198
|
+
const separator = opts.semicolon ? ";" : ","
|
|
199
|
+
const rows = Array.from(table.rows)
|
|
200
|
+
const csvRows = []
|
|
201
|
+
|
|
202
|
+
for (const row of rows) {
|
|
203
|
+
const cells = Array.from(row.cells)
|
|
204
|
+
const csvCells = cells.map(cell => {
|
|
205
|
+
let text = cell.textContent?.trim() || ''
|
|
206
|
+
|
|
207
|
+
// Escape double quotes and wrap in quotes if needed
|
|
208
|
+
if(text.includes('"')) {
|
|
209
|
+
text = text.replace(/"/g, '""')
|
|
210
|
+
}
|
|
211
|
+
if(text.includes(separator) || text.includes('"') || text.includes('\n')) {
|
|
212
|
+
text = `"${text}"`
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return text
|
|
216
|
+
})
|
|
217
|
+
csvRows.push(csvCells.join(separator))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
csv = false
|
|
221
|
+
return csvRows.join("\n")
|
|
222
|
+
}
|
|
223
|
+
// * --- CSV --- *
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
// * --- Expandable --- *
|
|
227
|
+
let expandedRow = $state() as undefined | T
|
|
228
|
+
|
|
164
229
|
</script>
|
|
165
230
|
|
|
166
231
|
<!---------------------------------------------------->
|
|
167
232
|
|
|
233
|
+
{#if csv !== false}
|
|
234
|
+
{@const renderedColumns = columns.filter(v => v.id !== '__fixed')}
|
|
235
|
+
<table bind:this={csvElement} hidden>
|
|
236
|
+
<thead>
|
|
237
|
+
<tr>
|
|
238
|
+
{#each renderedColumns as column}
|
|
239
|
+
<th>{@render column.snippets.title()}</th>
|
|
240
|
+
{/each}
|
|
241
|
+
</tr>
|
|
242
|
+
</thead>
|
|
243
|
+
<tbody>
|
|
244
|
+
{#each data.current as row, i}
|
|
245
|
+
{#if (csv.selected && table.selected.includes(row)) || !csv.selected}
|
|
246
|
+
<tr>
|
|
247
|
+
{#each renderedColumns as column}
|
|
248
|
+
<td>
|
|
249
|
+
{@render column.snippets.row?.(row, {
|
|
250
|
+
index: i,
|
|
251
|
+
value: column.options.value?.(row),
|
|
252
|
+
isHovered: false,
|
|
253
|
+
itemState: { index: i, dragging: false, positioning: false } as ItemState<any>,
|
|
254
|
+
selected: false
|
|
255
|
+
})}
|
|
256
|
+
</td>
|
|
257
|
+
{/each}
|
|
258
|
+
</tr>
|
|
259
|
+
{/if}
|
|
260
|
+
{/each}
|
|
261
|
+
</tbody>
|
|
262
|
+
</table>
|
|
263
|
+
{/if}
|
|
264
|
+
|
|
168
265
|
<svelte:head>
|
|
169
266
|
{@html `<style>${style}</style>`}
|
|
170
267
|
</svelte:head>
|
|
@@ -264,23 +361,31 @@
|
|
|
264
361
|
{/snippet}
|
|
265
362
|
|
|
266
363
|
{#snippet rowSnippet(item: T, itemState?: ItemState<T>)}
|
|
267
|
-
{@const props = table.options.href ? { href: table.options.href(item) } : {}}
|
|
268
364
|
{@const i = itemState?.index ?? 0}
|
|
269
365
|
{@const index = (itemState?.index ?? 0)}
|
|
270
|
-
<
|
|
271
|
-
this={table.options.href ? 'a' : 'tr'}
|
|
366
|
+
<tr
|
|
272
367
|
aria-rowindex={index + 1}
|
|
273
368
|
data-svelte-tably={table.id}
|
|
274
369
|
style:opacity={itemState?.positioning ? 0 : 1}
|
|
275
|
-
class=
|
|
370
|
+
class='row'
|
|
276
371
|
class:hover={hoveredRow === item}
|
|
277
372
|
class:dragging={itemState?.dragging}
|
|
278
373
|
class:selected={table.selected?.includes(item)}
|
|
279
374
|
class:first={i === 0}
|
|
280
375
|
class:last={i === virtualization.area.length - 1}
|
|
281
|
-
{...
|
|
376
|
+
{...(table.options.href ? { href: table.options.href(item) } : {})}
|
|
377
|
+
{...(itemState?.dragging ? { 'data-svelte-tably': table.id } : {})}
|
|
282
378
|
onpointerenter={() => (hoveredRow = item)}
|
|
283
379
|
onpointerleave={() => (hoveredRow = null)}
|
|
380
|
+
onclick={(e) => {
|
|
381
|
+
if (table.expandable) {
|
|
382
|
+
let target = e.target as HTMLElement
|
|
383
|
+
if(['INPUT', 'TEXTAREA', 'BUTTON', 'A'].includes(target.tagName)) {
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
expandedRow = expandedRow === item ? undefined : item
|
|
387
|
+
}
|
|
388
|
+
}}
|
|
284
389
|
>
|
|
285
390
|
{@render columnsSnippet(
|
|
286
391
|
(column) => column.snippets.row,
|
|
@@ -312,20 +417,41 @@
|
|
|
312
417
|
]
|
|
313
418
|
}
|
|
314
419
|
)}
|
|
315
|
-
</
|
|
420
|
+
</tr>
|
|
421
|
+
|
|
422
|
+
{@const expandableTween = new SizeTween(() => table.expandable && expandedRow === item, { min: 1, duration: 150 })}
|
|
423
|
+
{#if expandableTween.current > 0}
|
|
424
|
+
<tr class='expandable' style='height: {expandableTween.current}px'>
|
|
425
|
+
<td
|
|
426
|
+
colspan={columns.length}
|
|
427
|
+
style='height: {expandableTween.current}px'
|
|
428
|
+
>
|
|
429
|
+
<div
|
|
430
|
+
bind:offsetHeight={expandableTween.size}
|
|
431
|
+
style='width: {tbody.width - 2}px'
|
|
432
|
+
>
|
|
433
|
+
{@render table.expandable!.snippets.content?.(item, {
|
|
434
|
+
close() {
|
|
435
|
+
expandedRow = undefined
|
|
436
|
+
}
|
|
437
|
+
})}
|
|
438
|
+
</div>
|
|
439
|
+
</td>
|
|
440
|
+
</tr>
|
|
441
|
+
{/if}
|
|
316
442
|
{/snippet}
|
|
317
443
|
|
|
318
444
|
<table
|
|
319
445
|
id={table.id}
|
|
320
|
-
class=
|
|
321
|
-
style=
|
|
446
|
+
class='table svelte-tably'
|
|
447
|
+
style='--t: {virtualization.virtualTop}px; --b: {virtualization.virtualBottom}px;'
|
|
322
448
|
aria-rowcount={data.current.length}
|
|
323
449
|
>
|
|
324
|
-
<thead class=
|
|
450
|
+
<thead class='headers' bind:this={elements.headers}>
|
|
325
451
|
{@render columnsSnippet(
|
|
326
452
|
(column) => column.snippets.header,
|
|
327
453
|
() => [{
|
|
328
|
-
get header() { return true }
|
|
454
|
+
get header() { return true },
|
|
329
455
|
get data() { return data.current }
|
|
330
456
|
}],
|
|
331
457
|
true
|
|
@@ -333,11 +459,12 @@
|
|
|
333
459
|
</thead>
|
|
334
460
|
|
|
335
461
|
<tbody
|
|
336
|
-
class=
|
|
462
|
+
class='content'
|
|
337
463
|
use:reorderArea={{ axis: 'y' }}
|
|
338
464
|
bind:this={virtualization.viewport.element}
|
|
339
465
|
onscrollcapture={onscroll}
|
|
340
466
|
bind:clientHeight={virtualization.viewport.height}
|
|
467
|
+
bind:clientWidth={tbody.width}
|
|
341
468
|
>
|
|
342
469
|
{#if table.options.reorderable}
|
|
343
470
|
{@render reorderArea({
|
|
@@ -358,7 +485,7 @@
|
|
|
358
485
|
{/if}
|
|
359
486
|
</tbody>
|
|
360
487
|
|
|
361
|
-
<tfoot class=
|
|
488
|
+
<tfoot class='statusbar' bind:this={elements.statusbar}>
|
|
362
489
|
<tr>
|
|
363
490
|
{@render columnsSnippet(
|
|
364
491
|
(column) => column.snippets.statusbar,
|
|
@@ -370,14 +497,13 @@
|
|
|
370
497
|
</tfoot>
|
|
371
498
|
|
|
372
499
|
<caption
|
|
373
|
-
class=
|
|
374
|
-
style=
|
|
375
|
-
style:overflow={panelTween.transitioning ? 'hidden' : 'auto'}
|
|
500
|
+
class='panel'
|
|
501
|
+
style='width: {panelTween.current}px;'
|
|
376
502
|
>
|
|
377
503
|
{#if properties.panel && properties.panel in table.panels}
|
|
378
504
|
<div
|
|
379
|
-
class=
|
|
380
|
-
bind:
|
|
505
|
+
class='panel-content'
|
|
506
|
+
bind:offsetWidth={panelTween.size}
|
|
381
507
|
in:fly={{ x: 100, easing: sineInOut, duration: 300 }}
|
|
382
508
|
out:fly={{ x: 100, duration: 200, easing: sineInOut }}
|
|
383
509
|
>
|
|
@@ -392,18 +518,18 @@
|
|
|
392
518
|
</div>
|
|
393
519
|
{/if}
|
|
394
520
|
</caption>
|
|
395
|
-
<caption class=
|
|
396
|
-
<button aria-label=
|
|
521
|
+
<caption class='backdrop' aria-hidden={properties.panel && table.panels[properties.panel]?.backdrop ? false : true}>
|
|
522
|
+
<button aria-label='Panel backdrop' class='btn-backdrop' tabindex='-1' onclick={() => (properties.panel = undefined)}
|
|
397
523
|
></button>
|
|
398
524
|
</caption>
|
|
399
525
|
</table>
|
|
400
526
|
|
|
401
527
|
{#snippet headerSelected(ctx: HeaderSelectCtx<T>)}
|
|
402
|
-
<input type=
|
|
528
|
+
<input type='checkbox' indeterminate={ctx.indeterminate} bind:checked={ctx.isSelected} />
|
|
403
529
|
{/snippet}
|
|
404
530
|
|
|
405
531
|
{#snippet rowSelected(ctx: RowSelectCtx<T>)}
|
|
406
|
-
<input type=
|
|
532
|
+
<input type='checkbox' bind:checked={ctx.isSelected} />
|
|
407
533
|
{/snippet}
|
|
408
534
|
|
|
409
535
|
{#if table.options.select || table.options.reorderable}
|
|
@@ -416,16 +542,16 @@
|
|
|
416
542
|
} = typeof select === 'boolean' ? {} : select}
|
|
417
543
|
{#if show !== 'never' || reorderable}
|
|
418
544
|
<Column
|
|
419
|
-
id=
|
|
545
|
+
id='__fixed'
|
|
420
546
|
{table}
|
|
421
547
|
fixed
|
|
422
548
|
width={Math.max(56, (select && show !== 'never' ? 34 : 0) + (reorderable ? 34 : 0))}
|
|
423
549
|
resizeable={false}
|
|
424
550
|
>
|
|
425
551
|
{#snippet header()}
|
|
426
|
-
<div class=
|
|
552
|
+
<div class='__fixed'>
|
|
427
553
|
{#if reorderable}
|
|
428
|
-
<span style=
|
|
554
|
+
<span style='width: 16px; display: flex; align-items: center;'></span>
|
|
429
555
|
{/if}
|
|
430
556
|
{#if select}
|
|
431
557
|
{@render headerSnippet({
|
|
@@ -453,9 +579,9 @@
|
|
|
453
579
|
</div>
|
|
454
580
|
{/snippet}
|
|
455
581
|
{#snippet row(item, row)}
|
|
456
|
-
<div class=
|
|
582
|
+
<div class='__fixed'>
|
|
457
583
|
{#if reorderable}
|
|
458
|
-
<span style=
|
|
584
|
+
<span style='width: 16px; display: flex; align-items: center;' use:row.itemState.handle>
|
|
459
585
|
{#if (row.isHovered && !row.itemState?.area.isTarget) || row.itemState.dragging}
|
|
460
586
|
{@render dragSnippet()}
|
|
461
587
|
{/if}
|
|
@@ -489,6 +615,7 @@
|
|
|
489
615
|
{@render content?.({
|
|
490
616
|
Column,
|
|
491
617
|
Panel,
|
|
618
|
+
Expandable,
|
|
492
619
|
get table() {
|
|
493
620
|
return table
|
|
494
621
|
},
|
|
@@ -510,6 +637,21 @@
|
|
|
510
637
|
overflow: visible;
|
|
511
638
|
}
|
|
512
639
|
|
|
640
|
+
.expandable {
|
|
641
|
+
position: relative;
|
|
642
|
+
|
|
643
|
+
& > td {
|
|
644
|
+
position: sticky;
|
|
645
|
+
left: 1px;
|
|
646
|
+
> div {
|
|
647
|
+
position: absolute;
|
|
648
|
+
overflow: auto;
|
|
649
|
+
top: 0;
|
|
650
|
+
left: 0;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
513
655
|
caption {
|
|
514
656
|
all: unset;
|
|
515
657
|
}
|
|
@@ -572,7 +714,7 @@
|
|
|
572
714
|
height: var(--b);
|
|
573
715
|
}
|
|
574
716
|
|
|
575
|
-
|
|
717
|
+
.row:global(:is(a)) {
|
|
576
718
|
color: inherit;
|
|
577
719
|
text-decoration: inherit;
|
|
578
720
|
}
|
|
@@ -728,18 +870,19 @@
|
|
|
728
870
|
position: relative;
|
|
729
871
|
grid-area: panel;
|
|
730
872
|
height: 100%;
|
|
731
|
-
|
|
873
|
+
overflow: hidden;
|
|
732
874
|
border-left: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
733
|
-
|
|
734
|
-
scrollbar-width: thin;
|
|
875
|
+
|
|
735
876
|
z-index: 4;
|
|
736
877
|
|
|
737
878
|
> .panel-content {
|
|
738
879
|
position: absolute;
|
|
739
880
|
top: 0;
|
|
740
881
|
right: 0;
|
|
882
|
+
bottom: 0;
|
|
741
883
|
width: min-content;
|
|
742
884
|
overflow: auto;
|
|
885
|
+
scrollbar-width: thin;
|
|
743
886
|
padding: var(--tably-padding-y, 0.5rem) 0;
|
|
744
887
|
}
|
|
745
888
|
}
|
|
@@ -3,7 +3,14 @@ declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
|
|
|
3
3
|
events(): {};
|
|
4
4
|
slots(): {};
|
|
5
5
|
bindings(): "selected" | "panel" | "data";
|
|
6
|
-
exports(): {
|
|
6
|
+
exports(): {
|
|
7
|
+
toCSV: (opts?: {
|
|
8
|
+
/** Semi-colons as separator? */
|
|
9
|
+
semicolon?: boolean;
|
|
10
|
+
/** Only selected rows */
|
|
11
|
+
selected?: boolean;
|
|
12
|
+
}) => Promise<string>;
|
|
13
|
+
};
|
|
7
14
|
}
|
|
8
15
|
interface $$IsomorphicComponent {
|
|
9
16
|
new <T extends Record<PropertyKey, unknown>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-tably",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.13",
|
|
4
4
|
"repository": "github:refzlund/svelte-tably",
|
|
5
5
|
"homepage": "https://github.com/Refzlund/svelte-tably",
|
|
6
6
|
"bugs": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
14
14
|
"floating-runes": "^1.0.0",
|
|
15
15
|
"publint": "^0.2.0",
|
|
16
|
-
"runic-reorder": "
|
|
16
|
+
"runic-reorder": "^1.0.0",
|
|
17
17
|
"svelte": "^5.0.0",
|
|
18
18
|
"svelte-check": "^4.0.0",
|
|
19
19
|
"typescript": "^5.0.0",
|