@bexis2/bexis2-core-ui 0.3.4 → 0.3.6
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 +13 -0
- package/dist/components/File/FileUploader.svelte +7 -0
- package/dist/components/Table/Table.svelte +5 -379
- package/dist/components/Table/Table.svelte.d.ts +1 -12
- package/dist/components/Table/TableContent.svelte +382 -0
- package/dist/components/Table/TableContent.svelte.d.ts +19 -0
- package/dist/components/form/InputContainer.svelte +1 -1
- package/dist/components/page/Docs.svelte +1 -1
- package/package.json +1 -1
- package/src/lib/components/Table/Table.svelte +6 -437
- package/src/lib/components/Table/TableContent.svelte +442 -0
- package/src/lib/components/file/FileUploader.svelte +9 -0
- package/src/lib/components/form/InputContainer.svelte +1 -1
- package/src/lib/components/page/Docs.svelte +1 -1
package/README.md
CHANGED
|
@@ -9,10 +9,12 @@ import { Api } from "../../services/Api.js";
|
|
|
9
9
|
export let id = 0;
|
|
10
10
|
export let version = 1;
|
|
11
11
|
import { onMount } from "svelte";
|
|
12
|
+
import { ProgressBar } from "@skeletonlabs/skeleton";
|
|
12
13
|
export let start = "";
|
|
13
14
|
export let submit = "";
|
|
14
15
|
export let context = "";
|
|
15
16
|
export let data;
|
|
17
|
+
let isUploading = false;
|
|
16
18
|
$:
|
|
17
19
|
model = data;
|
|
18
20
|
$:
|
|
@@ -72,6 +74,7 @@ function getErrorMessage(rejected) {
|
|
|
72
74
|
}
|
|
73
75
|
async function handleSubmit() {
|
|
74
76
|
dispatch("submit");
|
|
77
|
+
isUploading = true;
|
|
75
78
|
let url = submit + "?id=" + id;
|
|
76
79
|
if (files.accepted.length > 0) {
|
|
77
80
|
const formData = new FormData();
|
|
@@ -89,6 +92,7 @@ async function handleSubmit() {
|
|
|
89
92
|
files.accepted = [];
|
|
90
93
|
}
|
|
91
94
|
}
|
|
95
|
+
isUploading = false;
|
|
92
96
|
}
|
|
93
97
|
</script>
|
|
94
98
|
|
|
@@ -115,6 +119,9 @@ async function handleSubmit() {
|
|
|
115
119
|
{/if}
|
|
116
120
|
</p>
|
|
117
121
|
</DropZone>
|
|
122
|
+
{#if isUploading}
|
|
123
|
+
<ProgressBar value={undefined}/>
|
|
124
|
+
{/if}
|
|
118
125
|
</div>
|
|
119
126
|
|
|
120
127
|
<button id={submitBt} color="primary" style="display:none"><Fa icon={faSave} /></button>
|
|
@@ -1,382 +1,8 @@
|
|
|
1
|
-
<script>import
|
|
2
|
-
import { createTable, Subscribe, Render, createRender } from "svelte-headless-table";
|
|
3
|
-
import {
|
|
4
|
-
addSortBy,
|
|
5
|
-
addPagination,
|
|
6
|
-
addExpandedRows,
|
|
7
|
-
addColumnFilters,
|
|
8
|
-
addTableFilter,
|
|
9
|
-
addDataExport
|
|
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
|
-
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
|
14
|
-
import TableFilter from "./TableFilter.svelte";
|
|
15
|
-
import TablePagination from "./TablePagination.svelte";
|
|
16
|
-
import { columnFilter, searchFilter } from "./filter";
|
|
1
|
+
<script>import Table from "./TableContent.svelte";
|
|
17
2
|
export let config;
|
|
18
|
-
|
|
19
|
-
id: tableId,
|
|
20
|
-
// Unique table ID
|
|
21
|
-
data,
|
|
22
|
-
// Data store
|
|
23
|
-
columns,
|
|
24
|
-
// Column configuration
|
|
25
|
-
resizable = "none",
|
|
26
|
-
// Resizability config
|
|
27
|
-
height = null,
|
|
28
|
-
// Table height
|
|
29
|
-
rowHeight = null,
|
|
30
|
-
// Row height
|
|
31
|
-
optionsComponent,
|
|
32
|
-
// Custom component to render in the last column
|
|
33
|
-
defaultPageSize = 10,
|
|
34
|
-
// Default page size - number of rows to display per page
|
|
35
|
-
toggle = false,
|
|
36
|
-
// Whether to display the fitToScreen toggle
|
|
37
|
-
pageSizes = [5, 10, 15, 20],
|
|
38
|
-
// Page sizes to display in the pagination component
|
|
39
|
-
fitToScreen = true,
|
|
40
|
-
// Whether to fit the table to the screen,
|
|
41
|
-
exportable = false
|
|
42
|
-
// Whether to display the export button and enable export functionality
|
|
43
|
-
} = config;
|
|
44
|
-
const dispatch = createEventDispatcher();
|
|
45
|
-
const actionDispatcher = (obj) => dispatch("action", obj);
|
|
46
|
-
const table = createTable(data, {
|
|
47
|
-
colFilter: addColumnFilters(),
|
|
48
|
-
tableFilter: addTableFilter({
|
|
49
|
-
fn: searchFilter
|
|
50
|
-
}),
|
|
51
|
-
sort: addSortBy({ disableMultiSort: true }),
|
|
52
|
-
page: addPagination({ initialPageSize: defaultPageSize }),
|
|
53
|
-
expand: addExpandedRows(),
|
|
54
|
-
export: addDataExport({ format: "csv" })
|
|
55
|
-
});
|
|
56
|
-
const allCols = {};
|
|
57
|
-
$data.forEach((item) => {
|
|
58
|
-
Object.keys(item).forEach((key) => {
|
|
59
|
-
if (!allCols[key]) {
|
|
60
|
-
allCols[key] = {};
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
const accessors = Object.keys(allCols);
|
|
65
|
-
const tableColumns = [
|
|
66
|
-
...accessors.filter((accessor) => {
|
|
67
|
-
const key = accessor;
|
|
68
|
-
if (columns !== void 0 && key in columns && columns[key].exclude === true) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
return true;
|
|
72
|
-
}).map((accessor) => {
|
|
73
|
-
const key = accessor;
|
|
74
|
-
if (columns !== void 0 && key in columns) {
|
|
75
|
-
const {
|
|
76
|
-
header,
|
|
77
|
-
// Custom header to display
|
|
78
|
-
colFilterFn,
|
|
79
|
-
// Custom column filter function
|
|
80
|
-
colFilterComponent,
|
|
81
|
-
// Custom column filter component
|
|
82
|
-
instructions,
|
|
83
|
-
// Custom instructions for the column cells (sorting, filtering, searching, rendering)
|
|
84
|
-
disableFiltering = false,
|
|
85
|
-
// Whether to disable filtering for the column
|
|
86
|
-
disableSorting = false
|
|
87
|
-
// Whether to disable sorting for the column
|
|
88
|
-
} = columns[key];
|
|
89
|
-
const { toSortableValueFn, toFilterableValueFn, toStringFn, renderComponent } = instructions ?? {};
|
|
90
|
-
return table.column({
|
|
91
|
-
// If header is not provided, use the key as the header
|
|
92
|
-
header: header ?? key,
|
|
93
|
-
accessor,
|
|
94
|
-
// Render the cell with the provided component, or use the toStringFn if provided, or just use the value
|
|
95
|
-
cell: ({ value, row }) => {
|
|
96
|
-
return renderComponent ? createRender(renderComponent, { value, row }) : toStringFn ? toStringFn(value) : value;
|
|
97
|
-
},
|
|
98
|
-
plugins: {
|
|
99
|
-
// Sorting config
|
|
100
|
-
sort: {
|
|
101
|
-
disable: disableSorting,
|
|
102
|
-
invert: true,
|
|
103
|
-
getSortValue: (row) => {
|
|
104
|
-
return toSortableValueFn ? toSortableValueFn(row) : row;
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
colFilter: !disableFiltering ? {
|
|
108
|
-
fn: ({ filterValue: filterValue2, value }) => {
|
|
109
|
-
const val = toFilterableValueFn ? toFilterableValueFn(value) : value;
|
|
110
|
-
return colFilterFn ? colFilterFn({ filterValue: filterValue2, value: val }) : columnFilter({ filterValue: filterValue2, value: val });
|
|
111
|
-
},
|
|
112
|
-
render: ({ filterValue: filterValue2, values, id }) => {
|
|
113
|
-
return createRender(colFilterComponent ?? TableFilter, {
|
|
114
|
-
filterValue: filterValue2,
|
|
115
|
-
id,
|
|
116
|
-
tableId,
|
|
117
|
-
values,
|
|
118
|
-
toFilterableValueFn
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
} : void 0,
|
|
122
|
-
tableFilter: {
|
|
123
|
-
// Search filter config
|
|
124
|
-
getFilterValue: (row) => {
|
|
125
|
-
return toStringFn ? toStringFn(row) : row;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
} else {
|
|
131
|
-
return table.column({
|
|
132
|
-
header: key,
|
|
133
|
-
accessor,
|
|
134
|
-
cell: ({ value }) => {
|
|
135
|
-
return value ? value : "";
|
|
136
|
-
},
|
|
137
|
-
plugins: {
|
|
138
|
-
// Sorting enabled by default
|
|
139
|
-
sort: {
|
|
140
|
-
invert: true
|
|
141
|
-
},
|
|
142
|
-
// Filtering enabled by default
|
|
143
|
-
colFilter: {
|
|
144
|
-
fn: columnFilter,
|
|
145
|
-
render: ({ filterValue: filterValue2, values, id }) => createRender(TableFilter, {
|
|
146
|
-
filterValue: filterValue2,
|
|
147
|
-
id,
|
|
148
|
-
tableId,
|
|
149
|
-
values
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
];
|
|
157
|
-
if (optionsComponent !== void 0) {
|
|
158
|
-
tableColumns.push(
|
|
159
|
-
table.display({
|
|
160
|
-
id: "optionsColumn",
|
|
161
|
-
header: "",
|
|
162
|
-
plugins: {
|
|
163
|
-
export: {
|
|
164
|
-
exclude: true
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
cell: ({ row }, _) => {
|
|
168
|
-
return createRender(optionsComponent, {
|
|
169
|
-
row: row.isData() ? row.original : null,
|
|
170
|
-
dispatchFn: actionDispatcher
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
const createdTableColumns = table.createColumns(tableColumns);
|
|
177
|
-
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } = table.createViewModel(createdTableColumns);
|
|
178
|
-
const { filterValue } = pluginStates.tableFilter;
|
|
179
|
-
const { exportedData } = pluginStates.export;
|
|
180
|
-
const minWidth = (id) => {
|
|
181
|
-
if (columns && id in columns) {
|
|
182
|
-
return columns[id].minWidth ?? 0;
|
|
183
|
-
}
|
|
184
|
-
return 0;
|
|
185
|
-
};
|
|
186
|
-
const fixedWidth = (id) => {
|
|
187
|
-
if (columns && id in columns) {
|
|
188
|
-
return columns[id].fixedWidth ?? 0;
|
|
189
|
-
}
|
|
190
|
-
return 0;
|
|
191
|
-
};
|
|
192
|
-
const cellStyle = (id) => {
|
|
193
|
-
const minW = minWidth(id);
|
|
194
|
-
const fixedW = fixedWidth(id);
|
|
195
|
-
const styles = [];
|
|
196
|
-
minW && styles.push(`min-width: ${minW}px`);
|
|
197
|
-
fixedW && styles.push(`width: ${fixedW}px`);
|
|
198
|
-
return styles.join(";");
|
|
199
|
-
};
|
|
200
|
-
const resetResize = () => {
|
|
201
|
-
if (resizable === "columns" || resizable === "both") {
|
|
202
|
-
$headerRows.forEach((row) => {
|
|
203
|
-
row.cells.forEach((cell) => {
|
|
204
|
-
const minW = minWidth(cell.id);
|
|
205
|
-
const fixedW = fixedWidth(cell.id);
|
|
206
|
-
fixedW && document.getElementById(`th-${tableId}-${cell.id}`)?.style.setProperty("width", `${fixedW}px`);
|
|
207
|
-
minW && document.getElementById(`th-${tableId}-${cell.id}`)?.style.setProperty("min-width", `${minW}px`);
|
|
208
|
-
!minW && !fixedW && document.getElementById(`th-${tableId}-${cell.id}`)?.style.setProperty("width", "auto");
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
if (resizable === "rows" || resizable === "both") {
|
|
213
|
-
$pageRows.forEach((row) => {
|
|
214
|
-
row.cells.forEach((cell) => {
|
|
215
|
-
document.getElementById(`${tableId}-${cell.id}-${row.id}`)?.style.setProperty("height", "auto");
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
const exportAsCsv = () => {
|
|
221
|
-
const anchor = document.createElement("a");
|
|
222
|
-
anchor.style.display = "none";
|
|
223
|
-
anchor.href = `data:text/csv;charset=utf-8,${encodeURIComponent($exportedData)}`;
|
|
224
|
-
anchor.download = `${tableId}.csv`;
|
|
225
|
-
document.body.appendChild(anchor);
|
|
226
|
-
anchor.click();
|
|
227
|
-
document.body.removeChild(anchor);
|
|
228
|
-
};
|
|
3
|
+
const data = config.data;
|
|
229
4
|
</script>
|
|
230
5
|
|
|
231
|
-
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
{#if $data.length > 0}
|
|
235
|
-
<input
|
|
236
|
-
class="input p-2 border border-primary-500"
|
|
237
|
-
type="text"
|
|
238
|
-
bind:value={$filterValue}
|
|
239
|
-
placeholder="Search rows..."
|
|
240
|
-
id="{tableId}-search"
|
|
241
|
-
/>
|
|
242
|
-
<div class="flex justify-between items-center py-2 w-full">
|
|
243
|
-
<div>
|
|
244
|
-
<!-- Enable the fitToScreen toggle if toggle === true -->
|
|
245
|
-
{#if toggle}
|
|
246
|
-
<SlideToggle
|
|
247
|
-
name="slider-label"
|
|
248
|
-
active="bg-primary-500"
|
|
249
|
-
size="sm"
|
|
250
|
-
checked={fitToScreen}
|
|
251
|
-
id="{tableId}-toggle"
|
|
252
|
-
on:change={() => (fitToScreen = !fitToScreen)}>Fit to screen</SlideToggle
|
|
253
|
-
>
|
|
254
|
-
{/if}
|
|
255
|
-
</div>
|
|
256
|
-
<div class="flex gap-2">
|
|
257
|
-
<!-- Enable the resetResize button if resizable !== 'none' -->
|
|
258
|
-
{#if resizable !== 'none'}
|
|
259
|
-
<button
|
|
260
|
-
type="button"
|
|
261
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
262
|
-
on:click|preventDefault={resetResize}>Reset sizing</button
|
|
263
|
-
>
|
|
264
|
-
{/if}
|
|
265
|
-
{#if exportable}
|
|
266
|
-
<button
|
|
267
|
-
type="button"
|
|
268
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
269
|
-
on:click|preventDefault={exportAsCsv}>Export as CSV</button
|
|
270
|
-
>
|
|
271
|
-
{/if}
|
|
272
|
-
</div>
|
|
273
|
-
</div>
|
|
274
|
-
{/if}
|
|
275
|
-
|
|
276
|
-
<div class="overflow-auto" style="height: {height}px">
|
|
277
|
-
<table
|
|
278
|
-
{...$tableAttrs}
|
|
279
|
-
class="table table-auto table-compact bg-tertiary-500/30 dark:bg-tertiary-900/10 overflow-clip"
|
|
280
|
-
id="{tableId}-table"
|
|
281
|
-
>
|
|
282
|
-
<!-- If table height is provided, making the top row sticky -->
|
|
283
|
-
<thead class=" {height != null ? `sticky top-0` : ''}">
|
|
284
|
-
{#if $data.length > 0}
|
|
285
|
-
{#each $headerRows as headerRow (headerRow.id)}
|
|
286
|
-
<Subscribe
|
|
287
|
-
rowAttrs={headerRow.attrs()}
|
|
288
|
-
let:rowAttrs
|
|
289
|
-
rowProps={headerRow.props()}
|
|
290
|
-
let:rowProps
|
|
291
|
-
>
|
|
292
|
-
<tr {...rowAttrs} class="bg-primary-300 dark:bg-primary-500 items-stretch">
|
|
293
|
-
{#each headerRow.cells as cell (cell.id)}
|
|
294
|
-
<Subscribe attrs={cell.attrs()} props={cell.props()} let:props let:attrs>
|
|
295
|
-
<th
|
|
296
|
-
scope="col"
|
|
297
|
-
class="!p-2 overflow-auto"
|
|
298
|
-
class:resize-x={(resizable === 'columns' || resizable === 'both') &&
|
|
299
|
-
!fixedWidth(cell.id)}
|
|
300
|
-
{...attrs}
|
|
301
|
-
id="th-{tableId}-{cell.id}"
|
|
302
|
-
style={cellStyle(cell.id)}
|
|
303
|
-
>
|
|
304
|
-
<div class="flex justify-between items-center">
|
|
305
|
-
<div class="flex gap-1 whitespace-pre-wrap">
|
|
306
|
-
<!-- Adding sorting config and styling -->
|
|
307
|
-
<span
|
|
308
|
-
class:underline={props.sort.order}
|
|
309
|
-
class:normal-case={cell.id !== cell.label}
|
|
310
|
-
class:cursor-pointer={!props.sort.disabled}
|
|
311
|
-
on:click={props.sort.toggle}
|
|
312
|
-
on:keydown={props.sort.toggle}
|
|
313
|
-
>
|
|
314
|
-
{cell.render()}
|
|
315
|
-
</span>
|
|
316
|
-
<div class="w-2">
|
|
317
|
-
{#if props.sort.order === 'asc'}
|
|
318
|
-
▾
|
|
319
|
-
{:else if props.sort.order === 'desc'}
|
|
320
|
-
▴
|
|
321
|
-
{/if}
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
<!-- Adding column filter config -->
|
|
325
|
-
{#if cell.isData()}
|
|
326
|
-
{#if props.colFilter?.render}
|
|
327
|
-
<div class="">
|
|
328
|
-
<Render of={props.colFilter.render} />
|
|
329
|
-
</div>
|
|
330
|
-
{/if}
|
|
331
|
-
{/if}
|
|
332
|
-
</div>
|
|
333
|
-
</th>
|
|
334
|
-
</Subscribe>
|
|
335
|
-
{/each}
|
|
336
|
-
</tr>
|
|
337
|
-
</Subscribe>
|
|
338
|
-
{/each}
|
|
339
|
-
{:else}
|
|
340
|
-
<!-- Table is empty -->
|
|
341
|
-
<p class="items-center justify-center flex w-full p-10 italic">Nothing to show here.</p>
|
|
342
|
-
{/if}
|
|
343
|
-
</thead>
|
|
344
|
-
|
|
345
|
-
<tbody class="overflow-auto" {...$tableBodyAttrs}>
|
|
346
|
-
{#if $data.length > 0}
|
|
347
|
-
{#each $pageRows as row (row.id)}
|
|
348
|
-
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
|
|
349
|
-
<tr {...rowAttrs} id="{tableId}-row-{row.id}" class="">
|
|
350
|
-
{#each row.cells as cell, index (cell?.id)}
|
|
351
|
-
<Subscribe attrs={cell.attrs()} let:attrs>
|
|
352
|
-
<td
|
|
353
|
-
{...attrs}
|
|
354
|
-
class="!p-2 overflow-auto {index === 0 &&
|
|
355
|
-
(resizable === 'rows' || resizable === 'both')
|
|
356
|
-
? 'resize-y'
|
|
357
|
-
: ''}"
|
|
358
|
-
id="{tableId}-{cell.id}-{row.id}"
|
|
359
|
-
>
|
|
360
|
-
<!-- Adding config for initial rowHeight, if provided -->
|
|
361
|
-
<div
|
|
362
|
-
class="flex items-center"
|
|
363
|
-
style="height: {rowHeight ? `${rowHeight}px` : 'auto'};"
|
|
364
|
-
>
|
|
365
|
-
<div class="grow h-full"><Render of={cell.render()} /></div>
|
|
366
|
-
</div>
|
|
367
|
-
</td>
|
|
368
|
-
</Subscribe>
|
|
369
|
-
{/each}
|
|
370
|
-
</tr>
|
|
371
|
-
</Subscribe>
|
|
372
|
-
{/each}
|
|
373
|
-
{/if}
|
|
374
|
-
</tbody>
|
|
375
|
-
</table>
|
|
376
|
-
</div>
|
|
377
|
-
</div>
|
|
378
|
-
{#if $data.length > 0}
|
|
379
|
-
<!-- Adding pagination, if table is not empty -->
|
|
380
|
-
<TablePagination pageConfig={pluginStates.page} {pageSizes} id={tableId} />
|
|
381
|
-
{/if}
|
|
382
|
-
</div>
|
|
6
|
+
{#key $data.length && true}
|
|
7
|
+
<Table {config} on:action />
|
|
8
|
+
{/key}
|
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
import { SvelteComponentTyped } from "svelte";
|
|
2
|
-
|
|
3
|
-
declare const __propDef: {
|
|
4
|
-
props: {
|
|
5
|
-
config: TableConfig<any>;
|
|
6
|
-
};
|
|
7
|
-
events: {
|
|
8
|
-
action: CustomEvent<any>;
|
|
9
|
-
} & {
|
|
10
|
-
[evt: string]: CustomEvent<any>;
|
|
11
|
-
};
|
|
12
|
-
slots: {};
|
|
13
|
-
};
|
|
2
|
+
declare const __propDef: any;
|
|
14
3
|
export type TableProps = typeof __propDef.props;
|
|
15
4
|
export type TableEvents = typeof __propDef.events;
|
|
16
5
|
export type TableSlots = typeof __propDef.slots;
|