svelte-tably 1.0.0-next.1 → 1.0.0-next.10

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,352 +0,0 @@
1
- <!-- @component
2
-
3
- This is a description, \
4
- on how to use this.
5
-
6
- @example
7
- <Component />
8
-
9
- -->
10
-
11
- <script module lang='ts'>
12
-
13
- export interface TableState<T extends Record<PropertyKey, any> = Record<PropertyKey, any>> {
14
- columns: Record<string, Column<T, unknown>>
15
- panels: Record<string, Panel>
16
- sortby?: string
17
- positions: {
18
- sticky: string[]
19
- scroll: string[]
20
- hidden: string[]
21
- toggle(key: string): void
22
- }
23
- readonly data: T[]
24
- addColumn(key: string, options: Column<T, unknown>): void
25
- removeColumn(key: string): void
26
- }
27
-
28
- export function getTableState<T extends Record<PropertyKey, any> = Record<PropertyKey, any>>() {
29
- return getContext<TableState<T>>('svelte5-table')
30
- }
31
-
32
- </script>
33
-
34
- <script lang='ts' generics='T extends Record<PropertyKey, unknown>'>
35
-
36
- import { getContext, setContext, type Snippet } from 'svelte'
37
- import { type Column } from './Column.svelte'
38
- import { PanelTween, type Panel } from './Panel.svelte'
39
- import { fly } from 'svelte/transition'
40
- import { sineInOut } from 'svelte/easing'
41
-
42
- interface Props {
43
- children?: Snippet
44
- panel?: string
45
- data?: T[]
46
- id?: string
47
- }
48
-
49
- let {
50
- children,
51
- panel,
52
- data: _data = [],
53
- id = Array.from({length: 12}, () => String.fromCharCode(Math.floor(Math.random() * 26) + 97)).join('')
54
- }: Props = $props()
55
-
56
- const data = $derived(_data.toSorted())
57
-
58
- const table: TableState<T> = $state({
59
- columns: {},
60
- panels: {},
61
- positions: {
62
- sticky: [],
63
- scroll: [],
64
- hidden: [],
65
- toggle(key) {
66
- if(table.positions.hidden.includes(key))
67
- table.positions.hidden = table.positions.hidden.filter(column => column !== key)
68
- else
69
- table.positions.hidden.push(key)
70
- }
71
- },
72
- get data() {
73
- return data
74
- },
75
- addColumn(key, column) {
76
- table.columns[key] = column
77
-
78
- if(column.defaults.sort)
79
- table.sortby = key
80
-
81
- if(!column.defaults.show)
82
- table.positions.hidden.push(key)
83
-
84
- if(column.defaults.sticky)
85
- table.positions.sticky.push(key)
86
- else
87
- table.positions.scroll.push(key)
88
- },
89
- removeColumn(key) {
90
- delete table.columns[key]
91
- table.positions.sticky = table.positions.sticky.filter(column => column !== key)
92
- table.positions.scroll = table.positions.scroll.filter(column => column !== key)
93
- table.positions.hidden = table.positions.hidden.filter(column => column !== key)
94
- }
95
- })
96
-
97
- setContext('svelte5-table', table)
98
-
99
- // * --- *
100
-
101
- const panelTween = new PanelTween(() => panel)
102
- const elements = $state({}) as Record<'headers' | 'statusbar', HTMLElement>
103
-
104
- /** Order of columns */
105
- const columns = $derived([...table.positions.sticky, ...table.positions.scroll].filter(key => !table.positions.hidden.includes(key)))
106
-
107
- /** Width of each column */
108
- const widths = $state({}) as Record<string, number>
109
-
110
- /** grid-template-columns for widths */
111
- const style = $derived(`
112
- #${id} > .headers, #${id} > .rows > .row, #${id} > .statusbar {
113
- grid-template-columns: ${columns.map((key, i, arr) => i === arr.length - 1 ? `minmax(${widths[key] || 150}px, 1fr)` : `${widths[key] || 150}px`).join(' ')};
114
- }
115
- `)
116
-
117
- const observer = typeof MutationObserver === 'undefined' ? undefined : new MutationObserver(mutations => {
118
- const target = mutations[0].target as HTMLDivElement
119
- widths[target.getAttribute('data-column')!] = parseFloat(target.style.width)
120
- })
121
-
122
- function observe(node: HTMLDivElement, column: string) {
123
- observer?.observe(node, {attributes: true})
124
- return { destroy: () => observer?.disconnect() }
125
- }
126
-
127
- function onscroll(event: Event) {
128
- const target = event.target as HTMLDivElement
129
- elements.headers.scrollLeft = target.scrollLeft
130
- elements.statusbar.scrollLeft = target.scrollLeft
131
- }
132
-
133
- </script>
134
- <!---------------------------------------------------->
135
-
136
- <svelte:head>
137
- {@html `<style>${style}</style>`}
138
- </svelte:head>
139
-
140
- <div id={id} class='table'>
141
-
142
- <div class='headers' bind:this={elements.headers}>
143
- {#each table.positions.sticky as column, i (column)}
144
- {#if !table.positions.hidden.includes(column)}
145
- <div class='column sticky' data-column="{column}" use:observe={column}>
146
- {@render table.columns[column]?.header()}
147
- </div>
148
- {/if}
149
- {/each}
150
- {#each table.positions.scroll as column, i (column)}
151
- {#if !table.positions.hidden.includes(column)}
152
- <div class='column' use:observe={column}>
153
- {@render table.columns[column]?.header()}
154
- </div>
155
- {/if}
156
- {/each}
157
- </div>
158
-
159
- <div class="rows" {onscroll}>
160
- {#each data as item}
161
- <div class='row'>
162
- {#each table.positions.sticky as column, i (column)}
163
- {#if !table.positions.hidden.includes(column)}
164
- {@const col = table.columns[column]}
165
- <div class='column sticky' class:border={i == table.positions.sticky.length - 1}>
166
- {@render col.row(item, col.options.value ? col.options.value(item) : undefined)}
167
- </div>
168
- {/if}
169
- {/each}
170
- {#each table.positions.scroll as column, i (column)}
171
- {#if !table.positions.hidden.includes(column)}
172
- {@const col = table.columns[column]}
173
- <div class='column'>
174
- {@render col.row(item, col.options.value ? col.options.value(item) : undefined)}
175
- </div>
176
- {/if}
177
- {/each}
178
- </div>
179
- {/each}
180
- </div>
181
-
182
- <div class='statusbar' bind:this={elements.statusbar}>
183
- {#each table.positions.sticky as column, i (column)}
184
- {#if !table.positions.hidden.includes(column)}
185
- <div class='column sticky' class:border={i == table.positions.sticky.length - 1}>
186
- {@render table.columns[column]?.statusbar?.(data)}
187
- </div>
188
- {/if}
189
- {/each}
190
- {#each table.positions.scroll as column, i (column)}
191
- {#if !table.positions.hidden.includes(column)}
192
- <div class='column'>
193
- {@render table.columns[column]?.statusbar?.(data)}
194
- </div>
195
- {/if}
196
- {/each}
197
- </div>
198
-
199
- <div class='panel' style='width: {panelTween.current}px;' style:overflow={panelTween.transitioning ? 'hidden' : 'auto'}>
200
- {#if panel && panel in table.panels}
201
- <div
202
- class="panel-content"
203
- bind:clientWidth={panelTween.width}
204
- in:fly={{ x: 100, easing: sineInOut, duration:300 }}
205
- out:fly={{ x:100, duration:200, easing: sineInOut }}
206
- >
207
- {@render table.panels[panel].content(table as TableState)}
208
- </div>
209
- {/if}
210
- </div>
211
- </div>
212
-
213
-
214
- {@render children?.()}
215
-
216
-
217
-
218
- <!---------------------------------------------------->
219
- <style>
220
-
221
- .table, .table * {
222
- box-sizing: border-box;
223
- }
224
-
225
- .sticky {
226
- position: sticky;
227
- left: 0px;
228
- /* right: 100px; */
229
- background-color: white;
230
- z-index: 1;
231
- }
232
-
233
- .sticky.border {
234
- border-right: 1px solid hsla(0, 0%, 90%);
235
- }
236
-
237
- .headers > .column {
238
- border-right: 1px solid hsla(0, 0%, 90%);
239
- resize: horizontal;
240
- overflow: hidden;
241
- padding: var(--padding-y) 0;
242
- }
243
-
244
- .table {
245
- --panel: 250px;
246
- --padding-x: 1rem;
247
- --padding-y: .5rem;
248
- --gap: .25rem;
249
- --header-height: 2.5rem;
250
-
251
- display: grid;
252
-
253
- grid-template-areas:
254
- "headers panel"
255
- "rows panel"
256
- "statusbar panel"
257
- ;
258
-
259
- grid-template-columns: auto min-content;
260
- grid-template-rows: auto 1fr auto;
261
-
262
- border: 1px solid hsla(0, 0%, 90%);
263
- border-radius: .25rem;
264
-
265
- max-height: 100%;
266
- }
267
-
268
- .headers {
269
- grid-area: headers;
270
- z-index: 2;
271
- overflow: hidden;
272
- padding-right: 1rem;
273
- }
274
-
275
- .headers > .column {
276
- width: auto !important;
277
- background-color: hsla(0, 0%, 100%);
278
- border-bottom: 1px solid hsla(0, 0%, 90%);
279
- }
280
-
281
- .rows {
282
- grid-area: rows;
283
- display: grid;
284
- overflow: auto;
285
- scrollbar-width: thin;
286
- background-color: hsla(0, 0%, 100%);
287
- }
288
-
289
- .statusbar {
290
- grid-area: statusbar;
291
- overflow: hidden;
292
- padding-right: 1rem;
293
- }
294
-
295
- .statusbar > .column {
296
- background-color: hsla(0, 0%, 99%);
297
- border-top: 1px solid hsla(0, 0%, 90%);
298
- padding: calc(var(--padding-y) / 2) 0;
299
- }
300
-
301
- .headers, .row, .statusbar {
302
- display: grid;
303
- width: 100%;
304
- height: 100%;
305
-
306
- & > .column {
307
- display: flex;
308
- padding-left: var(--padding-x);
309
- overflow: hidden;
310
- }
311
-
312
- & > *:last-child {
313
- width: 100%;
314
- padding-right: var(--padding-x);
315
- }
316
- }
317
-
318
- .row:nth-child(1) > * {
319
- padding-top: calc(var(--padding-y) + var(--gap));
320
- }
321
- .row:nth-last-child(1) > * {
322
- padding-bottom: calc(var(--padding-y) + var(--gap));
323
- }
324
-
325
- .row > * {
326
- padding: var(--gap) 0;
327
- }
328
-
329
- .panel {
330
- position: relative;
331
- grid-area: panel;
332
- width: var(--panel);
333
- height: 100%;
334
- background-color: white;
335
-
336
- border-left: 1px solid hsla(0, 0%, 90%);
337
-
338
- > .panel-content {
339
- position: absolute;
340
- top: 0;
341
- right: 0;
342
- width: min-content;
343
- overflow: hidden;
344
- padding: var(--padding-y) var(--padding-x);
345
- }
346
- }
347
-
348
- .statusbar {
349
- grid-area: statusbar;
350
- }
351
-
352
- </style>
@@ -1,12 +0,0 @@
1
- import { default as _Table } from './Table.svelte';
2
- import Column from './Column.svelte';
3
- import { default as _Panel } from './Panel.svelte';
4
- declare const LATIN: readonly ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
5
- type Capital = typeof LATIN[number];
6
- declare const Table: typeof _Table & {
7
- [key: `${Capital}${string}`]: typeof Column;
8
- };
9
- declare const Panel: {
10
- [key: `${Capital}${string}`]: typeof _Panel;
11
- };
12
- export { Table, Panel };
@@ -1,31 +0,0 @@
1
- import { default as _Table } from './Table.svelte';
2
- import Column from './Column.svelte';
3
- import { default as _Panel } from './Panel.svelte';
4
- const LATIN = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
5
- const Table = new Proxy(_Table, {
6
- get(target, p, receiver) {
7
- if (typeof p !== 'string' || !LATIN.includes(p[0])) {
8
- return Reflect.get(target, p, receiver);
9
- }
10
- return new Proxy(Column, {
11
- apply(_, __, [anchor, props]) {
12
- Object.assign(props, { __key: p });
13
- return Column(anchor, props);
14
- },
15
- });
16
- }
17
- });
18
- const Panel = new Proxy(_Panel, {
19
- get(target, p, receiver) {
20
- if (typeof p !== 'string' || !LATIN.includes(p[0])) {
21
- return Reflect.get(target, p, receiver);
22
- }
23
- return new Proxy(_Panel, {
24
- apply(_, __, [anchor, props]) {
25
- Object.assign(props, { __key: p });
26
- return _Panel(anchor, props);
27
- },
28
- });
29
- },
30
- });
31
- export { Table, Panel };
@@ -1,33 +0,0 @@
1
- <!-- @component
2
-
3
- This is a description, \
4
- on how to use this.
5
-
6
- @example
7
- <Component />
8
-
9
- -->
10
-
11
- <script lang="ts">
12
- import type { Snippet } from 'svelte'
13
- import { getTableState, type ColumnOptions } from '../Table.svelte'
14
-
15
- interface Props {
16
- [key: string]: Snippet<[options: ColumnOptions]>
17
- }
18
-
19
- let headers: Props = $props()
20
- const table = getTableState()
21
-
22
- let keys = [] as string[]
23
-
24
- $effect.pre(() => {
25
- keys.forEach((key) => delete table.columns[key].header)
26
- keys = []
27
-
28
- for (const [key, value] of Object.entries(headers)) {
29
- table.updateColumn(key, { header: value })
30
- keys.push(key)
31
- }
32
- })
33
- </script>
@@ -1,15 +0,0 @@
1
- import type { Snippet } from 'svelte';
2
- import { type ColumnOptions } from '../Table.svelte';
3
- interface Props {
4
- [key: string]: Snippet<[options: ColumnOptions]>;
5
- }
6
- /**
7
- * This is a description, \
8
- * on how to use this.
9
- *
10
- * @example
11
- * <Component />
12
- */
13
- declare const Headers: import("svelte").Component<Props, {}, "">;
14
- type Headers = ReturnType<typeof Headers>;
15
- export default Headers;
@@ -1,25 +0,0 @@
1
- <!-- @component
2
-
3
- This is a description, \
4
- on how to use this.
5
-
6
- @example
7
- <Component />
8
-
9
- -->
10
-
11
- <script lang='ts'>
12
-
13
- import type { Snippet } from 'svelte'
14
- import { getTableState, type TableState } from './Table.svelte'
15
-
16
- interface Props {
17
- [key: string]: Snippet<[table: TableState]>
18
- }
19
-
20
- let panels: Props = $props()
21
-
22
- getTableState().panels = panels
23
-
24
- </script>
25
- <!---------------------------------------------------->
@@ -1,15 +0,0 @@
1
- import type { Snippet } from 'svelte';
2
- import { type TableState } from './Table.svelte';
3
- interface Props {
4
- [key: string]: Snippet<[table: TableState]>;
5
- }
6
- /**
7
- * This is a description, \
8
- * on how to use this.
9
- *
10
- * @example
11
- * <Component />
12
- */
13
- declare const Panels: import("svelte").Component<Props, {}, "">;
14
- type Panels = ReturnType<typeof Panels>;
15
- export default Panels;
@@ -1,35 +0,0 @@
1
- <!-- @component
2
-
3
- This is a description, \
4
- on how to use this.
5
-
6
- @example
7
- <Component />
8
-
9
- -->
10
-
11
- <script lang='ts' generics='T extends Record<PropertyKey, unknown>'>
12
-
13
- import type { Snippet } from 'svelte'
14
- import { getTableState } from './Table.svelte'
15
-
16
- interface Props {
17
- [key: string]: Snippet<[data: T]>
18
- }
19
-
20
- let rows: Props = $props()
21
- const table = getTableState<T>()
22
-
23
- let keys = [] as string[]
24
-
25
- $effect.pre(() => {
26
- keys.forEach(key => delete table.columns[key].row)
27
- keys = []
28
-
29
- for(const [key, value] of Object.entries(rows)) {
30
- table.updateColumn(key, { row: value })
31
- keys.push(key)
32
- }
33
- })
34
-
35
- </script>
@@ -1,27 +0,0 @@
1
- import type { Snippet } from 'svelte';
2
- declare class __sveltets_Render<T extends Record<PropertyKey, unknown>> {
3
- props(): {
4
- [key: string]: Snippet<[data: T]>;
5
- };
6
- events(): {};
7
- slots(): {};
8
- bindings(): "";
9
- exports(): {};
10
- }
11
- interface $$IsomorphicComponent {
12
- 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']>> & {
13
- $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
14
- } & ReturnType<__sveltets_Render<T>['exports']>;
15
- <T extends Record<PropertyKey, unknown>>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
16
- z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
17
- }
18
- /**
19
- * This is a description, \
20
- * on how to use this.
21
- *
22
- * @example
23
- * <Component />
24
- */
25
- declare const Rows: $$IsomorphicComponent;
26
- type Rows<T extends Record<PropertyKey, unknown>> = InstanceType<typeof Rows<T>>;
27
- export default Rows;
@@ -1,35 +0,0 @@
1
- <!-- @component
2
-
3
- This is a description, \
4
- on how to use this.
5
-
6
- @example
7
- <Component />
8
-
9
- -->
10
-
11
- <script lang='ts'>
12
-
13
- import type { Snippet } from 'svelte'
14
- import { getTableState, type TableState } from './Table.svelte'
15
-
16
- interface Props {
17
- [key: string]: Snippet<[data: T[]]>
18
- }
19
-
20
- let statusbars: Props = $props()
21
- const table = getTableState()
22
-
23
- let keys = [] as string[]
24
-
25
- $effect.pre(() => {
26
- keys.forEach(key => delete table.columns[key].statusbar)
27
- keys = []
28
- for(const [key, value] of Object.entries(statusbars)) {
29
- table.updateColumn(key, { statusbar: value })
30
- keys.push(key)
31
- }
32
- })
33
-
34
- </script>
35
- <!---------------------------------------------------->
@@ -1,13 +0,0 @@
1
- import type { Snippet } from 'svelte';
2
- /**
3
- * This is a description, \
4
- * on how to use this.
5
- *
6
- * @example
7
- * <Component />
8
- */
9
- declare const Statusbar: import("svelte").Component<{
10
- [key: string]: Snippet<[data: T[]]>;
11
- }, {}, "">;
12
- type Statusbar = ReturnType<typeof Statusbar>;
13
- export default Statusbar;