@bexis2/bexis2-core-ui 0.2.14 → 0.2.16
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 +11 -0
- package/dist/components/Table/Table.svelte +101 -86
- package/dist/components/Table/TableFilter.svelte +2 -2
- package/dist/components/form/MultiSelect.svelte +2 -0
- package/dist/components/form/MultiSelect.svelte.d.ts +2 -0
- package/dist/components/page/Page.svelte +56 -56
- package/dist/models/Models.d.ts +1 -0
- package/package.json +1 -1
- package/src/lib/components/Table/Table.svelte +262 -246
- package/src/lib/components/Table/TableFilter.svelte +2 -2
- package/src/lib/components/form/MultiSelect.svelte +2 -0
- package/src/lib/components/page/Page.svelte +96 -96
- package/src/lib/models/Models.ts +134 -133
|
@@ -1,246 +1,262 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { createEventDispatcher } from 'svelte';
|
|
3
|
-
import { createTable, Subscribe, Render, createRender } from 'svelte-headless-table';
|
|
4
|
-
import {
|
|
5
|
-
addSortBy,
|
|
6
|
-
addPagination,
|
|
7
|
-
addExpandedRows,
|
|
8
|
-
addColumnFilters,
|
|
9
|
-
addTableFilter
|
|
10
|
-
} from 'svelte-headless-table/plugins';
|
|
11
|
-
import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floating-ui/dom';
|
|
12
|
-
import { storePopup } from '@skeletonlabs/skeleton';
|
|
13
|
-
|
|
14
|
-
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
|
15
|
-
|
|
16
|
-
import TableFilter from './TableFilter.svelte';
|
|
17
|
-
import TablePagination from './TablePagination.svelte';
|
|
18
|
-
import { columnFilter, searchFilter } from './filter';
|
|
19
|
-
import type { TableConfig } from '$lib/models/Models';
|
|
20
|
-
|
|
21
|
-
export let config: TableConfig<any>;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
3
|
+
import { createTable, Subscribe, Render, createRender } from 'svelte-headless-table';
|
|
4
|
+
import {
|
|
5
|
+
addSortBy,
|
|
6
|
+
addPagination,
|
|
7
|
+
addExpandedRows,
|
|
8
|
+
addColumnFilters,
|
|
9
|
+
addTableFilter
|
|
10
|
+
} from 'svelte-headless-table/plugins';
|
|
11
|
+
import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floating-ui/dom';
|
|
12
|
+
import { SlideToggle, storePopup } from '@skeletonlabs/skeleton';
|
|
13
|
+
|
|
14
|
+
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
|
15
|
+
|
|
16
|
+
import TableFilter from './TableFilter.svelte';
|
|
17
|
+
import TablePagination from './TablePagination.svelte';
|
|
18
|
+
import { columnFilter, searchFilter } from './filter';
|
|
19
|
+
import type { TableConfig } from '$lib/models/Models';
|
|
20
|
+
|
|
21
|
+
export let config: TableConfig<any>;
|
|
22
|
+
|
|
23
|
+
let {
|
|
24
|
+
id: tableId,
|
|
25
|
+
data,
|
|
26
|
+
columns,
|
|
27
|
+
height = null,
|
|
28
|
+
optionsComponent,
|
|
29
|
+
defaultPageSize = 10,
|
|
30
|
+
pageSizes = [5, 10, 15, 20]
|
|
31
|
+
} = config;
|
|
32
|
+
let fitToScreen = true;
|
|
33
|
+
|
|
34
|
+
type AccessorType = keyof (typeof $data)[number];
|
|
35
|
+
|
|
36
|
+
const dispatch = createEventDispatcher();
|
|
37
|
+
const actionDispatcher = (obj) => dispatch('action', obj);
|
|
38
|
+
|
|
39
|
+
const table = createTable(data, {
|
|
40
|
+
colFilter: addColumnFilters(),
|
|
41
|
+
tableFilter: addTableFilter({
|
|
42
|
+
fn: searchFilter
|
|
43
|
+
}),
|
|
44
|
+
sort: addSortBy({ disableMultiSort: true }),
|
|
45
|
+
page: addPagination({ initialPageSize: defaultPageSize }),
|
|
46
|
+
expand: addExpandedRows()
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const accessors: AccessorType[] =
|
|
50
|
+
$data.length > 0 ? (Object.keys($data[0]) as AccessorType[]) : [];
|
|
51
|
+
|
|
52
|
+
const tableColumns = [
|
|
53
|
+
...accessors
|
|
54
|
+
.filter((accessor) => {
|
|
55
|
+
const key = accessor as string;
|
|
56
|
+
if (columns !== undefined && key in columns && columns[key].exclude === true) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
})
|
|
61
|
+
.map((accessor) => {
|
|
62
|
+
const key = accessor as string;
|
|
63
|
+
if (columns !== undefined && key in columns) {
|
|
64
|
+
const {
|
|
65
|
+
header,
|
|
66
|
+
colFilterFn,
|
|
67
|
+
colFilterComponent,
|
|
68
|
+
instructions,
|
|
69
|
+
disableFiltering = false,
|
|
70
|
+
disableSorting = false
|
|
71
|
+
} = columns[key];
|
|
72
|
+
|
|
73
|
+
const { toSortableValueFn, toFilterableValueFn, toStringFn, renderComponent } =
|
|
74
|
+
instructions ?? {};
|
|
75
|
+
|
|
76
|
+
return table.column({
|
|
77
|
+
header: header ?? key,
|
|
78
|
+
accessor: accessor,
|
|
79
|
+
cell: ({ value, row }) => {
|
|
80
|
+
return renderComponent
|
|
81
|
+
? createRender(renderComponent, { value, row })
|
|
82
|
+
: toStringFn
|
|
83
|
+
? toStringFn(value)
|
|
84
|
+
: value;
|
|
85
|
+
},
|
|
86
|
+
plugins: {
|
|
87
|
+
sort: {
|
|
88
|
+
disable: disableSorting,
|
|
89
|
+
invert: true,
|
|
90
|
+
getSortValue: (row) => {
|
|
91
|
+
return toSortableValueFn ? toSortableValueFn(row) : row;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
colFilter: !disableFiltering
|
|
95
|
+
? {
|
|
96
|
+
fn: ({ filterValue, value }) => {
|
|
97
|
+
const val = toFilterableValueFn ? toFilterableValueFn(value) : value;
|
|
98
|
+
|
|
99
|
+
return colFilterFn
|
|
100
|
+
? colFilterFn({ filterValue, value: val })
|
|
101
|
+
: columnFilter({ filterValue, value: val });
|
|
102
|
+
},
|
|
103
|
+
render: ({ filterValue, values, id }) => {
|
|
104
|
+
return createRender(colFilterComponent ?? TableFilter, {
|
|
105
|
+
filterValue,
|
|
106
|
+
id,
|
|
107
|
+
tableId,
|
|
108
|
+
values,
|
|
109
|
+
toFilterableValueFn
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
: undefined,
|
|
114
|
+
tableFilter: {
|
|
115
|
+
getFilterValue: (row) => {
|
|
116
|
+
return toStringFn ? toStringFn(row) : row;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
return table.column({
|
|
123
|
+
header: key,
|
|
124
|
+
accessor: accessor,
|
|
125
|
+
plugins: {
|
|
126
|
+
sort: {
|
|
127
|
+
invert: true
|
|
128
|
+
},
|
|
129
|
+
colFilter: {
|
|
130
|
+
fn: columnFilter,
|
|
131
|
+
render: ({ filterValue, values, id }) =>
|
|
132
|
+
createRender(TableFilter, {
|
|
133
|
+
filterValue,
|
|
134
|
+
id,
|
|
135
|
+
tableId,
|
|
136
|
+
values
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
if (optionsComponent !== undefined) {
|
|
146
|
+
tableColumns.push(
|
|
147
|
+
table.display({
|
|
148
|
+
id: 'options',
|
|
149
|
+
header: '',
|
|
150
|
+
cell: ({ row }, _) => {
|
|
151
|
+
return createRender(optionsComponent!, {
|
|
152
|
+
row: row.isData() ? row.original : null,
|
|
153
|
+
dispatchFn: actionDispatcher
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}) as any
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const createdTableColumns = table.createColumns(tableColumns);
|
|
161
|
+
|
|
162
|
+
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } =
|
|
163
|
+
table.createViewModel(createdTableColumns);
|
|
164
|
+
const { filterValue } = pluginStates.tableFilter;
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<div class="grid gap-2 overflow-auto" class:w-max={!fitToScreen} class:w-full={fitToScreen}>
|
|
168
|
+
<div class="table-container">
|
|
169
|
+
{#if $data.length > 0}
|
|
170
|
+
<input
|
|
171
|
+
class="input p-2 mb-2 border border-primary-500"
|
|
172
|
+
type="text"
|
|
173
|
+
bind:value={$filterValue}
|
|
174
|
+
placeholder="Search rows..."
|
|
175
|
+
/>
|
|
176
|
+
{/if}
|
|
177
|
+
<SlideToggle
|
|
178
|
+
name="slider-label"
|
|
179
|
+
active="bg-primary-500"
|
|
180
|
+
size="sm"
|
|
181
|
+
checked={fitToScreen}
|
|
182
|
+
on:change={() => (fitToScreen = !fitToScreen)}>Fit to screen</SlideToggle
|
|
183
|
+
>
|
|
184
|
+
|
|
185
|
+
<div class="overflow-auto" style="height: {height}px">
|
|
186
|
+
<table {...$tableAttrs} class="table table-compact bg-tertiary-200 overflow-clip">
|
|
187
|
+
<thead class={height != null ? `sticky top-0` : ''}>
|
|
188
|
+
{#each $headerRows as headerRow (headerRow.id)}
|
|
189
|
+
<Subscribe
|
|
190
|
+
rowAttrs={headerRow.attrs()}
|
|
191
|
+
let:rowAttrs
|
|
192
|
+
rowProps={headerRow.props()}
|
|
193
|
+
let:rowProps
|
|
194
|
+
>
|
|
195
|
+
<tr {...rowAttrs} class="bg-primary-300">
|
|
196
|
+
{#each headerRow.cells as cell (cell.id)}
|
|
197
|
+
<Subscribe attrs={cell.attrs()} props={cell.props()} let:props let:attrs>
|
|
198
|
+
<th scope="col" class="!p-2 w-min" {...attrs}>
|
|
199
|
+
<div class="flex w-full justify-between items-center">
|
|
200
|
+
<div class="flex gap-1 whitespace-pre-wrap">
|
|
201
|
+
<span
|
|
202
|
+
class:underline={props.sort.order}
|
|
203
|
+
class:normal-case={cell.id !== cell.label}
|
|
204
|
+
class:cursor-pointer={!props.sort.disabled}
|
|
205
|
+
on:click={props.sort.toggle}
|
|
206
|
+
on:keydown={props.sort.toggle}
|
|
207
|
+
>
|
|
208
|
+
{cell.render()}
|
|
209
|
+
</span>
|
|
210
|
+
<div class="w-2">
|
|
211
|
+
{#if props.sort.order === 'asc'}
|
|
212
|
+
▾
|
|
213
|
+
{:else if props.sort.order === 'desc'}
|
|
214
|
+
▴
|
|
215
|
+
{/if}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
{#if cell.isData()}
|
|
219
|
+
{#if props.colFilter?.render}
|
|
220
|
+
<div class="">
|
|
221
|
+
<Render of={props.colFilter.render} />
|
|
222
|
+
</div>
|
|
223
|
+
{/if}
|
|
224
|
+
{/if}
|
|
225
|
+
</div>
|
|
226
|
+
</th>
|
|
227
|
+
</Subscribe>
|
|
228
|
+
{/each}
|
|
229
|
+
</tr>
|
|
230
|
+
</Subscribe>
|
|
231
|
+
{:else}
|
|
232
|
+
<p class="items-center justify-center flex w-full p-10 italic">Nothing to show here.</p>
|
|
233
|
+
{/each}
|
|
234
|
+
</thead>
|
|
235
|
+
|
|
236
|
+
<tbody class="overflow-auto" {...$tableBodyAttrs}>
|
|
237
|
+
{#each $pageRows as row (row.id)}
|
|
238
|
+
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
|
|
239
|
+
<tr {...rowAttrs}>
|
|
240
|
+
{#each row.cells as cell (cell?.id)}
|
|
241
|
+
<Subscribe attrs={cell.attrs()} let:attrs>
|
|
242
|
+
<td {...attrs} class="!p-2 w-max focus:resize">
|
|
243
|
+
<div
|
|
244
|
+
class="flex items-center h-max overflow-x-auto resize-none hover:resize"
|
|
245
|
+
class:max-w-md={!fitToScreen}
|
|
246
|
+
>
|
|
247
|
+
<Render of={cell.render()} />
|
|
248
|
+
</div>
|
|
249
|
+
</td>
|
|
250
|
+
</Subscribe>
|
|
251
|
+
{/each}
|
|
252
|
+
</tr>
|
|
253
|
+
</Subscribe>
|
|
254
|
+
{/each}
|
|
255
|
+
</tbody>
|
|
256
|
+
</table>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
{#if $data.length > 0}
|
|
260
|
+
<TablePagination pageConfig={pluginStates.page} {pageSizes} />
|
|
261
|
+
{/if}
|
|
262
|
+
</div>
|
|
@@ -123,8 +123,8 @@
|
|
|
123
123
|
<Fa icon={faFilter} size="12" />
|
|
124
124
|
</button>
|
|
125
125
|
|
|
126
|
-
<div data-popup={`${popupId}`}>
|
|
127
|
-
<div class="card p-3
|
|
126
|
+
<div data-popup={`${popupId}`} class="z-50">
|
|
127
|
+
<div class="card p-3 grid gap-2 shadow-lg w-min bg-base-100">
|
|
128
128
|
<button
|
|
129
129
|
class="btn variant-filled-primary btn-sm"
|
|
130
130
|
type="button"
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
export let invalid = false;
|
|
21
21
|
export let loading = false;
|
|
22
22
|
export let help = false;
|
|
23
|
+
export let clearable = true;
|
|
23
24
|
|
|
24
25
|
let isLoaded = false;
|
|
25
26
|
|
|
@@ -150,6 +151,7 @@
|
|
|
150
151
|
{placeholder}
|
|
151
152
|
hasError={invalid}
|
|
152
153
|
{loading}
|
|
154
|
+
{clearable}
|
|
153
155
|
on:change
|
|
154
156
|
on:input
|
|
155
157
|
on:focus
|