sveltacular 0.0.42 → 0.0.44
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/dist/generic/empty/empty.svelte +53 -8
- package/dist/generic/empty/empty.svelte.d.ts +4 -0
- package/dist/generic/notice/notice.svelte +9 -10
- package/dist/generic/notice/notice.svelte.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/navigation/pagination/pagination.svelte +129 -0
- package/dist/navigation/pagination/pagination.svelte.d.ts +22 -0
- package/dist/navigation/wizard/wizard-context.d.ts +1 -0
- package/dist/navigation/wizard/wizard-step.svelte +15 -1
- package/dist/navigation/wizard/wizard.svelte +15 -9
- package/dist/navigation/wizard/wizard.svelte.d.ts +2 -2
- package/dist/tables/data-grid.svelte +40 -9
- package/dist/tables/data-grid.svelte.d.ts +5 -2
- package/dist/tables/table-cell.svelte +8 -2
- package/dist/tables/table-cell.svelte.d.ts +1 -0
- package/dist/tables/table-footer-cell.svelte +9 -1
- package/dist/tables/table-header-cell.svelte +9 -1
- package/dist/tables/table-header-cell.svelte.d.ts +1 -0
- package/dist/types/data.d.ts +2 -1
- package/package.json +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
<script>export let text = "No data to display";
|
|
2
|
+
export let size = "md";
|
|
3
|
+
export let orientation = "vertical";
|
|
4
|
+
export let reverse = false;
|
|
5
|
+
export let align = "center";
|
|
2
6
|
</script>
|
|
3
7
|
|
|
4
|
-
<div class="empty">
|
|
8
|
+
<div class="empty {size} {orientation} {reverse ? 'reverse' : ''} {align}">
|
|
5
9
|
{#if $$slots.default}
|
|
6
10
|
<div class="icon">
|
|
7
11
|
<slot />
|
|
@@ -19,20 +23,61 @@
|
|
|
19
23
|
justify-content: center;
|
|
20
24
|
text-align: center;
|
|
21
25
|
color: var(--color-text-secondary, rgba(150, 150, 150, 0.5));
|
|
22
|
-
font-size: 1.5rem;
|
|
23
26
|
font-weight: 500;
|
|
24
|
-
line-height: 2rem;
|
|
25
|
-
margin: 2rem 0;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
.
|
|
29
|
+
.start {
|
|
30
|
+
justify-content: flex-start;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.end {
|
|
34
|
+
justify-content: flex-end;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.horizontal {
|
|
38
|
+
flex-direction: row;
|
|
39
|
+
gap: 1rem;
|
|
40
|
+
}
|
|
41
|
+
.horizontal.reverse {
|
|
42
|
+
flex-direction: row-reverse;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.vertical.reverse {
|
|
46
|
+
flex-direction: column-reverse;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sm {
|
|
50
|
+
font-size: 1rem;
|
|
51
|
+
line-height: 1.5rem;
|
|
52
|
+
}
|
|
53
|
+
.sm .icon {
|
|
54
|
+
height: 1.5rem;
|
|
55
|
+
width: 1.5rem;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.md {
|
|
59
|
+
font-size: 1.25rem;
|
|
60
|
+
line-height: 1.75rem;
|
|
61
|
+
}
|
|
62
|
+
.md .icon {
|
|
29
63
|
height: 2rem;
|
|
30
64
|
width: 2rem;
|
|
31
|
-
margin-bottom: 1rem;
|
|
32
65
|
}
|
|
33
66
|
|
|
34
|
-
.
|
|
67
|
+
.lg {
|
|
35
68
|
font-size: 1.5rem;
|
|
36
|
-
font-weight: 500;
|
|
37
69
|
line-height: 2rem;
|
|
70
|
+
}
|
|
71
|
+
.lg .icon {
|
|
72
|
+
height: 3rem;
|
|
73
|
+
width: 3rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.xl {
|
|
77
|
+
font-size: 2rem;
|
|
78
|
+
line-height: 2.5rem;
|
|
79
|
+
}
|
|
80
|
+
.xl .icon {
|
|
81
|
+
height: 4rem;
|
|
82
|
+
width: 4rem;
|
|
38
83
|
}</style>
|
|
@@ -2,6 +2,10 @@ import { SvelteComponent } from "svelte";
|
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
4
|
text?: string | undefined;
|
|
5
|
+
size?: "sm" | "md" | "lg" | "xl" | undefined;
|
|
6
|
+
orientation?: "horizontal" | "vertical" | undefined;
|
|
7
|
+
reverse?: boolean | undefined;
|
|
8
|
+
align?: "center" | "end" | "start" | undefined;
|
|
5
9
|
};
|
|
6
10
|
events: {
|
|
7
11
|
[evt: string]: CustomEvent<any>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const dispatch = createEventDispatcher();
|
|
3
3
|
export let title = void 0;
|
|
4
4
|
export let style = "info";
|
|
5
|
-
export let size = "
|
|
5
|
+
export let size = "md";
|
|
6
6
|
export let dismissable = false;
|
|
7
7
|
let visible = true;
|
|
8
8
|
let fading = false;
|
|
@@ -54,9 +54,9 @@ const onClick = (e) => {
|
|
|
54
54
|
max-width: 100%;
|
|
55
55
|
padding: 1rem;
|
|
56
56
|
border-radius: 0.2rem;
|
|
57
|
-
border: 2px solid var(--base-
|
|
58
|
-
background: var(--base-
|
|
59
|
-
color: var(--base-
|
|
57
|
+
border: 2px solid var(--base-bg, black);
|
|
58
|
+
background: var(--base-fg, white);
|
|
59
|
+
color: var(--base-bg, black);
|
|
60
60
|
position: relative;
|
|
61
61
|
opacity: 1;
|
|
62
62
|
transition: opacity 0.3s ease-in-out, transform 0.5s ease-in-out;
|
|
@@ -101,11 +101,12 @@ const onClick = (e) => {
|
|
|
101
101
|
color: rgb(100, 0, 0);
|
|
102
102
|
border-color: rgb(218, 40, 40);
|
|
103
103
|
}
|
|
104
|
-
.notice.xl {
|
|
105
|
-
width:
|
|
104
|
+
.notice.xl .icon {
|
|
105
|
+
width: 3rem;
|
|
106
|
+
min-width: 3rem;
|
|
106
107
|
}
|
|
107
|
-
.notice.
|
|
108
|
-
|
|
108
|
+
.notice.xl .content {
|
|
109
|
+
font-size: 1.15rem;
|
|
109
110
|
}
|
|
110
111
|
.notice.lg .icon {
|
|
111
112
|
width: 2.5rem;
|
|
@@ -115,7 +116,6 @@ const onClick = (e) => {
|
|
|
115
116
|
font-size: 0.95rem;
|
|
116
117
|
}
|
|
117
118
|
.notice.md {
|
|
118
|
-
width: 25rem;
|
|
119
119
|
border-width: 1px;
|
|
120
120
|
border-radius: 3px;
|
|
121
121
|
}
|
|
@@ -127,7 +127,6 @@ const onClick = (e) => {
|
|
|
127
127
|
font-size: 0.85rem;
|
|
128
128
|
}
|
|
129
129
|
.notice.sm {
|
|
130
|
-
width: 15rem;
|
|
131
130
|
border-width: 1px;
|
|
132
131
|
border-radius: 2px;
|
|
133
132
|
}
|
|
@@ -3,7 +3,7 @@ declare const __propDef: {
|
|
|
3
3
|
props: {
|
|
4
4
|
title?: string | undefined;
|
|
5
5
|
style?: ("outline" | "attention" | "success" | "error" | "info") | undefined;
|
|
6
|
-
size?: ("sm" | "md" | "lg" | "xl"
|
|
6
|
+
size?: ("sm" | "md" | "lg" | "xl") | undefined;
|
|
7
7
|
dismissable?: boolean | undefined;
|
|
8
8
|
};
|
|
9
9
|
events: {
|
package/dist/index.d.ts
CHANGED
|
@@ -61,6 +61,7 @@ export { default as AppNavItem } from './navigation/app-bar/app-nav-item.svelte'
|
|
|
61
61
|
export { default as AppBranding } from './navigation/app-bar/app-branding.svelte';
|
|
62
62
|
export { default as Wizard } from './navigation/wizard/wizard.svelte';
|
|
63
63
|
export { default as WizardStep } from './navigation/wizard/wizard-step.svelte';
|
|
64
|
+
export { default as Pagination } from './navigation/pagination/pagination.svelte';
|
|
64
65
|
export { default as DataGrid } from './tables/data-grid.svelte';
|
|
65
66
|
export { default as Table } from './tables/table.svelte';
|
|
66
67
|
export { default as TableBody } from './tables/table-body.svelte';
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,7 @@ export { default as AppNavItem } from './navigation/app-bar/app-nav-item.svelte'
|
|
|
66
66
|
export { default as AppBranding } from './navigation/app-bar/app-branding.svelte';
|
|
67
67
|
export { default as Wizard } from './navigation/wizard/wizard.svelte';
|
|
68
68
|
export { default as WizardStep } from './navigation/wizard/wizard-step.svelte';
|
|
69
|
+
export { default as Pagination } from './navigation/pagination/pagination.svelte';
|
|
69
70
|
// Tables
|
|
70
71
|
export { default as DataGrid } from './tables/data-grid.svelte';
|
|
71
72
|
export { default as Table } from './tables/table.svelte';
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<script>import { createEventDispatcher } from "svelte";
|
|
2
|
+
export let currentPage = 1;
|
|
3
|
+
export let totalPages = 1;
|
|
4
|
+
export let align = "center";
|
|
5
|
+
export let style = "default";
|
|
6
|
+
export let size = "md";
|
|
7
|
+
const dispatch = createEventDispatcher();
|
|
8
|
+
const changePage = (page) => {
|
|
9
|
+
if (page < 1 || page > totalPages)
|
|
10
|
+
return;
|
|
11
|
+
currentPage = page;
|
|
12
|
+
dispatch("page", page);
|
|
13
|
+
};
|
|
14
|
+
$:
|
|
15
|
+
previousPages = currentPage > 1 ? (() => {
|
|
16
|
+
const pages = [];
|
|
17
|
+
for (let i = currentPage - 1; i > 0 && i >= currentPage - 3; i--) {
|
|
18
|
+
pages.push(i);
|
|
19
|
+
}
|
|
20
|
+
return pages.reverse();
|
|
21
|
+
})() : [];
|
|
22
|
+
$:
|
|
23
|
+
nextPages = currentPage < totalPages ? (() => {
|
|
24
|
+
const pages = [];
|
|
25
|
+
for (let i = currentPage + 1; i <= totalPages && i <= currentPage + 3; i++) {
|
|
26
|
+
pages.push(i);
|
|
27
|
+
}
|
|
28
|
+
return pages;
|
|
29
|
+
})() : [];
|
|
30
|
+
$:
|
|
31
|
+
showFirst = currentPage > 4;
|
|
32
|
+
$:
|
|
33
|
+
showLast = currentPage < totalPages - 3;
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<nav class="{align} {style} {size}">
|
|
37
|
+
{#if currentPage > 1}
|
|
38
|
+
<button on:click={() => changePage(currentPage - 1)} class="previous page">Previous</button>
|
|
39
|
+
{/if}
|
|
40
|
+
{#if showFirst}
|
|
41
|
+
<button on:click={() => changePage(1)} class="first page">1</button>
|
|
42
|
+
<div class="ellipsis page">···</div>
|
|
43
|
+
{/if}
|
|
44
|
+
{#each previousPages as page}
|
|
45
|
+
<button on:click={() => changePage(page)} class="pre page">{page}</button>
|
|
46
|
+
{/each}
|
|
47
|
+
<div class="current page">{currentPage}</div>
|
|
48
|
+
{#each nextPages as page}
|
|
49
|
+
<button on:click={() => changePage(page)} class="pro numbered page">{page}</button>
|
|
50
|
+
{/each}
|
|
51
|
+
{#if showLast}
|
|
52
|
+
<div class="ellipsis page">···</div>
|
|
53
|
+
<button on:click={() => changePage(totalPages)} class="last page">{totalPages}</button>
|
|
54
|
+
{/if}
|
|
55
|
+
{#if currentPage < totalPages}
|
|
56
|
+
<button on:click={() => changePage(currentPage + 1)} class="next page">Next</button>
|
|
57
|
+
{/if}
|
|
58
|
+
</nav>
|
|
59
|
+
|
|
60
|
+
<style>nav {
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: row;
|
|
63
|
+
gap: 0.2rem;
|
|
64
|
+
align-items: center;
|
|
65
|
+
justify-content: center;
|
|
66
|
+
}
|
|
67
|
+
nav .page {
|
|
68
|
+
border: none;
|
|
69
|
+
background: none;
|
|
70
|
+
margin: 0;
|
|
71
|
+
color: var(--base-fg, #ccc);
|
|
72
|
+
text-shadow: 0 0 0.125rem rgba(0, 0, 0, 0.5);
|
|
73
|
+
}
|
|
74
|
+
nav button {
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
}
|
|
77
|
+
nav .current {
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
}
|
|
80
|
+
nav.start {
|
|
81
|
+
justify-content: flex-start;
|
|
82
|
+
}
|
|
83
|
+
nav.end {
|
|
84
|
+
justify-content: flex-end;
|
|
85
|
+
}
|
|
86
|
+
nav.sm .page {
|
|
87
|
+
font-size: 0.75rem;
|
|
88
|
+
padding: 0.5rem 0.65rem 0.5rem 0.65rem;
|
|
89
|
+
}
|
|
90
|
+
nav.sm .current {
|
|
91
|
+
font-size: 0.95rem;
|
|
92
|
+
}
|
|
93
|
+
nav.md .page {
|
|
94
|
+
font-size: 0.85rem;
|
|
95
|
+
padding: 0.5rem 0.65rem 0.5rem 0.65rem;
|
|
96
|
+
}
|
|
97
|
+
nav.md .current {
|
|
98
|
+
font-size: 1.05rem;
|
|
99
|
+
}
|
|
100
|
+
nav.lg .page {
|
|
101
|
+
font-size: 0.95rem;
|
|
102
|
+
padding: 0.5rem 0.65rem 0.5rem 0.65rem;
|
|
103
|
+
}
|
|
104
|
+
nav.lg .current {
|
|
105
|
+
font-size: 1.15rem;
|
|
106
|
+
}
|
|
107
|
+
nav.xl .page {
|
|
108
|
+
font-size: 1.05rem;
|
|
109
|
+
padding: 0.5rem 0.65rem 0.5rem 0.65rem;
|
|
110
|
+
}
|
|
111
|
+
nav.xl .current {
|
|
112
|
+
font-size: 1.25rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
nav.flat button:hover {
|
|
116
|
+
color: var(--form-input-bg, #fff);
|
|
117
|
+
background: var(--form-input-fg, #000);
|
|
118
|
+
border-radius: 0.5rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@media (max-width: 600px) {
|
|
122
|
+
nav {
|
|
123
|
+
gap: 0rem;
|
|
124
|
+
}
|
|
125
|
+
nav .pre,
|
|
126
|
+
nav .pro {
|
|
127
|
+
display: none;
|
|
128
|
+
}
|
|
129
|
+
}</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
currentPage?: number | undefined;
|
|
5
|
+
totalPages?: number | undefined;
|
|
6
|
+
align?: "center" | "end" | "start" | undefined;
|
|
7
|
+
style?: "default" | "flat" | undefined;
|
|
8
|
+
size?: "sm" | "md" | "lg" | "xl" | undefined;
|
|
9
|
+
};
|
|
10
|
+
events: {
|
|
11
|
+
page: CustomEvent<number>;
|
|
12
|
+
} & {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {};
|
|
16
|
+
};
|
|
17
|
+
export type PaginationProps = typeof __propDef.props;
|
|
18
|
+
export type PaginationEvents = typeof __propDef.events;
|
|
19
|
+
export type PaginationSlots = typeof __propDef.slots;
|
|
20
|
+
export default class Pagination extends SvelteComponent<PaginationProps, PaginationEvents, PaginationSlots> {
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<script>import { getContext
|
|
1
|
+
<script>import { getContext } from "svelte";
|
|
2
|
+
import Notice from "../../generic/notice/notice.svelte";
|
|
2
3
|
const wizard = getContext("wizard");
|
|
3
4
|
const state = wizard.state;
|
|
4
5
|
export let step;
|
|
@@ -6,9 +7,16 @@ export let subtitle;
|
|
|
6
7
|
wizard.register(step, subtitle);
|
|
7
8
|
$:
|
|
8
9
|
isCurrentStep = $state.currentStep === step;
|
|
10
|
+
$:
|
|
11
|
+
errors = $state.errors;
|
|
9
12
|
</script>
|
|
10
13
|
|
|
11
14
|
<div class="step {isCurrentStep ? 'current' : ''}">
|
|
15
|
+
{#if errors.length}
|
|
16
|
+
<div class="errors">
|
|
17
|
+
<Notice style="error" size="md">{errors.join(' ')}</Notice>
|
|
18
|
+
</div>
|
|
19
|
+
{/if}
|
|
12
20
|
<slot />
|
|
13
21
|
</div>
|
|
14
22
|
|
|
@@ -17,4 +25,10 @@ $:
|
|
|
17
25
|
}
|
|
18
26
|
.step.current {
|
|
19
27
|
display: block;
|
|
28
|
+
}
|
|
29
|
+
.step .errors {
|
|
30
|
+
margin-bottom: 1rem;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: 1rem;
|
|
20
34
|
}</style>
|
|
@@ -9,18 +9,21 @@ export let disabled = false;
|
|
|
9
9
|
export let onNext = async () => [];
|
|
10
10
|
export let onSubmit = async () => [];
|
|
11
11
|
let currentStep = 0;
|
|
12
|
+
let errors = [];
|
|
12
13
|
const dispatch = createEventDispatcher();
|
|
13
14
|
const steps = {};
|
|
14
15
|
const wizardStore = writable({
|
|
15
16
|
currentStep,
|
|
16
17
|
totalSteps: 0,
|
|
17
|
-
disabled
|
|
18
|
+
disabled,
|
|
19
|
+
errors
|
|
18
20
|
});
|
|
19
21
|
const publish = () => {
|
|
20
22
|
wizardStore.set({
|
|
21
23
|
currentStep,
|
|
22
24
|
totalSteps: Object.values(steps).length,
|
|
23
|
-
disabled
|
|
25
|
+
disabled,
|
|
26
|
+
errors
|
|
24
27
|
});
|
|
25
28
|
};
|
|
26
29
|
const register = (stepNumber, subtitle2) => {
|
|
@@ -29,7 +32,7 @@ const register = (stepNumber, subtitle2) => {
|
|
|
29
32
|
};
|
|
30
33
|
const validate = async (callback) => {
|
|
31
34
|
disabled = true;
|
|
32
|
-
|
|
35
|
+
errors = await callback() || [];
|
|
33
36
|
disabled = false;
|
|
34
37
|
dispatch("errors", errors);
|
|
35
38
|
return errors;
|
|
@@ -37,9 +40,11 @@ const validate = async (callback) => {
|
|
|
37
40
|
const next = async () => {
|
|
38
41
|
if (currentStep >= Object.values(steps).length || disabled)
|
|
39
42
|
return;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
if (currentStep) {
|
|
44
|
+
const errors2 = await validate(() => onNext(currentStep));
|
|
45
|
+
if (errors2.length)
|
|
46
|
+
return publish();
|
|
47
|
+
}
|
|
43
48
|
currentStep++;
|
|
44
49
|
dispatch("next", currentStep);
|
|
45
50
|
publish();
|
|
@@ -48,6 +53,7 @@ const previous = () => {
|
|
|
48
53
|
if (currentStep <= 1 || disabled)
|
|
49
54
|
return;
|
|
50
55
|
currentStep--;
|
|
56
|
+
errors = [];
|
|
51
57
|
dispatch("previous", currentStep);
|
|
52
58
|
publish();
|
|
53
59
|
};
|
|
@@ -57,9 +63,9 @@ const reset = () => {
|
|
|
57
63
|
publish();
|
|
58
64
|
};
|
|
59
65
|
const done = async () => {
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
return;
|
|
66
|
+
const errors2 = await validate(onSubmit);
|
|
67
|
+
if (errors2.length)
|
|
68
|
+
return publish();
|
|
63
69
|
dispatch("done");
|
|
64
70
|
reset();
|
|
65
71
|
};
|
|
@@ -5,8 +5,8 @@ declare const __propDef: {
|
|
|
5
5
|
title: string;
|
|
6
6
|
level?: SectionLevel | undefined;
|
|
7
7
|
disabled?: boolean | undefined;
|
|
8
|
-
onNext?: ((step: number) => Promise<string[]>) | undefined;
|
|
9
|
-
onSubmit?: (() => Promise<string[]>) | undefined;
|
|
8
|
+
onNext?: ((step: number) => Promise<string[] | void>) | undefined;
|
|
9
|
+
onSubmit?: (() => Promise<string[] | void>) | undefined;
|
|
10
10
|
};
|
|
11
11
|
events: {
|
|
12
12
|
done: CustomEvent<void>;
|
|
@@ -10,8 +10,8 @@ import TableRow from "./table-row.svelte";
|
|
|
10
10
|
import Table from "./table.svelte";
|
|
11
11
|
import Empty from "../generic/empty/empty.svelte";
|
|
12
12
|
import FolderOpenIcon from "../icons/folder-open-icon.svelte";
|
|
13
|
+
import Pagination from "../navigation/pagination/pagination.svelte";
|
|
13
14
|
import Loading from "../placeholders/loading.svelte";
|
|
14
|
-
import Text from "../typography/text.svelte";
|
|
15
15
|
import TableCaption from "./table-caption.svelte";
|
|
16
16
|
export let caption = "";
|
|
17
17
|
export let rows = void 0;
|
|
@@ -19,6 +19,7 @@ export let cols;
|
|
|
19
19
|
export let pagination = void 0;
|
|
20
20
|
export let editRow = void 0;
|
|
21
21
|
export let deleteRow = void 0;
|
|
22
|
+
export let onPageChange = null;
|
|
22
23
|
const getColType = (col) => {
|
|
23
24
|
if (col.type)
|
|
24
25
|
return col.type;
|
|
@@ -42,12 +43,37 @@ const format = (row, key) => {
|
|
|
42
43
|
return col.format(row, key);
|
|
43
44
|
return row[key];
|
|
44
45
|
};
|
|
46
|
+
const calculateTotalPages = () => {
|
|
47
|
+
if (!pagination || !rows)
|
|
48
|
+
return 1;
|
|
49
|
+
const totalRows = Math.max(pagination.total || rows.length);
|
|
50
|
+
return Math.ceil(totalRows / pagination.perPage);
|
|
51
|
+
};
|
|
52
|
+
const changePage = async (e) => {
|
|
53
|
+
pagination = { page: e.detail, perPage: pagination?.perPage || 5 };
|
|
54
|
+
if (onPageChange) {
|
|
55
|
+
rows = await onPageChange(pagination);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const filterRows = () => {
|
|
59
|
+
if (!rows?.length || !pagination)
|
|
60
|
+
return rows;
|
|
61
|
+
if (onPageChange)
|
|
62
|
+
return rows;
|
|
63
|
+
const currentPage = pagination.page || 1;
|
|
64
|
+
const perPage = pagination.perPage || 5;
|
|
65
|
+
const startIndex = currentPage * perPage - perPage;
|
|
66
|
+
const endIndex = startIndex + perPage;
|
|
67
|
+
return rows.filter((_row, index) => index >= startIndex && index < endIndex);
|
|
68
|
+
};
|
|
45
69
|
$:
|
|
46
70
|
hasActionRow = editRow || deleteRow;
|
|
47
71
|
$:
|
|
48
72
|
colCount = Math.max(1, cols.filter((col) => !col.hide).length) + (hasActionRow ? 1 : 0);
|
|
49
73
|
$:
|
|
50
|
-
totalPages = pagination && rows ?
|
|
74
|
+
totalPages = pagination && rows ? calculateTotalPages() : 1;
|
|
75
|
+
$:
|
|
76
|
+
filteredRows = rows && pagination ? filterRows() : rows;
|
|
51
77
|
</script>
|
|
52
78
|
|
|
53
79
|
<Table>
|
|
@@ -58,7 +84,7 @@ $:
|
|
|
58
84
|
<TableHeaderRow>
|
|
59
85
|
{#each cols as col}
|
|
60
86
|
{#if !col.hide}
|
|
61
|
-
<TableHeaderCell type={getColType(col)}>{col.label}</TableHeaderCell>
|
|
87
|
+
<TableHeaderCell type={getColType(col)} width={col.width}>{col.label}</TableHeaderCell>
|
|
62
88
|
{/if}
|
|
63
89
|
{/each}
|
|
64
90
|
{#if hasActionRow}
|
|
@@ -67,7 +93,7 @@ $:
|
|
|
67
93
|
</TableHeaderRow>
|
|
68
94
|
</TableHeader>
|
|
69
95
|
<TableBody>
|
|
70
|
-
{#if !
|
|
96
|
+
{#if !filteredRows?.length}
|
|
71
97
|
<TableRow>
|
|
72
98
|
<TableCell colspan={colCount}>
|
|
73
99
|
<div class="empty">
|
|
@@ -82,11 +108,11 @@ $:
|
|
|
82
108
|
</TableCell>
|
|
83
109
|
</TableRow>
|
|
84
110
|
{:else}
|
|
85
|
-
{#each
|
|
111
|
+
{#each filteredRows as row}
|
|
86
112
|
<TableRow>
|
|
87
113
|
{#each cols as col}
|
|
88
114
|
{#if !col.hide}
|
|
89
|
-
<TableCell type={col.type || typeof row[col.key]}>
|
|
115
|
+
<TableCell type={col.type || typeof row[col.key]} width={col.width}>
|
|
90
116
|
{#if col.link}
|
|
91
117
|
<a href={col.link(row, col.key)}>{format(row, col.key)}</a>
|
|
92
118
|
{:else}
|
|
@@ -113,9 +139,14 @@ $:
|
|
|
113
139
|
<TableFooter>
|
|
114
140
|
<TableFooterRow>
|
|
115
141
|
<TableFooterCell colspan={colCount}>
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
142
|
+
<Pagination
|
|
143
|
+
currentPage={pagination.page}
|
|
144
|
+
{totalPages}
|
|
145
|
+
style="flat"
|
|
146
|
+
size="sm"
|
|
147
|
+
align="center"
|
|
148
|
+
on:page={changePage}
|
|
149
|
+
/>
|
|
119
150
|
</TableFooterCell>
|
|
120
151
|
</TableFooterRow>
|
|
121
152
|
</TableFooter>
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type { DataCol, DataRow,
|
|
2
|
+
import type { DataCol, DataRow, PaginationProperties } from '../types/data.js';
|
|
3
3
|
declare const __propDef: {
|
|
4
4
|
props: {
|
|
5
5
|
caption?: string | undefined;
|
|
6
6
|
rows?: DataRow[] | undefined;
|
|
7
7
|
cols: DataCol[];
|
|
8
|
-
pagination?:
|
|
8
|
+
pagination?: PaginationProperties | undefined;
|
|
9
9
|
editRow?: ((row: DataRow) => unknown) | undefined;
|
|
10
10
|
deleteRow?: ((row: DataRow) => unknown) | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Handle page change, which should return the new filtered/fetched rows.
|
|
13
|
+
*/ onPageChange?: ((pagination: PaginationProperties) => Promise<DataRow[]>) | null | undefined;
|
|
11
14
|
};
|
|
12
15
|
events: {
|
|
13
16
|
[evt: string]: CustomEvent<any>;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
<script>export let colspan = 1;
|
|
2
2
|
export let type = void 0;
|
|
3
|
+
export let width = void 0;
|
|
4
|
+
$:
|
|
5
|
+
styleProperties = [
|
|
6
|
+
`text-align: ${type === "currency" || type === "number" ? "right" : type === "boolean" ? "center" : "left"}`,
|
|
7
|
+
`width: ${width ? width : "auto"}`
|
|
8
|
+
];
|
|
3
9
|
</script>
|
|
4
10
|
|
|
5
|
-
<td {colspan} class={type}>
|
|
11
|
+
<td {colspan} class={type} style={styleProperties.join('; ')}>
|
|
6
12
|
<slot />
|
|
7
13
|
</td>
|
|
8
14
|
|
|
9
15
|
<style>td {
|
|
10
|
-
padding: 0.
|
|
16
|
+
padding: 0.25rem;
|
|
11
17
|
font-size: 1rem;
|
|
12
18
|
}
|
|
13
19
|
td.currency, td.number {
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
</script>
|
|
3
3
|
|
|
4
4
|
<td {colspan}>
|
|
5
|
-
<
|
|
5
|
+
<div>
|
|
6
|
+
<slot />
|
|
7
|
+
</div>
|
|
6
8
|
</td>
|
|
7
9
|
|
|
8
10
|
<style>
|
|
@@ -12,4 +14,10 @@
|
|
|
12
14
|
font-family: sans-serif;
|
|
13
15
|
text-shadow: 1px 1px 1px black;
|
|
14
16
|
}
|
|
17
|
+
|
|
18
|
+
div {
|
|
19
|
+
display: flex;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
align-items: center;
|
|
22
|
+
}
|
|
15
23
|
</style>
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
<script>export let colspan = 1;
|
|
2
2
|
export let type = void 0;
|
|
3
|
+
export let width = void 0;
|
|
4
|
+
$:
|
|
5
|
+
styleProperties = [
|
|
6
|
+
`text-align: ${type === "currency" || type === "number" ? "right" : type === "boolean" ? "center" : "left"}`,
|
|
7
|
+
"text-overflow: ellipsis",
|
|
8
|
+
"overflow: hidden",
|
|
9
|
+
`width: ${width ? width : "auto"}`
|
|
10
|
+
];
|
|
3
11
|
</script>
|
|
4
12
|
|
|
5
|
-
<th {colspan} class={type}>
|
|
13
|
+
<th {colspan} class={type} style={styleProperties.join('; ')}>
|
|
6
14
|
<slot />
|
|
7
15
|
</th>
|
|
8
16
|
|
package/dist/types/data.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ export type DataCol<T extends DataRow = DataRow> = {
|
|
|
6
6
|
format?: (row: T, key: keyof T) => string;
|
|
7
7
|
link?: (row: T, key: keyof T) => string;
|
|
8
8
|
hide?: boolean;
|
|
9
|
+
width?: number | string;
|
|
9
10
|
};
|
|
10
|
-
export type
|
|
11
|
+
export type PaginationProperties = {
|
|
11
12
|
page: number;
|
|
12
13
|
perPage: number;
|
|
13
14
|
total?: number;
|