svelte-tably 1.0.0-next.7 → 1.0.0-next.9
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 +5 -3
- package/dist/Column.svelte +110 -51
- package/dist/Column.svelte.d.ts +75 -30
- package/dist/Table.svelte +604 -258
- package/dist/Table.svelte.d.ts +51 -47
- package/dist/trigger.svelte.d.ts +10 -0
- package/dist/trigger.svelte.js +27 -0
- package/package.json +1 -1
package/dist/Table.svelte
CHANGED
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
|
|
9
9
|
-->
|
|
10
10
|
|
|
11
|
-
<script module lang=
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
<script module lang="ts">
|
|
12
|
+
export interface TableState<
|
|
13
|
+
T extends Record<PropertyKey, any> = Record<PropertyKey, any>
|
|
14
|
+
> {
|
|
15
|
+
columns: Record<string, ColumnState<T>>
|
|
15
16
|
panels: Record<string, TPanel<T>>
|
|
16
17
|
selected: T[] | null
|
|
17
18
|
sortby?: string
|
|
19
|
+
sortReverse: boolean
|
|
18
20
|
positions: {
|
|
19
21
|
sticky: string[]
|
|
20
22
|
scroll: string[]
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
readonly data: T[]
|
|
26
28
|
/** Rows become anchors */
|
|
27
29
|
readonly href?: (item: T) => string
|
|
28
|
-
addColumn(key: string, options:
|
|
30
|
+
addColumn(key: string, options: ColumnState<T>): void
|
|
29
31
|
removeColumn(key: string): void
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -33,21 +35,49 @@
|
|
|
33
35
|
return getContext<TableState<T>>('svelte5-table')
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
export type HeaderSelectCtx<T = any> = {
|
|
39
|
+
isSelected: boolean
|
|
40
|
+
/** The list of selected items */
|
|
41
|
+
readonly selected: T[]
|
|
42
|
+
/**
|
|
43
|
+
* See [MDN :indeterminate](https://developer.mozilla.org/en-US/docs/Web/CSS/:indeterminate)
|
|
44
|
+
*/
|
|
45
|
+
readonly indeterminate: boolean
|
|
46
|
+
}
|
|
37
47
|
|
|
38
|
-
<
|
|
48
|
+
export type RowSelectCtx<T = any> = {
|
|
49
|
+
readonly item: T
|
|
50
|
+
readonly row: RowCtx<unknown>
|
|
51
|
+
data: T[]
|
|
52
|
+
isSelected: boolean
|
|
53
|
+
}
|
|
54
|
+
</script>
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
import
|
|
56
|
+
<script lang="ts">
|
|
57
|
+
import { getContext, onMount, setContext, tick, untrack, type Snippet } from 'svelte'
|
|
58
|
+
import Column, { type ColumnProps, type RowCtx, type ColumnState } from './Column.svelte'
|
|
42
59
|
import Panel, { PanelTween, type Panel as TPanel } from './Panel.svelte'
|
|
43
60
|
import { fly } from 'svelte/transition'
|
|
44
61
|
import { sineInOut } from 'svelte/easing'
|
|
45
|
-
import { get } from 'svelte/store'
|
|
46
62
|
import { on } from 'svelte/events'
|
|
47
|
-
|
|
63
|
+
|
|
64
|
+
type T = $$Generic<Record<PropertyKey, unknown>>
|
|
65
|
+
|
|
66
|
+
type ConstructorReturnType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer K ? K : never
|
|
67
|
+
type ConstructorParams<T extends new (...args: any[]) => any> = T extends new (...args: infer K) => any ? K : never
|
|
68
|
+
|
|
69
|
+
type ContentCtx<T extends Record<PropertyKey, unknown>> = {
|
|
70
|
+
Column: {
|
|
71
|
+
new <V>(...args: ConstructorParams<typeof Column<T, V>>): ConstructorReturnType<typeof Column<T, V>>
|
|
72
|
+
<V>(...args: Parameters<typeof Column<T, V>>): ReturnType<typeof Column<T, V>>
|
|
73
|
+
}
|
|
74
|
+
Panel: typeof Panel
|
|
75
|
+
readonly table: TableState<T>
|
|
76
|
+
readonly data: T[]
|
|
77
|
+
}
|
|
48
78
|
|
|
49
79
|
interface Props {
|
|
50
|
-
content: Snippet<[context:
|
|
80
|
+
content: Snippet<[context: ContentCtx<T>]>
|
|
51
81
|
|
|
52
82
|
panel?: string
|
|
53
83
|
data?: T[]
|
|
@@ -56,79 +86,103 @@
|
|
|
56
86
|
/**
|
|
57
87
|
* Can you change the width of the columns?
|
|
58
88
|
* @default true
|
|
59
|
-
|
|
89
|
+
*/
|
|
60
90
|
resizeable?: boolean
|
|
61
|
-
|
|
91
|
+
|
|
92
|
+
selected?: T[]
|
|
93
|
+
select?:
|
|
94
|
+
| boolean
|
|
95
|
+
| {
|
|
96
|
+
/**
|
|
97
|
+
* The style, in which the selection is shown
|
|
98
|
+
*
|
|
99
|
+
* NOTE: If using `edge` | 'side', "show" will always be `hover`. This is due to
|
|
100
|
+
* an inconsistency/limitation of matching the scroll between the selection div and the rows.
|
|
101
|
+
*
|
|
102
|
+
* @default 'column'
|
|
103
|
+
*/
|
|
104
|
+
style?: 'column'
|
|
105
|
+
/**
|
|
106
|
+
* When to show the row-select, when not selected?
|
|
107
|
+
* @default 'hover'
|
|
108
|
+
*/
|
|
109
|
+
show?: 'hover' | 'always' | 'never'
|
|
110
|
+
/**
|
|
111
|
+
* Custom snippet
|
|
112
|
+
*/
|
|
113
|
+
headerSnippet?: Snippet<[context: HeaderSelectCtx]>
|
|
114
|
+
rowSnippet?: Snippet<[context: RowSelectCtx<T>]>
|
|
115
|
+
}
|
|
116
|
+
// | {
|
|
117
|
+
// /**
|
|
118
|
+
// * The style, in which the selection is shown
|
|
119
|
+
// *
|
|
120
|
+
// * NOTE: If using `edge` | 'side', "show" will always be `hover`. This is due to
|
|
121
|
+
// * an inconsistency/limitation of matching the scroll between the selection div and the rows.
|
|
122
|
+
// *
|
|
123
|
+
// * @default 'column'
|
|
124
|
+
// */
|
|
125
|
+
// style?: 'edge' | 'side'
|
|
126
|
+
// /**
|
|
127
|
+
// * When to show the row-select, when not selected?
|
|
128
|
+
// * @default 'hover'
|
|
129
|
+
// */
|
|
130
|
+
// show?: 'hover'
|
|
131
|
+
// /**
|
|
132
|
+
// * Custom snippet
|
|
133
|
+
// */
|
|
134
|
+
// snippet?: Snippet<[context: { item: T, data: T[], selected: boolean }]>
|
|
135
|
+
// }
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
ordered?: {
|
|
139
|
+
style?: 'column' | 'side' // combine with select if both use 'column'
|
|
140
|
+
show?: 'hover' | 'always'
|
|
141
|
+
// snippet?: Snippet<[context: { item: T, data: T[], selected: boolean }]>
|
|
142
|
+
}
|
|
143
|
+
*/
|
|
62
144
|
}
|
|
63
145
|
|
|
64
146
|
let {
|
|
65
147
|
content,
|
|
66
|
-
|
|
148
|
+
selected = $bindable([]),
|
|
67
149
|
panel = $bindable(),
|
|
68
150
|
data: _data = [],
|
|
69
|
-
id = Array.from({length: 12}, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join(''),
|
|
151
|
+
id = Array.from({ length: 12 }, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join(''),
|
|
70
152
|
href,
|
|
71
153
|
resizeable = true,
|
|
72
|
-
|
|
154
|
+
select
|
|
73
155
|
}: Props = $props()
|
|
74
|
-
|
|
75
|
-
const data = $derived([..._data])
|
|
76
|
-
|
|
77
|
-
const elements = $state({}) as Record<'headers' | 'statusbar' | 'rows', HTMLElement>
|
|
78
156
|
|
|
157
|
+
let mounted = $state(false)
|
|
158
|
+
onMount(() => (mounted = true))
|
|
79
159
|
|
|
80
|
-
|
|
81
|
-
let scrollTop = $state(0)
|
|
82
|
-
let viewportHeight = $state(0)
|
|
83
|
-
|
|
84
|
-
let heightPerItem = $derived.by(() => {
|
|
85
|
-
data
|
|
86
|
-
if(!elements.rows)
|
|
87
|
-
return 8
|
|
88
|
-
const result = elements.rows.scrollHeight / elements.rows.childNodes.length
|
|
89
|
-
return result
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
let renderItemLength = $derived(Math.ceil(Math.max(30, (viewportHeight / heightPerItem) * 2)))
|
|
160
|
+
const data = $derived([..._data])
|
|
93
161
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
index,
|
|
111
|
-
end
|
|
112
|
-
)
|
|
162
|
+
const elements = $state({}) as Record<
|
|
163
|
+
'headers' | 'statusbar' | 'rows' | 'virtualTop' | 'virtualBottom' | 'selects',
|
|
164
|
+
HTMLElement
|
|
165
|
+
>
|
|
166
|
+
|
|
167
|
+
let cols: TableState<T>['columns'] = $state({})
|
|
168
|
+
let positions: TableState<T>['positions'] = $state({
|
|
169
|
+
fixed: [],
|
|
170
|
+
sticky: [],
|
|
171
|
+
scroll: [],
|
|
172
|
+
hidden: [],
|
|
173
|
+
toggle(key) {
|
|
174
|
+
if (table.positions.hidden.includes(key))
|
|
175
|
+
table.positions.hidden = table.positions.hidden.filter((column) => column !== key)
|
|
176
|
+
else table.positions.hidden.push(key)
|
|
177
|
+
}
|
|
113
178
|
})
|
|
114
|
-
// * --- Virtualization --- *
|
|
115
|
-
|
|
116
179
|
|
|
117
180
|
const table: TableState<T> = $state({
|
|
118
|
-
columns:
|
|
119
|
-
selected
|
|
181
|
+
columns: cols,
|
|
182
|
+
selected,
|
|
120
183
|
panels: {},
|
|
121
|
-
positions
|
|
122
|
-
|
|
123
|
-
scroll: [],
|
|
124
|
-
hidden: [],
|
|
125
|
-
toggle(key) {
|
|
126
|
-
if(table.positions.hidden.includes(key))
|
|
127
|
-
table.positions.hidden = table.positions.hidden.filter(column => column !== key)
|
|
128
|
-
else
|
|
129
|
-
table.positions.hidden.push(key)
|
|
130
|
-
}
|
|
131
|
-
},
|
|
184
|
+
positions,
|
|
185
|
+
sortReverse: false,
|
|
132
186
|
get href() {
|
|
133
187
|
return href
|
|
134
188
|
},
|
|
@@ -141,260 +195,547 @@
|
|
|
141
195
|
addColumn(key, column) {
|
|
142
196
|
table.columns[key] = column
|
|
143
197
|
|
|
144
|
-
if(column.defaults.sort)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
table.positions.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
198
|
+
if (column.defaults.sort) sortBy(key)
|
|
199
|
+
|
|
200
|
+
if (column.fixed) {
|
|
201
|
+
// @ts-expect-error
|
|
202
|
+
table.positions.fixed.push(key)
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!column.defaults.show) table.positions.hidden.push(key)
|
|
207
|
+
|
|
208
|
+
if (column.defaults.sticky) table.positions.sticky.push(key)
|
|
209
|
+
else table.positions.scroll.push(key)
|
|
154
210
|
},
|
|
155
211
|
removeColumn(key) {
|
|
156
212
|
delete table.columns[key]
|
|
157
|
-
|
|
158
|
-
table.positions.
|
|
159
|
-
table.positions.
|
|
213
|
+
// @ts-expect-error fixed is not typed
|
|
214
|
+
table.positions.fixed = table.positions.fixed.filter((column) => column !== key)
|
|
215
|
+
table.positions.sticky = table.positions.sticky.filter((column) => column !== key)
|
|
216
|
+
table.positions.scroll = table.positions.scroll.filter((column) => column !== key)
|
|
217
|
+
table.positions.hidden = table.positions.hidden.filter((column) => column !== key)
|
|
160
218
|
}
|
|
161
219
|
})
|
|
162
220
|
|
|
163
221
|
setContext('svelte5-table', table)
|
|
164
222
|
|
|
165
223
|
// * --- *
|
|
224
|
+
|
|
225
|
+
// * --- Virtualization --- *
|
|
226
|
+
// #region Virtualization
|
|
227
|
+
let scrollTop = $state(0)
|
|
228
|
+
let viewportHeight = $state(0)
|
|
229
|
+
|
|
230
|
+
let heightPerItem = $state(8)
|
|
231
|
+
|
|
232
|
+
const spacing = () => viewportHeight / 2
|
|
233
|
+
|
|
234
|
+
let virtualTop = $derived.by(() => {
|
|
235
|
+
let result = Math.max(scrollTop - spacing(), 0)
|
|
236
|
+
result -= result % heightPerItem
|
|
237
|
+
return result
|
|
238
|
+
})
|
|
239
|
+
let virtualBottom = $derived.by(() => {
|
|
240
|
+
let result = heightPerItem * data.length - virtualTop - spacing() * 4
|
|
241
|
+
result = Math.max(result, 0)
|
|
242
|
+
return result
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
let renderItemLength = $derived(Math.ceil(Math.max(30, (viewportHeight / heightPerItem) * 2)))
|
|
246
|
+
|
|
247
|
+
/** The area of data being rendered */
|
|
248
|
+
let area = $derived.by(() => {
|
|
249
|
+
table.sortReverse
|
|
250
|
+
table.sortby
|
|
251
|
+
const index = virtualTop / heightPerItem || 0
|
|
252
|
+
const end = index + renderItemLength
|
|
253
|
+
const result = data.slice(index, end)
|
|
254
|
+
return result
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
function calculateHeightPerItem() {
|
|
258
|
+
if (!elements.rows) {
|
|
259
|
+
heightPerItem = 8
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
tick().then(() => {
|
|
263
|
+
const firstRow = elements.rows.children[0].getBoundingClientRect().top
|
|
264
|
+
const lastRow =
|
|
265
|
+
elements.rows.children[elements.rows.children.length - 1].getBoundingClientRect().bottom
|
|
266
|
+
heightPerItem = (lastRow - firstRow) / area.length
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
$effect(() => {
|
|
271
|
+
data
|
|
272
|
+
untrack(calculateHeightPerItem)
|
|
273
|
+
})
|
|
274
|
+
// #endregion
|
|
275
|
+
// * --- Virtualization --- *
|
|
276
|
+
|
|
166
277
|
|
|
278
|
+
|
|
279
|
+
function sortBy(column: string) {
|
|
280
|
+
const { sorting, value } = table.columns[column]!.options
|
|
281
|
+
if(!sorting || !value) return
|
|
282
|
+
|
|
283
|
+
if (table.sortby === column) {
|
|
284
|
+
table.sortReverse = !table.sortReverse
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
table.sortReverse = false
|
|
288
|
+
table.sortby = column
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function sortAction(node: HTMLElement, column: string) {
|
|
292
|
+
$effect(() => on(node, 'click', () => sortBy(column)))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function sortTable() {
|
|
296
|
+
if (!table.sortby) return
|
|
297
|
+
const column = table.columns[table.sortby]
|
|
298
|
+
let { sorting, value } = column.options
|
|
299
|
+
if(!sorting || !value) return
|
|
300
|
+
if(sorting === true) {
|
|
301
|
+
sorting = (a, b) => String(a).localeCompare(String(b))
|
|
302
|
+
}
|
|
303
|
+
if(table.sortReverse) {
|
|
304
|
+
data.sort((a, b) => sorting(value(b), value(a)))
|
|
305
|
+
} else {
|
|
306
|
+
data.sort((a, b) => sorting(value(a), value(b)))
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
$effect.pre(() => {
|
|
311
|
+
data
|
|
312
|
+
table.sortby
|
|
313
|
+
table.sortReverse
|
|
314
|
+
untrack(sortTable)
|
|
315
|
+
})
|
|
316
|
+
|
|
167
317
|
const panelTween = new PanelTween(() => panel, 24)
|
|
168
318
|
|
|
169
319
|
let hoveredRow: T | null = $state(null)
|
|
170
320
|
|
|
171
321
|
/** Order of columns */
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
322
|
+
const fixed = $derived(
|
|
323
|
+
// @ts-expect-error
|
|
324
|
+
positions.fixed
|
|
325
|
+
) as string[]
|
|
326
|
+
const hidden = $derived(positions.hidden)
|
|
327
|
+
const notHidden = (key: string) => !positions.hidden.includes(key)
|
|
328
|
+
const sticky = $derived(positions.sticky.filter(notHidden))
|
|
329
|
+
const scrolled = $derived(positions.scroll.filter(notHidden))
|
|
330
|
+
const columns = $derived([...fixed, ...sticky, ...scrolled])
|
|
176
331
|
|
|
177
332
|
/** Width of each column */
|
|
178
333
|
const columnWidths = $state({}) as Record<string, number>
|
|
179
334
|
|
|
180
|
-
const getWidth = (key: string, def: number = 150) =>
|
|
335
|
+
const getWidth = (key: string, def: number = 150) =>
|
|
336
|
+
columnWidths[key] || table.columns[key]?.defaults.width || def
|
|
181
337
|
|
|
182
338
|
/** grid-template-columns for widths */
|
|
183
339
|
const style = $derived.by(() => {
|
|
340
|
+
if (!mounted) return ''
|
|
184
341
|
const templateColumns = `
|
|
185
342
|
#${id} > .headers,
|
|
186
|
-
#${id} >
|
|
187
|
-
#${id} >
|
|
343
|
+
#${id} > tbody > .row,
|
|
344
|
+
#${id} > tfoot > tr,
|
|
188
345
|
#${id} > .content > .virtual.bottom {
|
|
189
|
-
grid-template-columns: ${
|
|
190
|
-
|
|
346
|
+
grid-template-columns: ${columns
|
|
347
|
+
.map((key, i, arr) => {
|
|
191
348
|
const width = getWidth(key)
|
|
192
|
-
if(i === arr.length - 1)
|
|
193
|
-
return `minmax(${width}px, 1fr)`
|
|
349
|
+
if (i === arr.length - 1) return `minmax(${width}px, 1fr)`
|
|
194
350
|
return `${width}px`
|
|
195
|
-
})
|
|
196
|
-
|
|
351
|
+
})
|
|
352
|
+
.join(' ')};
|
|
197
353
|
}
|
|
198
354
|
`
|
|
199
|
-
|
|
355
|
+
|
|
200
356
|
let sum = 0
|
|
201
|
-
const stickyLeft =
|
|
202
|
-
|
|
203
|
-
|
|
357
|
+
const stickyLeft = [...fixed, ...sticky]
|
|
358
|
+
.map((key, i, arr) => {
|
|
359
|
+
sum += getWidth(arr[i - 1], i === 0 ? 0 : undefined)
|
|
360
|
+
return `
|
|
204
361
|
#${id} .column.sticky[data-column='${key}'] {
|
|
205
362
|
left: ${sum}px;
|
|
206
363
|
}
|
|
207
|
-
|
|
208
|
-
|
|
364
|
+
`
|
|
365
|
+
})
|
|
366
|
+
.join('')
|
|
209
367
|
|
|
210
368
|
return templateColumns + stickyLeft
|
|
211
369
|
})
|
|
212
|
-
|
|
370
|
+
|
|
213
371
|
function observeColumnWidth(node: HTMLDivElement, isHeader = false) {
|
|
214
|
-
if(!isHeader) return
|
|
372
|
+
if (!isHeader) return
|
|
215
373
|
|
|
216
374
|
const key = node.getAttribute('data-column')!
|
|
217
375
|
node.style.width = getWidth(key) + 'px'
|
|
218
376
|
|
|
219
|
-
const observer = new MutationObserver(() =>
|
|
377
|
+
const observer = new MutationObserver(() => {
|
|
378
|
+
columnWidths[key] = parseFloat(node.style.width)
|
|
379
|
+
})
|
|
220
380
|
|
|
221
|
-
observer.observe(node, {attributes: true})
|
|
381
|
+
observer.observe(node, { attributes: true })
|
|
222
382
|
return { destroy: () => observer.disconnect() }
|
|
223
383
|
}
|
|
224
384
|
|
|
225
|
-
function onscroll(
|
|
226
|
-
const target =
|
|
227
|
-
if(target.scrollTop !== scrollTop) {
|
|
228
|
-
scrollTop = target
|
|
385
|
+
async function onscroll() {
|
|
386
|
+
const target = elements.rows
|
|
387
|
+
if (target.scrollTop !== scrollTop) {
|
|
388
|
+
scrollTop = target?.scrollTop ?? scrollTop
|
|
229
389
|
}
|
|
230
|
-
|
|
231
|
-
if(
|
|
390
|
+
|
|
391
|
+
if (elements.selects) {
|
|
392
|
+
elements.selects.scrollTop = target?.scrollTop
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (!elements.headers) return
|
|
232
396
|
elements.headers.scrollLeft = target.scrollLeft
|
|
233
397
|
elements.statusbar.scrollLeft = target.scrollLeft
|
|
234
398
|
}
|
|
235
399
|
|
|
236
|
-
export {
|
|
237
|
-
table as state
|
|
238
|
-
}
|
|
239
|
-
|
|
400
|
+
export { selected, positions, data, href, cols as columns }
|
|
240
401
|
</script>
|
|
402
|
+
|
|
241
403
|
<!---------------------------------------------------->
|
|
242
404
|
|
|
243
405
|
<svelte:head>
|
|
244
406
|
{@html `<style>${style}</style>`}
|
|
245
407
|
</svelte:head>
|
|
246
408
|
|
|
409
|
+
{#snippet chevronSnippet(reversed: boolean)}
|
|
410
|
+
<svg
|
|
411
|
+
class='sorting-icon'
|
|
412
|
+
class:reversed
|
|
413
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
414
|
+
width="16"
|
|
415
|
+
height="16"
|
|
416
|
+
viewBox="0 0 16 16"
|
|
417
|
+
style='margin: auto; margin-right: var(--tably-padding-x, 1rem);'
|
|
418
|
+
>
|
|
419
|
+
<path
|
|
420
|
+
fill="currentColor"
|
|
421
|
+
d="M3.2 5.74a.75.75 0 0 1 1.06-.04L8 9.227L11.74 5.7a.75.75 0 1 1 1.02 1.1l-4.25 4a.75.75 0 0 1-1.02 0l-4.25-4a.75.75 0 0 1-.04-1.06"
|
|
422
|
+
/>
|
|
423
|
+
</svg>
|
|
424
|
+
{/snippet}
|
|
425
|
+
|
|
247
426
|
{#snippet columnsSnippet(
|
|
248
|
-
renderable: (column: string) => Snippet<[arg0?: any, arg1?: any]> | undefined,
|
|
427
|
+
renderable: (column: string) => Snippet<[arg0?: any, arg1?: any]> | undefined,
|
|
249
428
|
arg: null | ((column: string) => any[]) = null,
|
|
250
429
|
isHeader = false
|
|
251
430
|
)}
|
|
252
|
-
{#each
|
|
253
|
-
{#if !
|
|
431
|
+
{#each fixed as column, i (column)}
|
|
432
|
+
{#if !hidden.includes(column)}
|
|
254
433
|
{@const args = arg ? arg(column) : []}
|
|
255
|
-
|
|
256
|
-
|
|
434
|
+
{@const sortable = isHeader && table.columns[column]!.options.sorting}
|
|
435
|
+
{@const sortClick = isHeader ? sortAction : ()=>{}}
|
|
436
|
+
<svelte:element
|
|
437
|
+
this={isHeader ? 'th' : 'td'}
|
|
438
|
+
class="column sticky fixed"
|
|
439
|
+
data-column={column}
|
|
440
|
+
class:header={isHeader}
|
|
441
|
+
class:sortable={sortable}
|
|
442
|
+
use:sortClick={column}
|
|
443
|
+
>
|
|
444
|
+
{@render renderable(column)?.(args[0], args[1])}
|
|
445
|
+
{#if isHeader && table.sortby === column && sortable}
|
|
446
|
+
{@render chevronSnippet(table.sortReverse)}
|
|
447
|
+
{/if}
|
|
448
|
+
</svelte:element>
|
|
449
|
+
{/if}
|
|
450
|
+
{/each}
|
|
451
|
+
{#each sticky as column, i (column)}
|
|
452
|
+
{#if !hidden.includes(column)}
|
|
453
|
+
{@const args = arg ? arg(column) : []}
|
|
454
|
+
{@const sortable = isHeader && table.columns[column]!.options.sorting}
|
|
455
|
+
{@const sortClick = isHeader ? sortAction : ()=>{}}
|
|
456
|
+
<svelte:element
|
|
457
|
+
this={isHeader ? 'th' : 'td'}
|
|
458
|
+
class="column sticky"
|
|
257
459
|
use:observeColumnWidth={isHeader}
|
|
258
460
|
data-column={column}
|
|
259
|
-
class:
|
|
260
|
-
class:
|
|
461
|
+
class:header={isHeader}
|
|
462
|
+
class:resizeable={isHeader && table.columns[column].options.resizeable && table.resizeable}
|
|
463
|
+
class:border={i == sticky.length - 1}
|
|
464
|
+
class:sortable={sortable}
|
|
465
|
+
use:sortClick={column}
|
|
261
466
|
>
|
|
262
467
|
{@render renderable(column)?.(args[0], args[1])}
|
|
263
|
-
|
|
468
|
+
{#if isHeader && table.sortby === column && sortable}
|
|
469
|
+
{@render chevronSnippet(table.sortReverse)}
|
|
470
|
+
{/if}
|
|
471
|
+
</svelte:element>
|
|
264
472
|
{/if}
|
|
265
473
|
{/each}
|
|
266
|
-
{#each
|
|
267
|
-
{#if !
|
|
474
|
+
{#each scrolled as column, i (column)}
|
|
475
|
+
{#if !hidden.includes(column)}
|
|
268
476
|
{@const args = arg ? arg(column) : []}
|
|
269
|
-
|
|
270
|
-
|
|
477
|
+
{@const sortable = isHeader && table.columns[column]!.options.sorting}
|
|
478
|
+
{@const sortClick = isHeader ? sortAction : ()=>{}}
|
|
479
|
+
<svelte:element
|
|
480
|
+
this={isHeader ? 'th' : 'td'}
|
|
481
|
+
class="column"
|
|
271
482
|
data-column={column}
|
|
272
483
|
use:observeColumnWidth={isHeader}
|
|
273
|
-
class:resizeable={table.columns[column].options.resizeable && table.resizeable}
|
|
484
|
+
class:resizeable={isHeader && table.columns[column].options.resizeable && table.resizeable}
|
|
485
|
+
class:sortable={sortable}
|
|
486
|
+
use:sortClick={column}
|
|
274
487
|
>
|
|
275
488
|
{@render renderable(column)?.(args[0], args[1])}
|
|
276
|
-
|
|
489
|
+
{#if isHeader && table.sortby === column && sortable}
|
|
490
|
+
{@render chevronSnippet(table.sortReverse)}
|
|
491
|
+
{/if}
|
|
492
|
+
</svelte:element>
|
|
277
493
|
{/if}
|
|
278
494
|
{/each}
|
|
279
495
|
{/snippet}
|
|
280
496
|
|
|
281
|
-
<
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
497
|
+
<table
|
|
498
|
+
{id}
|
|
499
|
+
class="table svelte-tably"
|
|
500
|
+
style="--t: {virtualTop}px; --b: {virtualBottom}px;"
|
|
501
|
+
aria-rowcount={data.length}
|
|
502
|
+
>
|
|
503
|
+
<thead class="headers" bind:this={elements.headers}>
|
|
504
|
+
{@render columnsSnippet(
|
|
505
|
+
(column) => table.columns[column]?.header,
|
|
506
|
+
() => [true],
|
|
507
|
+
true
|
|
508
|
+
)}
|
|
509
|
+
</thead>
|
|
510
|
+
|
|
511
|
+
<tbody class="content" bind:this={elements.rows} onscrollcapture={onscroll} bind:clientHeight={viewportHeight}>
|
|
512
|
+
{#each area as item, i (item)}
|
|
513
|
+
{@const props = table.href ? { href: table.href(item) } : {}}
|
|
514
|
+
{@const index = data.indexOf(item) + 1}
|
|
515
|
+
<svelte:element
|
|
516
|
+
this={table.href ? 'a' : 'tr'}
|
|
517
|
+
class="row"
|
|
518
|
+
class:hover={hoveredRow === item}
|
|
519
|
+
class:selected={table.selected?.includes(item)}
|
|
520
|
+
class:first={i === 0}
|
|
521
|
+
class:last={i === area.length - 1}
|
|
522
|
+
{...props}
|
|
523
|
+
aria-rowindex={index}
|
|
524
|
+
onpointerenter={() => (hoveredRow = item)}
|
|
525
|
+
onpointerleave={() => (hoveredRow = null)}
|
|
526
|
+
>
|
|
527
|
+
{@render columnsSnippet(
|
|
528
|
+
(column) => table.columns[column]!.row,
|
|
529
|
+
(column) => {
|
|
530
|
+
const col = table.columns[column]!
|
|
531
|
+
return [
|
|
532
|
+
item,
|
|
533
|
+
{
|
|
534
|
+
get index() {
|
|
535
|
+
return index - 1
|
|
536
|
+
},
|
|
537
|
+
get value() {
|
|
538
|
+
return col.options.value ? col.options.value(item) : undefined
|
|
539
|
+
},
|
|
540
|
+
get isHovered() {
|
|
541
|
+
return hoveredRow === item
|
|
542
|
+
},
|
|
543
|
+
get selected() {
|
|
544
|
+
return table.selected?.includes(item)
|
|
545
|
+
},
|
|
546
|
+
set selected(value) {
|
|
547
|
+
value ?
|
|
548
|
+
table.selected!.push(item)
|
|
549
|
+
: table.selected!.splice(table.selected!.indexOf(item), 1)
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
]
|
|
553
|
+
}
|
|
554
|
+
)}
|
|
555
|
+
</svelte:element>
|
|
556
|
+
{/each}
|
|
557
|
+
</tbody>
|
|
558
|
+
|
|
559
|
+
<tfoot class="statusbar" bind:this={elements.statusbar}>
|
|
560
|
+
<tr>
|
|
561
|
+
{@render columnsSnippet((column) => table.columns[column]?.statusbar)}
|
|
562
|
+
</tr>
|
|
563
|
+
</tfoot>
|
|
564
|
+
|
|
565
|
+
<caption
|
|
566
|
+
class="panel"
|
|
567
|
+
style="width: {panelTween.current}px;"
|
|
568
|
+
style:overflow={panelTween.transitioning ? 'hidden' : 'auto'}
|
|
569
|
+
>
|
|
334
570
|
{#if panel && panel in table.panels}
|
|
335
|
-
<div
|
|
336
|
-
class=
|
|
571
|
+
<div
|
|
572
|
+
class="panel-content"
|
|
337
573
|
bind:clientWidth={panelTween.width}
|
|
338
|
-
in:fly={{ x: 100, easing: sineInOut, duration:300 }}
|
|
339
|
-
out:fly={{ x:100, duration:200, easing: sineInOut }}
|
|
574
|
+
in:fly={{ x: 100, easing: sineInOut, duration: 300 }}
|
|
575
|
+
out:fly={{ x: 100, duration: 200, easing: sineInOut }}
|
|
340
576
|
>
|
|
341
|
-
{@render table.panels[panel].content({
|
|
577
|
+
{@render table.panels[panel].content({
|
|
578
|
+
get table() {
|
|
579
|
+
return table
|
|
580
|
+
},
|
|
581
|
+
get data() {
|
|
582
|
+
return data
|
|
583
|
+
}
|
|
584
|
+
})}
|
|
342
585
|
</div>
|
|
343
586
|
{/if}
|
|
344
|
-
</
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
{@render content?.({ Column, Panel, get table() { return table }, get data() { return data } })}
|
|
587
|
+
</caption>
|
|
588
|
+
<caption class="backdrop" aria-hidden={panel && table.panels[panel]?.backdrop ? false : true}>
|
|
589
|
+
<button aria-label="Panel backdrop" tabindex="-1" onclick={() => (panel = undefined)}></button>
|
|
590
|
+
</caption>
|
|
591
|
+
</table>
|
|
592
|
+
|
|
593
|
+
{#snippet headerSelected(ctx: HeaderSelectCtx<T>)}
|
|
594
|
+
<input type="checkbox" indeterminate={ctx.indeterminate} bind:checked={ctx.isSelected} />
|
|
595
|
+
{/snippet}
|
|
356
596
|
|
|
597
|
+
{#snippet rowSelected(ctx: RowSelectCtx<T>)}
|
|
598
|
+
<input type="checkbox" bind:checked={ctx.isSelected} />
|
|
599
|
+
{/snippet}
|
|
357
600
|
|
|
601
|
+
{#if select}
|
|
602
|
+
{@const {
|
|
603
|
+
show = 'hover',
|
|
604
|
+
style = 'column',
|
|
605
|
+
rowSnippet = rowSelected,
|
|
606
|
+
headerSnippet = headerSelected
|
|
607
|
+
} = typeof select === 'boolean' ? {} : select}
|
|
608
|
+
{#if show !== 'never'}
|
|
609
|
+
<Column id="__fixed" {table} fixed width={56} resizeable={false}>
|
|
610
|
+
{#snippet header()}
|
|
611
|
+
<div class="__fixed">
|
|
612
|
+
{@render headerSnippet({
|
|
613
|
+
get isSelected() {
|
|
614
|
+
return table.data.length === table.selected?.length
|
|
615
|
+
},
|
|
616
|
+
set isSelected(value) {
|
|
617
|
+
if (value) {
|
|
618
|
+
table.selected = table.data
|
|
619
|
+
} else {
|
|
620
|
+
table.selected = []
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
get selected() {
|
|
624
|
+
return table.selected!
|
|
625
|
+
},
|
|
626
|
+
get indeterminate() {
|
|
627
|
+
return (table.selected?.length || 0) > 0 && table.data.length !== table.selected?.length
|
|
628
|
+
}
|
|
629
|
+
})}
|
|
630
|
+
</div>
|
|
631
|
+
{/snippet}
|
|
632
|
+
{#snippet row(item, row)}
|
|
633
|
+
<div class="__fixed">
|
|
634
|
+
{#if row.selected || show === 'always' || (row.isHovered && show === 'hover')}
|
|
635
|
+
{@render rowSnippet({
|
|
636
|
+
get isSelected() {
|
|
637
|
+
return row.selected
|
|
638
|
+
},
|
|
639
|
+
set isSelected(value) {
|
|
640
|
+
row.selected = value
|
|
641
|
+
},
|
|
642
|
+
get row() {
|
|
643
|
+
return row
|
|
644
|
+
},
|
|
645
|
+
get item() {
|
|
646
|
+
return item
|
|
647
|
+
},
|
|
648
|
+
get data() {
|
|
649
|
+
return table.data
|
|
650
|
+
}
|
|
651
|
+
})}
|
|
652
|
+
{/if}
|
|
653
|
+
</div>
|
|
654
|
+
{/snippet}
|
|
655
|
+
</Column>
|
|
656
|
+
{/if}
|
|
657
|
+
{/if}
|
|
658
|
+
|
|
659
|
+
{@render content?.({
|
|
660
|
+
Column,
|
|
661
|
+
Panel,
|
|
662
|
+
get table() {
|
|
663
|
+
return table
|
|
664
|
+
},
|
|
665
|
+
get data() {
|
|
666
|
+
return data
|
|
667
|
+
}
|
|
668
|
+
})}
|
|
358
669
|
|
|
359
670
|
<!---------------------------------------------------->
|
|
360
671
|
<style>
|
|
672
|
+
.svelte-tably *,
|
|
673
|
+
.svelte-tably {
|
|
674
|
+
box-sizing: border-box;
|
|
675
|
+
background-color: inherit;
|
|
676
|
+
}
|
|
361
677
|
|
|
362
|
-
.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
z-index: 3;
|
|
367
|
-
opacity: 1;
|
|
368
|
-
left: 2px;
|
|
369
|
-
overflow: visible;
|
|
370
|
-
background-color: transparent;
|
|
371
|
-
transition: .15s ease;
|
|
372
|
-
> input {
|
|
373
|
-
width: 18px;
|
|
374
|
-
height: 18px;
|
|
375
|
-
border-radius: 1rem;
|
|
376
|
-
cursor: pointer;
|
|
377
|
-
}
|
|
678
|
+
.svelte-tably {
|
|
679
|
+
position: relative;
|
|
680
|
+
overflow: visible;
|
|
681
|
+
}
|
|
378
682
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
683
|
+
input[type='checkbox'] {
|
|
684
|
+
width: 18px;
|
|
685
|
+
height: 18px;
|
|
686
|
+
cursor: pointer;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.sorting-icon {
|
|
690
|
+
transition: transform .15s ease;
|
|
691
|
+
transform: rotateZ(0deg);
|
|
692
|
+
&.reversed {
|
|
693
|
+
transform: rotateZ(-180deg);
|
|
385
694
|
}
|
|
386
695
|
}
|
|
387
|
-
|
|
696
|
+
|
|
697
|
+
.__fixed {
|
|
698
|
+
display: flex;
|
|
699
|
+
align-items: center;
|
|
700
|
+
justify-content: center;
|
|
701
|
+
gap: 0.5rem;
|
|
702
|
+
position: absolute;
|
|
703
|
+
top: 0;
|
|
704
|
+
left: 0;
|
|
705
|
+
right: 0;
|
|
706
|
+
bottom: 0;
|
|
707
|
+
width: 100%;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.first .__fixed {
|
|
711
|
+
top: var(--tably-padding-y, 0.5rem);
|
|
712
|
+
}
|
|
713
|
+
.last .__fixed {
|
|
714
|
+
bottom: var(--tably-padding-y, 0.5rem);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
tbody::before,
|
|
718
|
+
tbody::after,
|
|
719
|
+
selects::before,
|
|
720
|
+
selects::after {
|
|
721
|
+
content: '';
|
|
722
|
+
display: grid;
|
|
723
|
+
min-height: 100%;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
tbody::before,
|
|
727
|
+
selects::before {
|
|
728
|
+
height: var(--t);
|
|
729
|
+
}
|
|
730
|
+
tbody::after,
|
|
731
|
+
selects::after {
|
|
732
|
+
height: var(--b);
|
|
733
|
+
}
|
|
388
734
|
|
|
389
735
|
a.row {
|
|
390
736
|
color: inherit;
|
|
391
737
|
text-decoration: inherit;
|
|
392
738
|
}
|
|
393
|
-
|
|
394
|
-
.table, .table * {
|
|
395
|
-
box-sizing: border-box;
|
|
396
|
-
background-color: inherit;
|
|
397
|
-
}
|
|
398
739
|
|
|
399
740
|
.backdrop {
|
|
400
741
|
position: absolute;
|
|
@@ -402,21 +743,30 @@
|
|
|
402
743
|
top: 0px;
|
|
403
744
|
bottom: 0px;
|
|
404
745
|
right: 0px;
|
|
405
|
-
background-color: hsla(0, 0%, 0%, .3);
|
|
746
|
+
background-color: hsla(0, 0%, 0%, 0.3);
|
|
406
747
|
z-index: 3;
|
|
407
748
|
opacity: 1;
|
|
408
|
-
transition: .15s ease;
|
|
749
|
+
transition: 0.15s ease;
|
|
409
750
|
border: none;
|
|
410
751
|
outline: none;
|
|
411
752
|
cursor: pointer;
|
|
412
753
|
|
|
754
|
+
> button {
|
|
755
|
+
position: absolute;
|
|
756
|
+
left: 0px;
|
|
757
|
+
top: 0px;
|
|
758
|
+
bottom: 0px;
|
|
759
|
+
right: 0px;
|
|
760
|
+
}
|
|
761
|
+
|
|
413
762
|
&[aria-hidden='true'] {
|
|
414
763
|
opacity: 0;
|
|
415
764
|
pointer-events: none;
|
|
416
765
|
}
|
|
417
766
|
}
|
|
418
767
|
|
|
419
|
-
.headers,
|
|
768
|
+
.headers,
|
|
769
|
+
.statusbar {
|
|
420
770
|
/* So that the scrollbar doesn't cause the headers/statusbar to shift */
|
|
421
771
|
padding-right: 11px;
|
|
422
772
|
}
|
|
@@ -439,29 +789,34 @@
|
|
|
439
789
|
.headers > .column {
|
|
440
790
|
border-right: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
441
791
|
overflow: hidden;
|
|
442
|
-
padding: var(--tably-padding-y, .5rem) 0;
|
|
792
|
+
padding: var(--tably-padding-y, 0.5rem) 0;
|
|
793
|
+
cursor: default;
|
|
794
|
+
user-select: none;
|
|
795
|
+
|
|
796
|
+
&.sortable {
|
|
797
|
+
cursor: pointer;
|
|
798
|
+
}
|
|
443
799
|
|
|
444
800
|
&.resizeable {
|
|
445
801
|
resize: horizontal;
|
|
446
802
|
}
|
|
447
803
|
}
|
|
448
|
-
|
|
804
|
+
|
|
449
805
|
.table {
|
|
450
806
|
display: grid;
|
|
451
807
|
height: 100%;
|
|
452
808
|
position: relative;
|
|
453
809
|
|
|
454
|
-
grid-template-areas:
|
|
810
|
+
grid-template-areas:
|
|
455
811
|
'headers panel'
|
|
456
812
|
'rows panel'
|
|
457
|
-
'statusbar panel'
|
|
458
|
-
;
|
|
813
|
+
'statusbar panel';
|
|
459
814
|
|
|
460
815
|
grid-template-columns: auto min-content;
|
|
461
816
|
grid-template-rows: auto 1fr auto;
|
|
462
817
|
|
|
463
818
|
border: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
464
|
-
border-radius: var(--tably-radius, .25rem);
|
|
819
|
+
border-radius: var(--tably-radius, 0.25rem);
|
|
465
820
|
|
|
466
821
|
max-height: 100%;
|
|
467
822
|
}
|
|
@@ -478,19 +833,13 @@
|
|
|
478
833
|
}
|
|
479
834
|
|
|
480
835
|
.content {
|
|
481
|
-
grid-area: rows;
|
|
482
836
|
display: grid;
|
|
837
|
+
grid-auto-rows: max-content;
|
|
838
|
+
|
|
839
|
+
grid-area: rows;
|
|
483
840
|
scrollbar-width: thin;
|
|
484
841
|
overflow: auto;
|
|
485
|
-
height: 100%;
|
|
486
|
-
grid-template-rows: auto auto 1fr;
|
|
487
|
-
|
|
488
|
-
> .rows, > .virtual.bottom {
|
|
489
|
-
display: grid;
|
|
490
|
-
}
|
|
491
|
-
> .virtual.bottom {
|
|
492
|
-
min-height: 100%;
|
|
493
|
-
}
|
|
842
|
+
/* height: 100%; */
|
|
494
843
|
}
|
|
495
844
|
|
|
496
845
|
.statusbar {
|
|
@@ -499,12 +848,14 @@
|
|
|
499
848
|
background-color: var(--tably-statusbar, hsl(0, 0%, 98%));
|
|
500
849
|
}
|
|
501
850
|
|
|
502
|
-
.statusbar > .column {
|
|
851
|
+
.statusbar > tr > .column {
|
|
503
852
|
border-top: 1px solid var(--tably-border, hsl(0, 0%, 90%));
|
|
504
|
-
padding: calc(var(--tably-padding-y, .5rem) / 2) 0;
|
|
853
|
+
padding: calc(var(--tably-padding-y, 0.5rem) / 2) 0;
|
|
505
854
|
}
|
|
506
855
|
|
|
507
|
-
.headers,
|
|
856
|
+
.headers,
|
|
857
|
+
.row,
|
|
858
|
+
.statusbar > tr {
|
|
508
859
|
position: relative;
|
|
509
860
|
display: grid;
|
|
510
861
|
width: 100%;
|
|
@@ -523,14 +874,14 @@
|
|
|
523
874
|
}
|
|
524
875
|
|
|
525
876
|
.row:first-child > * {
|
|
526
|
-
padding-top: calc(var(--tably-padding-y, .5rem) + calc(var(--tably-padding-y, .5rem) / 2));
|
|
877
|
+
padding-top: calc(var(--tably-padding-y, 0.5rem) + calc(var(--tably-padding-y, 0.5rem) / 2));
|
|
527
878
|
}
|
|
528
879
|
.row:last-child > * {
|
|
529
|
-
padding-bottom: calc(var(--tably-padding-y, .5rem) + calc(var(--tably-padding-y, .5rem) / 2));
|
|
880
|
+
padding-bottom: calc(var(--tably-padding-y, 0.5rem) + calc(var(--tably-padding-y, 0.5rem) / 2));
|
|
530
881
|
}
|
|
531
882
|
|
|
532
883
|
.row > * {
|
|
533
|
-
padding: calc(var(--tably-padding-y, .5rem) / 2) 0;
|
|
884
|
+
padding: calc(var(--tably-padding-y, 0.5rem) / 2) 0;
|
|
534
885
|
}
|
|
535
886
|
|
|
536
887
|
.panel {
|
|
@@ -549,12 +900,7 @@
|
|
|
549
900
|
right: 0;
|
|
550
901
|
width: min-content;
|
|
551
902
|
overflow: auto;
|
|
552
|
-
padding: var(--tably-padding-y, .5rem) 0;
|
|
903
|
+
padding: var(--tably-padding-y, 0.5rem) 0;
|
|
553
904
|
}
|
|
554
905
|
}
|
|
555
|
-
|
|
556
|
-
.statusbar {
|
|
557
|
-
grid-area: statusbar;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
</style>
|
|
906
|
+
</style>
|