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.
@@ -1,6 +1,6 @@
1
1
  import {} from 'svelte';
2
2
  import { TableState } from '../table/table.svelte.js';
3
- import { assign, pick } from '../utility.svelte.js';
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.data.current;
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);
@@ -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 { TableState, type HeaderSelectCtx, type RowCtx, type RowSelectCtx, type TableProps } from './table.svelte.js'
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> = T extends new (...args: any[]) => infer K ? K : never
36
- type ConstructorParams<T extends new (...args: any[]) => any> = T extends new (...args: infer K) => any ? K : never
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 = columns
103
- .map((column, i, arr) => {
104
- const width = getWidth(column.id)
105
- if (i === arr.length - 1) return `minmax(${width}px, 1fr)`
106
- return `${width}px`
107
- })
108
- .join(' ') + context
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.map(column => !column.options.style ? '' : `
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
- `).join('')
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('click', (e) => {
161
- e.preventDefault()
162
- e.stopPropagation()
163
- mouseup = false
164
- }, { once: true, capture: true })
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("\n")
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
- node: HTMLTableRowElement,
280
- ctx: RowCtx<T>
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
- isHovered: false,
315
- itemState: { index: i, dragging: false, positioning: false } as ItemState<any>,
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='opacity: .3'>
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 isHovered() {
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='row'
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
- {...(table.options.href ? { href: table.options.href(item) } : {})}
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
- get value() {
506
- return column.options.value ? column.options.value(item) : undefined
507
- }
508
- }, ctx)
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='context-col'
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 && table.row?.snippets.contextHeader && hoveredRow !== item}
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
- () => table.expandable && expandedRow.includes(item),
528
- { min: 1, duration: table.expandable?.options.slide.duration, easing: table.expandable?.options.slide.easing })}
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='expandable' style='height: {expandableTween.current}px'>
531
- <td
532
- colspan={columns.length}
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='table svelte-tably'
549
- style='--t: {virtualization.virtualTop}px; --b: {virtualization.virtualBottom}px;'
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='headers' bind:this={elements.headers}>
554
- <tr style='min-width: {tbody.width}px'>
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
- get header() { return true },
559
- get data() { return table.data }
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='width:400px;background:none;pointer-events:none;'></tr>
603
+ <tr style="width:400px;background:none;pointer-events:none;"></tr>
572
604
  </thead>
573
605
  {/if}
574
606
 
575
607
  <tbody
576
- class='content'
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='statusbar' bind:this={elements.statusbar}>
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
- get data() { return table.data }
609
- }],
639
+ () => [
640
+ {
641
+ get data() {
642
+ return table.data
643
+ }
644
+ }
645
+ ],
610
646
  'statusbar'
611
647
  )}
612
648
  </tr>
613
- <tr style='width:400px;background:none;pointer-events:none;'></tr>
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='panel-content'
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 class='backdrop' aria-hidden={properties.panel && table.panels[properties.panel]?.backdrop ? false : true}>
640
- <button aria-label='Panel backdrop' class='btn-backdrop' tabindex='-1' onclick={() => (properties.panel = undefined)}
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='checkbox' indeterminate={ctx.indeterminate} bind:checked={ctx.isSelected} />
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='checkbox' bind:checked={ctx.isSelected} tabindex='-1' />
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='__fixed'
704
+ id="__fixed"
665
705
  {table}
666
706
  fixed
667
- width={Math.max(48, 0
668
- + (select && show !== 'never' ? 34 : 0)
669
- + (reorderable ? 34 : 0)
670
- + (expandable && expandable?.options.chevron !== 'never' ? 34 : 0)
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='__fixed'>
717
+ <div class="__fixed">
676
718
  {#if reorderable}
677
- <span style='width: 16px; display: flex; align-items: center;'></span>
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='__fixed'>
747
+ <div class="__fixed">
706
748
  {#if reorderable && row.itemState}
707
- <span style='width: 16px; display: flex; align-items: center;' use:row.itemState.handle>
708
- {#if (row.isHovered && !row.itemState.area.isTarget) || row.itemState.dragging}
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.isHovered && show === 'hover') || row.expanded)}
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='expand-row' tabindex='-1' onclick={() => row.expanded = !row.expanded}>
734
- {#if row.expanded || expandable.options.chevron === 'always' || (row.isHovered && expandable.options.chevron === 'hover')}
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
- typeof table.data[0]?.[key] === 'number'
753
- ? (a, b) => a - b
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, > .context-col {
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
- padding-right: var(--tably-padding-x);
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
- padding: var(--tably-padding-y) 0;
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
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-tably",
3
- "version": "1.0.0-next.19",
3
+ "version": "1.0.0-next.20",
4
4
  "repository": "github:refzlund/svelte-tably",
5
5
  "homepage": "https://github.com/Refzlund/svelte-tably",
6
6
  "bugs": {