svelte-tably 1.0.0-next.4 → 1.0.0-next.6
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 +50 -29
- package/dist/{Table/Column.svelte → Column.svelte} +28 -20
- package/dist/{Table/Column.svelte.d.ts → Column.svelte.d.ts} +23 -4
- package/dist/{Table/Panel.svelte → Panel.svelte} +8 -8
- package/dist/{prototype/Table.svelte.d.ts → Panel.svelte.d.ts} +27 -27
- package/dist/{Table/Table.svelte → Table.svelte} +212 -71
- package/dist/{Table/Table.svelte.d.ts → Table.svelte.d.ts} +27 -7
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/package.json +3 -1
- package/dist/Table/Panel.svelte.d.ts +0 -32
- package/dist/Table/index.d.ts +0 -1
- package/dist/Table/index.js +0 -1
- package/dist/prototype/Headers.svelte +0 -33
- package/dist/prototype/Headers.svelte.d.ts +0 -15
- package/dist/prototype/Panels.svelte +0 -25
- package/dist/prototype/Panels.svelte.d.ts +0 -15
- package/dist/prototype/Rows.svelte +0 -35
- package/dist/prototype/Rows.svelte.d.ts +0 -27
- package/dist/prototype/Statusbar.svelte +0 -35
- package/dist/prototype/Statusbar.svelte.d.ts +0 -13
- package/dist/prototype/Table.svelte +0 -336
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
export interface TableState<T extends Record<PropertyKey, any> = Record<PropertyKey, any>> {
|
|
14
14
|
columns: Record<string, TColumn<T, unknown>>
|
|
15
|
-
panels: Record<string, TPanel
|
|
15
|
+
panels: Record<string, TPanel<T>>
|
|
16
|
+
selected: T[] | null
|
|
16
17
|
sortby?: string
|
|
17
18
|
positions: {
|
|
18
19
|
sticky: string[]
|
|
@@ -20,7 +21,10 @@
|
|
|
20
21
|
hidden: string[]
|
|
21
22
|
toggle(key: string): void
|
|
22
23
|
}
|
|
24
|
+
readonly resizeable: boolean
|
|
23
25
|
readonly data: T[]
|
|
26
|
+
/** Rows become anchors */
|
|
27
|
+
readonly href?: (item: T) => string
|
|
24
28
|
addColumn(key: string, options: TColumn<T, unknown>): void
|
|
25
29
|
removeColumn(key: string): void
|
|
26
30
|
}
|
|
@@ -38,24 +42,37 @@
|
|
|
38
42
|
import Panel, { PanelTween, type Panel as TPanel } from './Panel.svelte'
|
|
39
43
|
import { fly } from 'svelte/transition'
|
|
40
44
|
import { sineInOut } from 'svelte/easing'
|
|
45
|
+
import { get } from 'svelte/store'
|
|
46
|
+
import { on } from 'svelte/events'
|
|
47
|
+
import { ka_GE } from '@faker-js/faker'
|
|
41
48
|
|
|
42
49
|
interface Props {
|
|
43
|
-
content: Snippet<[context: { Column: typeof Column<T>, Panel: typeof Panel,
|
|
50
|
+
content: Snippet<[context: { Column: typeof Column<T>, Panel: typeof Panel, readonly table: TableState<T>, readonly data: T[] }]>
|
|
44
51
|
|
|
45
52
|
panel?: string
|
|
46
53
|
data?: T[]
|
|
47
54
|
id?: string
|
|
55
|
+
href?: (item: T) => string
|
|
56
|
+
/**
|
|
57
|
+
* Can you change the width of the columns?
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
resizeable?: boolean
|
|
61
|
+
selectable?: 'hover' | 'always' | 'never'
|
|
48
62
|
}
|
|
49
63
|
|
|
50
64
|
let {
|
|
51
65
|
content,
|
|
52
66
|
|
|
53
|
-
panel,
|
|
67
|
+
panel = $bindable(),
|
|
54
68
|
data: _data = [],
|
|
55
|
-
id = Array.from({length: 12}, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')
|
|
69
|
+
id = Array.from({length: 12}, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join(''),
|
|
70
|
+
href,
|
|
71
|
+
resizeable = true,
|
|
72
|
+
selectable = 'never'
|
|
56
73
|
}: Props = $props()
|
|
57
74
|
|
|
58
|
-
const data = $derived(_data
|
|
75
|
+
const data = $derived([..._data])
|
|
59
76
|
|
|
60
77
|
const elements = $state({}) as Record<'headers' | 'statusbar' | 'rows', HTMLElement>
|
|
61
78
|
|
|
@@ -64,36 +81,34 @@
|
|
|
64
81
|
let scrollTop = $state(0)
|
|
65
82
|
let viewportHeight = $state(0)
|
|
66
83
|
|
|
67
|
-
let _heightPerItem = 24
|
|
68
|
-
let renderItemLength = $derived(Math.ceil(Math.max(30, viewportHeight / (_heightPerItem / 3))))
|
|
69
|
-
|
|
70
84
|
let heightPerItem = $derived.by(() => {
|
|
71
85
|
data
|
|
72
86
|
if(!elements.rows)
|
|
73
87
|
return 8
|
|
74
88
|
const result = elements.rows.scrollHeight / elements.rows.childNodes.length
|
|
75
|
-
_heightPerItem = result
|
|
76
89
|
return result
|
|
77
90
|
})
|
|
78
91
|
|
|
92
|
+
let renderItemLength = $derived(Math.ceil(Math.max(30, (viewportHeight / heightPerItem) * 2)))
|
|
93
|
+
|
|
94
|
+
const spacing = () => viewportHeight / 2
|
|
79
95
|
let virtualTop = $derived.by(() => {
|
|
80
|
-
let
|
|
81
|
-
let scroll = scrollTop - spacing
|
|
96
|
+
let scroll = scrollTop - spacing()
|
|
82
97
|
let virtualTop = Math.max(scroll, 0)
|
|
83
98
|
virtualTop -= virtualTop % heightPerItem
|
|
84
99
|
return virtualTop
|
|
85
100
|
})
|
|
86
101
|
let virtualBottom = $derived.by(() => {
|
|
87
|
-
const virtualBottom = (heightPerItem * data.length) - virtualTop
|
|
88
|
-
return virtualBottom
|
|
102
|
+
const virtualBottom = (heightPerItem * data.length) - virtualTop - spacing() * 4
|
|
103
|
+
return Math.max(virtualBottom, 0)
|
|
89
104
|
})
|
|
90
|
-
|
|
91
105
|
/** The area of data that is rendered */
|
|
92
106
|
const area = $derived.by(() => {
|
|
93
107
|
const index = (virtualTop / heightPerItem) || 0
|
|
108
|
+
const end = index + untrack(() => renderItemLength)
|
|
94
109
|
return data.slice(
|
|
95
110
|
index,
|
|
96
|
-
|
|
111
|
+
end
|
|
97
112
|
)
|
|
98
113
|
})
|
|
99
114
|
// * --- Virtualization --- *
|
|
@@ -101,6 +116,7 @@
|
|
|
101
116
|
|
|
102
117
|
const table: TableState<T> = $state({
|
|
103
118
|
columns: {},
|
|
119
|
+
selected: selectable === 'never' ? null : [],
|
|
104
120
|
panels: {},
|
|
105
121
|
positions: {
|
|
106
122
|
sticky: [],
|
|
@@ -113,9 +129,15 @@
|
|
|
113
129
|
table.positions.hidden.push(key)
|
|
114
130
|
}
|
|
115
131
|
},
|
|
132
|
+
get href() {
|
|
133
|
+
return href
|
|
134
|
+
},
|
|
116
135
|
get data() {
|
|
117
136
|
return data
|
|
118
137
|
},
|
|
138
|
+
get resizeable() {
|
|
139
|
+
return resizeable
|
|
140
|
+
},
|
|
119
141
|
addColumn(key, column) {
|
|
120
142
|
table.columns[key] = column
|
|
121
143
|
|
|
@@ -142,30 +164,50 @@
|
|
|
142
164
|
|
|
143
165
|
// * --- *
|
|
144
166
|
|
|
145
|
-
const panelTween = new PanelTween(() => panel)
|
|
167
|
+
const panelTween = new PanelTween(() => panel, 24)
|
|
168
|
+
|
|
169
|
+
let hoveredRow: T | null = $state(null)
|
|
146
170
|
|
|
147
171
|
/** Order of columns */
|
|
148
|
-
const
|
|
172
|
+
const notHidden = (key: string) => !table.positions.hidden.includes(key)
|
|
173
|
+
const sticky = $derived(table.positions.sticky.filter(notHidden))
|
|
174
|
+
const scrolled = $derived(table.positions.scroll.filter(notHidden))
|
|
175
|
+
const columns = $derived([...sticky, ...scrolled])
|
|
149
176
|
|
|
150
177
|
/** Width of each column */
|
|
151
|
-
const
|
|
178
|
+
const columnWidths = $state({}) as Record<string, number>
|
|
179
|
+
|
|
180
|
+
const getWidth = (key: string, def: number = 150) => columnWidths[key] || table.columns[key]?.defaults.width || def
|
|
152
181
|
|
|
153
182
|
/** grid-template-columns for widths */
|
|
154
183
|
const style = $derived(`
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
184
|
+
#${id} > .headers,
|
|
185
|
+
#${id} > .content > .rows > .row,
|
|
186
|
+
#${id} > .statusbar,
|
|
187
|
+
#${id} > .content > .virtual.bottom {
|
|
188
|
+
grid-template-columns: ${
|
|
189
|
+
columns.map((key, i, arr) => {
|
|
190
|
+
const width = getWidth(key)
|
|
191
|
+
if(i === arr.length - 1)
|
|
192
|
+
return `minmax(${width}px, 1fr)`
|
|
193
|
+
return `${width}px`
|
|
194
|
+
}).join(' ')
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
` + sticky.map((key, i, arr) => `
|
|
198
|
+
#${id} .column.sticky[data-column='${key}'] {
|
|
199
|
+
left: ${getWidth(arr[i - 1], 0)}px;
|
|
200
|
+
}
|
|
201
|
+
`).join(''))
|
|
202
|
+
|
|
203
|
+
function observeColumnWidth(node: HTMLDivElement, isHeader = false) {
|
|
166
204
|
if(!isHeader) return
|
|
167
|
-
observer
|
|
168
|
-
|
|
205
|
+
const observer = new MutationObserver(mutations => {
|
|
206
|
+
const target = mutations[0].target as HTMLElement
|
|
207
|
+
columnWidths[target.getAttribute('data-column')!] = parseFloat(target.style.width)
|
|
208
|
+
})
|
|
209
|
+
observer.observe(node, {attributes: true})
|
|
210
|
+
return { destroy: () => observer.disconnect() }
|
|
169
211
|
}
|
|
170
212
|
|
|
171
213
|
function onscroll(event: Event) {
|
|
@@ -179,6 +221,10 @@
|
|
|
179
221
|
elements.statusbar.scrollLeft = target.scrollLeft
|
|
180
222
|
}
|
|
181
223
|
|
|
224
|
+
export {
|
|
225
|
+
table as state
|
|
226
|
+
}
|
|
227
|
+
|
|
182
228
|
</script>
|
|
183
229
|
<!---------------------------------------------------->
|
|
184
230
|
|
|
@@ -187,34 +233,43 @@
|
|
|
187
233
|
</svelte:head>
|
|
188
234
|
|
|
189
235
|
{#snippet columnsSnippet(
|
|
190
|
-
renderable: (column: string) => Snippet<[arg0?: any, arg1?: any
|
|
236
|
+
renderable: (column: string) => Snippet<[arg0?: any, arg1?: any]> | undefined,
|
|
191
237
|
arg: null | ((column: string) => any[]) = null,
|
|
192
238
|
isHeader = false
|
|
193
239
|
)}
|
|
194
240
|
{#each table.positions.sticky as column, i (column)}
|
|
195
241
|
{#if !table.positions.hidden.includes(column)}
|
|
196
242
|
{@const args = arg ? arg(column) : []}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{
|
|
243
|
+
<div
|
|
244
|
+
class='column sticky'
|
|
245
|
+
use:observeColumnWidth={isHeader}
|
|
246
|
+
data-column={column}
|
|
247
|
+
class:resizeable={table.columns[column].options.resizeable && table.resizeable}
|
|
248
|
+
class:border={i == table.positions.sticky.length - 1}
|
|
249
|
+
>
|
|
250
|
+
{@render renderable(column)?.(args[0], args[1])}
|
|
200
251
|
</div>
|
|
201
252
|
{/if}
|
|
202
253
|
{/each}
|
|
203
254
|
{#each table.positions.scroll as column, i (column)}
|
|
204
255
|
{#if !table.positions.hidden.includes(column)}
|
|
205
256
|
{@const args = arg ? arg(column) : []}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
{
|
|
257
|
+
<div
|
|
258
|
+
class='column'
|
|
259
|
+
data-column={column}
|
|
260
|
+
use:observeColumnWidth={isHeader}
|
|
261
|
+
class:resizeable={table.columns[column].options.resizeable && table.resizeable}
|
|
262
|
+
>
|
|
263
|
+
{@render renderable(column)?.(args[0], args[1])}
|
|
209
264
|
</div>
|
|
210
265
|
{/if}
|
|
211
266
|
{/each}
|
|
212
267
|
{/snippet}
|
|
213
268
|
|
|
214
|
-
<div id={id} class='table'>
|
|
269
|
+
<div id={id} class='table svelte-tably'>
|
|
215
270
|
|
|
216
271
|
<div class='headers' bind:this={elements.headers}>
|
|
217
|
-
{@render columnsSnippet((column) => table.columns[column]?.header,
|
|
272
|
+
{@render columnsSnippet((column) => table.columns[column]?.header, () => [true], true)}
|
|
218
273
|
</div>
|
|
219
274
|
|
|
220
275
|
<div class='content' {onscroll} bind:clientHeight={viewportHeight}>
|
|
@@ -222,15 +277,35 @@
|
|
|
222
277
|
|
|
223
278
|
<div class='rows' bind:this={elements.rows}>
|
|
224
279
|
{#each area as item, i (item)}
|
|
225
|
-
|
|
280
|
+
{@const props = table.href ? { href: table.href(item) } : {}}
|
|
281
|
+
<!-- note: <svelte:element this={table.href ? 'a' : 'div'}> will break the virtualization for some reason -->
|
|
282
|
+
<a
|
|
283
|
+
class='row'
|
|
284
|
+
{...props}
|
|
285
|
+
onpointerenter={() => hoveredRow = item}
|
|
286
|
+
onpointerleave={() => hoveredRow = null}
|
|
287
|
+
>
|
|
288
|
+
{#if table.selected && (((selectable === 'hover' && hoveredRow === item) || selectable === 'always') || table.selected.includes(item))}
|
|
289
|
+
<div class='select' class:hover={selectable === 'hover'}>
|
|
290
|
+
<input type='checkbox' bind:checked={
|
|
291
|
+
() => table.selected!.includes(item),
|
|
292
|
+
(value) => value ? table.selected!.push(item) : table.selected!.splice(table.selected!.indexOf(item), 1)
|
|
293
|
+
}>
|
|
294
|
+
</div>
|
|
295
|
+
{/if}
|
|
296
|
+
|
|
226
297
|
{@render columnsSnippet(
|
|
227
298
|
(column) => table.columns[column]!.row,
|
|
228
299
|
(column) => {
|
|
229
300
|
const col = table.columns[column]!
|
|
230
|
-
return [item,
|
|
301
|
+
return [item, {
|
|
302
|
+
get index() { return _data.indexOf(item) },
|
|
303
|
+
get value() { return col.options.value ? col.options.value(item) : undefined },
|
|
304
|
+
get isHovered() { return hoveredRow === item }
|
|
305
|
+
}]
|
|
231
306
|
}
|
|
232
307
|
)}
|
|
233
|
-
</
|
|
308
|
+
</a>
|
|
234
309
|
{/each}
|
|
235
310
|
</div>
|
|
236
311
|
<div class='virtual bottom' style='height: {virtualBottom}px'>
|
|
@@ -239,10 +314,10 @@
|
|
|
239
314
|
</div>
|
|
240
315
|
|
|
241
316
|
<div class='statusbar' bind:this={elements.statusbar}>
|
|
242
|
-
{@render columnsSnippet((column) => table.columns[column]?.statusbar
|
|
317
|
+
{@render columnsSnippet((column) => table.columns[column]?.statusbar)}
|
|
243
318
|
</div>
|
|
244
319
|
|
|
245
|
-
<div class='panel' style='width: {panelTween.current
|
|
320
|
+
<div class='panel' style='width: {(panelTween.current)}px;' style:overflow={panelTween.transitioning ? 'hidden' : 'auto'}>
|
|
246
321
|
{#if panel && panel in table.panels}
|
|
247
322
|
<div
|
|
248
323
|
class='panel-content'
|
|
@@ -250,29 +325,97 @@
|
|
|
250
325
|
in:fly={{ x: 100, easing: sineInOut, duration:300 }}
|
|
251
326
|
out:fly={{ x:100, duration:200, easing: sineInOut }}
|
|
252
327
|
>
|
|
253
|
-
{@render table.panels[panel].content(table
|
|
328
|
+
{@render table.panels[panel].content({ get table() { return table }, get data() { return data } })}
|
|
254
329
|
</div>
|
|
255
330
|
{/if}
|
|
256
331
|
</div>
|
|
332
|
+
<button
|
|
333
|
+
class='backdrop'
|
|
334
|
+
aria-label='Panel backdrop'
|
|
335
|
+
tabindex='-1'
|
|
336
|
+
aria-hidden={panel && table.panels[panel]?.backdrop ? false : true}
|
|
337
|
+
onclick={() => panel = undefined}
|
|
338
|
+
></button>
|
|
257
339
|
</div>
|
|
258
340
|
|
|
259
341
|
|
|
260
|
-
{@render content?.({ Column, Panel,
|
|
342
|
+
{@render content?.({ Column, Panel, get table() { return table }, get data() { return data } })}
|
|
261
343
|
|
|
262
344
|
|
|
263
345
|
|
|
264
346
|
<!---------------------------------------------------->
|
|
265
347
|
<style>
|
|
348
|
+
|
|
349
|
+
.row {
|
|
350
|
+
> .select {
|
|
351
|
+
display: block;
|
|
352
|
+
position: absolute;
|
|
353
|
+
z-index: 3;
|
|
354
|
+
opacity: 1;
|
|
355
|
+
left: 2px;
|
|
356
|
+
overflow: visible;
|
|
357
|
+
background-color: transparent;
|
|
358
|
+
transition: .15s ease;
|
|
359
|
+
> input {
|
|
360
|
+
width: 18px;
|
|
361
|
+
height: 18px;
|
|
362
|
+
border-radius: 1rem;
|
|
363
|
+
cursor: pointer;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
&.hover {
|
|
367
|
+
@starting-style {
|
|
368
|
+
opacity: 0;
|
|
369
|
+
left: -2px;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
a.row {
|
|
377
|
+
color: inherit;
|
|
378
|
+
text-decoration: inherit;
|
|
379
|
+
}
|
|
266
380
|
|
|
267
381
|
.table, .table * {
|
|
268
382
|
box-sizing: border-box;
|
|
383
|
+
background-color: inherit;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.backdrop {
|
|
387
|
+
position: absolute;
|
|
388
|
+
left: 0px;
|
|
389
|
+
top: 0px;
|
|
390
|
+
bottom: 0px;
|
|
391
|
+
right: 0px;
|
|
392
|
+
background-color: hsla(0, 0%, 0%, .3);
|
|
393
|
+
z-index: 3;
|
|
394
|
+
opacity: 1;
|
|
395
|
+
transition: .15s ease;
|
|
396
|
+
border: none;
|
|
397
|
+
outline: none;
|
|
398
|
+
cursor: pointer;
|
|
399
|
+
|
|
400
|
+
&[aria-hidden='true'] {
|
|
401
|
+
opacity: 0;
|
|
402
|
+
pointer-events: none;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.headers, .statusbar {
|
|
407
|
+
/* So that the scrollbar doesn't cause the headers/statusbar to shift */
|
|
408
|
+
padding-right: 11px;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.table {
|
|
412
|
+
color: var(--tably-color, hsl(0, 0%, 0%));
|
|
413
|
+
background-color: var(--tably-bg, hsl(0, 0%, 100%));
|
|
269
414
|
}
|
|
270
415
|
|
|
271
416
|
.sticky {
|
|
272
417
|
position: sticky;
|
|
273
|
-
left: 0px;
|
|
274
418
|
/* right: 100px; */
|
|
275
|
-
background-color: var(--tably-bg, hsl(0, 0%, 100%));
|
|
276
419
|
z-index: 1;
|
|
277
420
|
}
|
|
278
421
|
|
|
@@ -282,20 +425,18 @@
|
|
|
282
425
|
|
|
283
426
|
.headers > .column {
|
|
284
427
|
border-right: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
285
|
-
resize: horizontal;
|
|
286
428
|
overflow: hidden;
|
|
287
|
-
padding: var(--padding-y) 0;
|
|
429
|
+
padding: var(--tably-padding-y, .5rem) 0;
|
|
430
|
+
|
|
431
|
+
&.resizeable {
|
|
432
|
+
resize: horizontal;
|
|
433
|
+
}
|
|
288
434
|
}
|
|
289
435
|
|
|
290
436
|
.table {
|
|
291
|
-
--panel: 250px;
|
|
292
|
-
--padding-x: 1rem;
|
|
293
|
-
--padding-y: .5rem;
|
|
294
|
-
--gap: .25rem;
|
|
295
|
-
--header-height: 2.5rem;
|
|
296
|
-
|
|
297
437
|
display: grid;
|
|
298
438
|
height: 100%;
|
|
439
|
+
position: relative;
|
|
299
440
|
|
|
300
441
|
grid-template-areas:
|
|
301
442
|
'headers panel'
|
|
@@ -307,7 +448,7 @@
|
|
|
307
448
|
grid-template-rows: auto 1fr auto;
|
|
308
449
|
|
|
309
450
|
border: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
310
|
-
border-radius: .25rem;
|
|
451
|
+
border-radius: var(--tably-radius, .25rem);
|
|
311
452
|
|
|
312
453
|
max-height: 100%;
|
|
313
454
|
}
|
|
@@ -320,7 +461,6 @@
|
|
|
320
461
|
|
|
321
462
|
.headers > .column {
|
|
322
463
|
width: auto !important;
|
|
323
|
-
background-color: var(--tably-bg, hsl(0, 0%, 100%));
|
|
324
464
|
border-bottom: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
325
465
|
}
|
|
326
466
|
|
|
@@ -343,51 +483,52 @@
|
|
|
343
483
|
.statusbar {
|
|
344
484
|
grid-area: statusbar;
|
|
345
485
|
overflow: hidden;
|
|
486
|
+
background-color: var(--tably-statusbar, hsl(0, 0%, 98%));
|
|
346
487
|
}
|
|
347
488
|
|
|
348
489
|
.statusbar > .column {
|
|
349
|
-
background-color: var(--tably-bg-statusbar, hsl(0, 0%, 99%));
|
|
350
490
|
border-top: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
351
|
-
padding: calc(var(--padding-y) / 2) 0;
|
|
491
|
+
padding: calc(var(--tably-padding-y, .5rem) / 2) 0;
|
|
352
492
|
}
|
|
353
493
|
|
|
354
494
|
.headers, .row, .statusbar {
|
|
495
|
+
position: relative;
|
|
355
496
|
display: grid;
|
|
356
497
|
width: 100%;
|
|
357
498
|
height: 100%;
|
|
358
499
|
|
|
359
500
|
& > .column {
|
|
360
501
|
display: flex;
|
|
361
|
-
padding-left: var(--padding-x);
|
|
502
|
+
padding-left: var(--tably-padding-x, 1rem);
|
|
362
503
|
overflow: hidden;
|
|
363
504
|
}
|
|
364
505
|
|
|
365
506
|
& > *:last-child {
|
|
366
507
|
width: 100%;
|
|
367
|
-
padding-right: var(--padding-x);
|
|
508
|
+
padding-right: var(--tably-padding-x, 1rem);
|
|
368
509
|
}
|
|
369
510
|
}
|
|
370
511
|
|
|
371
|
-
|
|
372
|
-
padding-top: calc(var(--padding-y) + var(--
|
|
512
|
+
.row:first-child > * {
|
|
513
|
+
padding-top: calc(var(--tably-padding-y, .5rem) + calc(var(--tably-padding-y, .5rem) / 2));
|
|
514
|
+
}
|
|
515
|
+
.row:last-child > * {
|
|
516
|
+
padding-bottom: calc(var(--tably-padding-y, .5rem) + calc(var(--tably-padding-y, .5rem) / 2));
|
|
373
517
|
}
|
|
374
|
-
.row:nth-last-child(1) > * {
|
|
375
|
-
padding-bottom: calc(var(--padding-y) + var(--gap));
|
|
376
|
-
} */
|
|
377
518
|
|
|
378
519
|
.row > * {
|
|
379
|
-
padding: var(--
|
|
520
|
+
padding: calc(var(--tably-padding-y, .5rem) / 2) 0;
|
|
380
521
|
}
|
|
381
522
|
|
|
382
523
|
.panel {
|
|
383
524
|
position: relative;
|
|
384
525
|
grid-area: panel;
|
|
385
526
|
height: 100%;
|
|
386
|
-
background-color: var(--tably-bg, hsl(0, 0%, 100%));
|
|
387
527
|
|
|
388
528
|
border-left: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
389
529
|
scrollbar-gutter: stable both-edges;
|
|
390
530
|
scrollbar-width: thin;
|
|
531
|
+
z-index: 4;
|
|
391
532
|
|
|
392
533
|
> .panel-content {
|
|
393
534
|
position: absolute;
|
|
@@ -395,7 +536,7 @@
|
|
|
395
536
|
right: 0;
|
|
396
537
|
width: min-content;
|
|
397
538
|
overflow: auto;
|
|
398
|
-
padding: var(--padding-y) 0;
|
|
539
|
+
padding: var(--tably-padding-y, .5rem) 0;
|
|
399
540
|
}
|
|
400
541
|
}
|
|
401
542
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
2
|
export interface TableState<T extends Record<PropertyKey, any> = Record<PropertyKey, any>> {
|
|
3
3
|
columns: Record<string, TColumn<T, unknown>>;
|
|
4
|
-
panels: Record<string, TPanel
|
|
4
|
+
panels: Record<string, TPanel<T>>;
|
|
5
|
+
selected: T[] | null;
|
|
5
6
|
sortby?: string;
|
|
6
7
|
positions: {
|
|
7
8
|
sticky: string[];
|
|
@@ -9,7 +10,10 @@ export interface TableState<T extends Record<PropertyKey, any> = Record<Property
|
|
|
9
10
|
hidden: string[];
|
|
10
11
|
toggle(key: string): void;
|
|
11
12
|
};
|
|
13
|
+
readonly resizeable: boolean;
|
|
12
14
|
readonly data: T[];
|
|
15
|
+
/** Rows become anchors */
|
|
16
|
+
readonly href?: (item: T) => string;
|
|
13
17
|
addColumn(key: string, options: TColumn<T, unknown>): void;
|
|
14
18
|
removeColumn(key: string): void;
|
|
15
19
|
}
|
|
@@ -22,52 +26,68 @@ declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
|
|
|
22
26
|
content: Snippet<[context: {
|
|
23
27
|
Column: {
|
|
24
28
|
(internal: unknown, props: {
|
|
25
|
-
header
|
|
29
|
+
header?: Column<T_1, V>["header"];
|
|
26
30
|
row: Column<T_1, V>["row"];
|
|
27
31
|
statusbar?: Column<T_1, V>["statusbar"];
|
|
28
32
|
id: string;
|
|
29
33
|
sticky?: boolean;
|
|
30
34
|
sort?: boolean;
|
|
31
35
|
show?: boolean;
|
|
36
|
+
width?: number;
|
|
32
37
|
value?: Column<T_1, V>["options"]["value"];
|
|
33
38
|
sorting?: Column<T_1, V>["options"]["sorting"];
|
|
39
|
+
resizeable?: boolean;
|
|
34
40
|
}): {};
|
|
35
41
|
new (options: import("svelte").ComponentConstructorOptions<{
|
|
36
|
-
header
|
|
42
|
+
header?: Column<T_1, V>["header"];
|
|
37
43
|
row: Column<T_1, V>["row"];
|
|
38
44
|
statusbar?: Column<T_1, V>["statusbar"];
|
|
39
45
|
id: string;
|
|
40
46
|
sticky?: boolean;
|
|
41
47
|
sort?: boolean;
|
|
42
48
|
show?: boolean;
|
|
49
|
+
width?: number;
|
|
43
50
|
value?: Column<T_1, V>["options"]["value"];
|
|
44
51
|
sorting?: Column<T_1, V>["options"]["sorting"];
|
|
52
|
+
resizeable?: boolean;
|
|
45
53
|
}>): SvelteComponent<{
|
|
46
|
-
header
|
|
54
|
+
header?: Column<T_1, V>["header"];
|
|
47
55
|
row: Column<T_1, V>["row"];
|
|
48
56
|
statusbar?: Column<T_1, V>["statusbar"];
|
|
49
57
|
id: string;
|
|
50
58
|
sticky?: boolean;
|
|
51
59
|
sort?: boolean;
|
|
52
60
|
show?: boolean;
|
|
61
|
+
width?: number;
|
|
53
62
|
value?: Column<T_1, V>["options"]["value"];
|
|
54
63
|
sorting?: Column<T_1, V>["options"]["sorting"];
|
|
64
|
+
resizeable?: boolean;
|
|
55
65
|
}, {}, {}> & {
|
|
56
66
|
$$bindings?: ReturnType<() => "">;
|
|
57
67
|
};
|
|
58
68
|
z_$$bindings?: ReturnType<() => "">;
|
|
59
69
|
};
|
|
60
70
|
Panel: typeof Panel;
|
|
61
|
-
|
|
71
|
+
readonly table: TableState<T>;
|
|
72
|
+
readonly data: T[];
|
|
62
73
|
}]>;
|
|
63
74
|
panel?: string;
|
|
64
75
|
data?: T[] | undefined;
|
|
65
76
|
id?: string;
|
|
77
|
+
href?: ((item: T) => string) | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Can you change the width of the columns?
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
resizeable?: boolean;
|
|
83
|
+
selectable?: "hover" | "always" | "never";
|
|
66
84
|
};
|
|
67
85
|
events(): {};
|
|
68
86
|
slots(): {};
|
|
69
|
-
bindings(): "";
|
|
70
|
-
exports(): {
|
|
87
|
+
bindings(): "panel";
|
|
88
|
+
exports(): {
|
|
89
|
+
state: TableState<T>;
|
|
90
|
+
};
|
|
71
91
|
}
|
|
72
92
|
interface $$IsomorphicComponent {
|
|
73
93
|
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/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export default
|
|
1
|
+
export { default as default } from './Table.svelte';
|
|
2
|
+
export { default as Panel } from './Panel.svelte';
|
|
3
|
+
export { default as Column } from './Column.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export default
|
|
1
|
+
export { default as default } from './Table.svelte';
|
|
2
|
+
export { default as Panel } from './Panel.svelte';
|
|
3
|
+
export { default as Column } from './Column.svelte';
|
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.6",
|
|
4
4
|
"repository": "github:refzlund/svelte-tably",
|
|
5
5
|
"homepage": "https://github.com/Refzlund/svelte-tably",
|
|
6
6
|
"bugs": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"@sveltejs/kit": "^2.9.0",
|
|
12
12
|
"@sveltejs/package": "^2.0.0",
|
|
13
13
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
14
|
+
"floating-runes": "^1.0.0",
|
|
14
15
|
"publint": "^0.2.0",
|
|
16
|
+
"runic-reorder": "^1.0.0-next.1",
|
|
15
17
|
"svelte": "^5.0.0",
|
|
16
18
|
"svelte-check": "^4.0.0",
|
|
17
19
|
"typescript": "^5.0.0",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export interface Panel {
|
|
2
|
-
/** A darkened backdrop? */
|
|
3
|
-
backdrop: boolean;
|
|
4
|
-
content: Snippet<[table: TableState]>;
|
|
5
|
-
}
|
|
6
|
-
export declare class PanelTween {
|
|
7
|
-
#private;
|
|
8
|
-
current: number;
|
|
9
|
-
transitioning: boolean;
|
|
10
|
-
/** bind:clientWidth */
|
|
11
|
-
width: number;
|
|
12
|
-
set target(value: number);
|
|
13
|
-
constructor(cb: () => string | undefined);
|
|
14
|
-
}
|
|
15
|
-
import { type Snippet } from 'svelte';
|
|
16
|
-
import { type TableState } from './Table.svelte';
|
|
17
|
-
interface Props {
|
|
18
|
-
id: string;
|
|
19
|
-
/** A darkened backdrop? */
|
|
20
|
-
backdrop?: boolean;
|
|
21
|
-
children: Snippet<[table: TableState]>;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* This is a description, \
|
|
25
|
-
* on how to use this.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* <Component />
|
|
29
|
-
*/
|
|
30
|
-
declare const Panel: import("svelte").Component<Props, {}, "">;
|
|
31
|
-
type Panel = ReturnType<typeof Panel>;
|
|
32
|
-
export default Panel;
|
package/dist/Table/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as Table } from './Table.svelte';
|