|
| 1 | +<script context="module"> |
| 2 | + export const DEFAULT_WIDTH = '100px' |
| 3 | +</script> |
| 4 | + |
1 | 5 | <script>
|
| 6 | + import { onMount } from 'svelte' |
| 7 | +
|
2 | 8 | import bem from '../../utils/bem'
|
3 | 9 | import CTd from './CTd.svelte'
|
4 | 10 | import CTh from './CTh.svelte'
|
5 | 11 | import CTr from './CTr.svelte'
|
| 12 | + import { EStickyPosition } from './types' |
6 | 13 |
|
7 | 14 | /**
|
8 | 15 | * Determine whether the table is striped or not.
|
|
12 | 19 |
|
13 | 20 | /**
|
14 | 21 | * The columns config array.
|
15 |
| - * @type {Array<{ field: string; width?: string; title?: string | import('svelte').ComponentType; cell?: import('svelte').ComponentType }>} |
| 22 | + * @type {Array<import('./types').Column>} |
16 | 23 | */
|
17 | 24 | export let columns = []
|
18 | 25 |
|
|
21 | 28 | * @type {Array<any>}
|
22 | 29 | */
|
23 | 30 | export let data = []
|
| 31 | +
|
| 32 | + const stickyLeftPositions = [] |
| 33 | + const stickyRightPositions = [] |
| 34 | + let maxStickyLeftIdx = -1 |
| 35 | + let minStickyRightIdx = -1 |
| 36 | +
|
| 37 | + function compute() { |
| 38 | + let previousLeftIndex = -1 |
| 39 | + let previousRightIndex = -1 |
| 40 | + columns.forEach((c, i) => { |
| 41 | + if (c.sticky === EStickyPosition.Left) { |
| 42 | + if (previousLeftIndex === -1) { |
| 43 | + stickyLeftPositions[i] = 0 |
| 44 | + } else { |
| 45 | + stickyLeftPositions[i] = |
| 46 | + columns[previousLeftIndex].width || DEFAULT_WIDTH |
| 47 | + } |
| 48 | +
|
| 49 | + previousLeftIndex = i |
| 50 | + maxStickyLeftIdx = i |
| 51 | + } else if (c.sticky === EStickyPosition.Right) { |
| 52 | + if (previousRightIndex === -1) { |
| 53 | + stickyRightPositions[i] = 0 |
| 54 | + minStickyRightIdx = i |
| 55 | + } else { |
| 56 | + stickyRightPositions[i] = |
| 57 | + columns[previousRightIndex].width || DEFAULT_WIDTH |
| 58 | + } |
| 59 | + previousRightIndex = i |
| 60 | + } else { |
| 61 | + stickyLeftPositions[i] = 0 |
| 62 | + stickyRightPositions[i] = 0 |
| 63 | + } |
| 64 | + }) |
| 65 | + } |
| 66 | +
|
| 67 | + compute() |
| 68 | +
|
| 69 | + /** |
| 70 | + * @type {HTMLDivElement} |
| 71 | + */ |
| 72 | + let tableWrapper |
| 73 | +
|
| 74 | + let scrollLeft = 0 |
| 75 | + let clientWidth = 0 |
| 76 | + let scrollWidth = 0 |
| 77 | +
|
| 78 | + $: showMaxLeftStickyShadow = scrollLeft > 0 |
| 79 | + $: showMaxRightStickyShadow = scrollLeft < scrollWidth - clientWidth |
| 80 | +
|
| 81 | + function handleScroll(e) { |
| 82 | + scrollLeft = e.target.scrollLeft |
| 83 | + } |
| 84 | +
|
| 85 | + onMount(() => { |
| 86 | + scrollWidth = tableWrapper.scrollWidth |
| 87 | + }) |
24 | 88 | </script>
|
25 | 89 |
|
26 | 90 | <div
|
27 | 91 | class={bem('table', {
|
28 | 92 | striped,
|
29 | 93 | })}
|
| 94 | + bind:clientWidth |
| 95 | + on:scroll={handleScroll} |
| 96 | + bind:this={tableWrapper} |
30 | 97 | >
|
31 | 98 | <table class="c-table--table">
|
32 | 99 | <colgroup>
|
33 |
| - {#each columns as _col} |
34 |
| - <col /> |
| 100 | + {#each columns as col} |
| 101 | + <col style={{ width: col.width ?? DEFAULT_WIDTH }} /> |
35 | 102 | {/each}
|
36 | 103 | </colgroup>
|
37 | 104 | <thead>
|
38 | 105 | <CTr>
|
39 |
| - {#each columns as col} |
40 |
| - <CTh width={col.width}> |
| 106 | + {#each columns as col, i} |
| 107 | + <CTh |
| 108 | + width={col.width} |
| 109 | + sticky={col.sticky} |
| 110 | + stickyLeft={stickyLeftPositions[i]} |
| 111 | + stickyRight={stickyRightPositions[i]} |
| 112 | + stickyLeftMax={maxStickyLeftIdx === i && showMaxLeftStickyShadow} |
| 113 | + stickyRightMin={minStickyRightIdx === i && showMaxRightStickyShadow} |
| 114 | + > |
41 | 115 | {#if typeof col.title === 'string'}
|
42 | 116 | {col.title}
|
43 | 117 | {:else}
|
|
50 | 124 | <tbody>
|
51 | 125 | {#each data as row, i}
|
52 | 126 | <CTr>
|
53 |
| - {#each columns as col} |
54 |
| - <CTd width={col.width}> |
| 127 | + {#each columns as col, j} |
| 128 | + <CTd |
| 129 | + width={col.width} |
| 130 | + sticky={col.sticky} |
| 131 | + stickyLeft={stickyLeftPositions[j]} |
| 132 | + stickyRight={stickyRightPositions[j]} |
| 133 | + stickyLeftMax={maxStickyLeftIdx === j && showMaxLeftStickyShadow} |
| 134 | + stickyRightMin={minStickyRightIdx === j && |
| 135 | + showMaxRightStickyShadow} |
| 136 | + > |
55 | 137 | {#if col.cell}
|
56 | 138 | <svelte:component this={col.cell} {col} {row} rowIndex={i} />
|
57 | 139 | {:else}
|
|
0 commit comments