@bexis2/bexis2-core-ui 0.0.30 → 0.0.31
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 +26 -0
- package/dist/components/Table/Table.svelte +132 -94
- package/dist/components/Table/Table.svelte.d.ts +2 -0
- package/dist/components/Table/TableFilter.svelte +50 -5
- package/dist/components/Table/TablePagination.svelte +1 -1
- package/dist/components/Table/filter.js +43 -3
- package/dist/components/page/Alert.svelte +39 -0
- package/dist/components/page/Alert.svelte.d.ts +22 -0
- package/dist/components/spinner/Spinner.svelte +11 -1
- package/dist/components/spinner/Spinner.svelte.d.ts +9 -13
- package/dist/css/themes/theme-bexis2.css +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/models/Enums.d.ts +5 -0
- package/dist/models/Enums.js +6 -0
- package/dist/models/Models.d.ts +8 -0
- package/package.json +1 -1
- package/src/lib/components/Table/Table.svelte +230 -184
- package/src/lib/components/Table/TableFilter.svelte +50 -5
- package/src/lib/components/Table/TablePagination.svelte +1 -1
- package/src/lib/components/Table/filter.ts +141 -94
- package/src/lib/components/page/Alert.svelte +46 -0
- package/src/lib/components/spinner/Spinner.svelte +14 -1
- package/src/lib/css/themes/theme-bexis2.css +3 -3
- package/src/lib/index.ts +2 -1
- package/src/lib/models/Enums.ts +6 -0
- package/src/lib/models/Models.ts +88 -78
package/dist/models/Models.d.ts
CHANGED
|
@@ -44,9 +44,17 @@ export interface FileObj {
|
|
|
44
44
|
type: string;
|
|
45
45
|
webkitRelativePath: string;
|
|
46
46
|
}
|
|
47
|
+
export interface ColumnInstructions {
|
|
48
|
+
toStringFn?: (value: any) => string;
|
|
49
|
+
toSortableValueFn?: (value: any) => string | number;
|
|
50
|
+
toFilterableValueFn?: (value: any) => string | number | Date;
|
|
51
|
+
}
|
|
47
52
|
export interface Column {
|
|
48
53
|
header?: string;
|
|
49
54
|
exclude?: boolean;
|
|
55
|
+
instructions?: ColumnInstructions;
|
|
56
|
+
disableFiltering?: boolean;
|
|
57
|
+
disableSorting?: boolean;
|
|
50
58
|
colFilterFn?: ColumnFilterFn;
|
|
51
59
|
colFilterComponent?: typeof SvelteComponent;
|
|
52
60
|
}
|
package/package.json
CHANGED
|
@@ -1,184 +1,230 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
let
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
plugins: {
|
|
75
|
-
sort: {
|
|
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
|
-
{#each $
|
|
165
|
-
<Subscribe
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
</
|
|
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
|
+
|
|
12
|
+
import TableFilter from './TableFilter.svelte';
|
|
13
|
+
import TablePagination from './TablePagination.svelte';
|
|
14
|
+
import { columnFilter, searchFilter } from './filter';
|
|
15
|
+
import type { TableConfig } from '$lib/models/Models';
|
|
16
|
+
|
|
17
|
+
export let config: TableConfig<any>;
|
|
18
|
+
let {
|
|
19
|
+
id: tableId,
|
|
20
|
+
data,
|
|
21
|
+
columns,
|
|
22
|
+
optionsComponent,
|
|
23
|
+
defaultPageSize = 10,
|
|
24
|
+
pageSizes = [5, 10, 15, 20]
|
|
25
|
+
} = config;
|
|
26
|
+
|
|
27
|
+
type AccessorType = keyof (typeof $data)[0];
|
|
28
|
+
|
|
29
|
+
const dispatch = createEventDispatcher();
|
|
30
|
+
const actionDispatcher = (obj) => dispatch('action', obj);
|
|
31
|
+
|
|
32
|
+
const table = createTable(data, {
|
|
33
|
+
colFilter: addColumnFilters(),
|
|
34
|
+
tableFilter: addTableFilter({
|
|
35
|
+
fn: searchFilter
|
|
36
|
+
}),
|
|
37
|
+
sort: addSortBy({ disableMultiSort: true }),
|
|
38
|
+
page: addPagination({ initialPageSize: defaultPageSize }),
|
|
39
|
+
expand: addExpandedRows()
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const accessors: AccessorType[] =
|
|
43
|
+
$data.length > 0 ? (Object.keys($data[0]) as AccessorType[]) : [];
|
|
44
|
+
|
|
45
|
+
const tableColumns = [
|
|
46
|
+
...accessors
|
|
47
|
+
.filter((accessor) => {
|
|
48
|
+
const key = accessor as string;
|
|
49
|
+
if (columns !== undefined && key in columns && columns[key].exclude === true) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
})
|
|
54
|
+
.map((accessor) => {
|
|
55
|
+
const key = accessor as string;
|
|
56
|
+
if (columns !== undefined && key in columns) {
|
|
57
|
+
const {
|
|
58
|
+
header,
|
|
59
|
+
colFilterFn,
|
|
60
|
+
colFilterComponent,
|
|
61
|
+
instructions,
|
|
62
|
+
disableFiltering = false,
|
|
63
|
+
disableSorting = false
|
|
64
|
+
} = columns[key];
|
|
65
|
+
|
|
66
|
+
const { toSortableValueFn, toFilterableValueFn, toStringFn } = instructions ?? {};
|
|
67
|
+
|
|
68
|
+
return table.column({
|
|
69
|
+
header: header ?? key,
|
|
70
|
+
accessor: accessor,
|
|
71
|
+
cell: ({ value }) => {
|
|
72
|
+
return toStringFn ? toStringFn(value) : value;
|
|
73
|
+
},
|
|
74
|
+
plugins: {
|
|
75
|
+
sort: {
|
|
76
|
+
disable: disableSorting,
|
|
77
|
+
invert: true,
|
|
78
|
+
getSortValue: (row) => {
|
|
79
|
+
return toSortableValueFn ? toSortableValueFn(row) : row;
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
colFilter: !disableFiltering
|
|
83
|
+
? {
|
|
84
|
+
fn: ({ filterValue, value }) => {
|
|
85
|
+
const val = toFilterableValueFn ? toFilterableValueFn(value) : value;
|
|
86
|
+
|
|
87
|
+
return colFilterFn
|
|
88
|
+
? colFilterFn({ filterValue, value: val })
|
|
89
|
+
: columnFilter({ filterValue, value: val });
|
|
90
|
+
},
|
|
91
|
+
render: ({ filterValue, values, id }) => {
|
|
92
|
+
return createRender(colFilterComponent ?? TableFilter, {
|
|
93
|
+
filterValue,
|
|
94
|
+
id,
|
|
95
|
+
tableId,
|
|
96
|
+
values
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
: undefined,
|
|
101
|
+
tableFilter: {
|
|
102
|
+
getFilterValue: (row) => {
|
|
103
|
+
return toStringFn ? toStringFn(row) : row;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
} else {
|
|
109
|
+
return table.column({
|
|
110
|
+
header: key,
|
|
111
|
+
accessor: accessor,
|
|
112
|
+
plugins: {
|
|
113
|
+
sort: {
|
|
114
|
+
invert: true
|
|
115
|
+
},
|
|
116
|
+
colFilter: {
|
|
117
|
+
fn: columnFilter,
|
|
118
|
+
render: ({ filterValue, values, id }) =>
|
|
119
|
+
createRender(TableFilter, {
|
|
120
|
+
filterValue,
|
|
121
|
+
id,
|
|
122
|
+
tableId,
|
|
123
|
+
values
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
if (optionsComponent !== undefined) {
|
|
133
|
+
tableColumns.push(
|
|
134
|
+
table.display({
|
|
135
|
+
id: 'options',
|
|
136
|
+
header: '',
|
|
137
|
+
cell: ({ row }, _) => {
|
|
138
|
+
return createRender(optionsComponent!, {
|
|
139
|
+
row: row.isData() ? row.original : null,
|
|
140
|
+
dispatchFn: actionDispatcher
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}) as any
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const createdTableColumns = table.createColumns(tableColumns);
|
|
148
|
+
|
|
149
|
+
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } =
|
|
150
|
+
table.createViewModel(createdTableColumns);
|
|
151
|
+
const { filterValue } = pluginStates.tableFilter;
|
|
152
|
+
</script>
|
|
153
|
+
|
|
154
|
+
<div class="grid gap-2">
|
|
155
|
+
<div class="table-container">
|
|
156
|
+
<input
|
|
157
|
+
class="input p-2 mb-2 border border-primary-500"
|
|
158
|
+
type="text"
|
|
159
|
+
bind:value={$filterValue}
|
|
160
|
+
placeholder="Search rows..."
|
|
161
|
+
/>
|
|
162
|
+
<table {...$tableAttrs} class="table table-compact bg-tertiary-200">
|
|
163
|
+
<thead>
|
|
164
|
+
{#each $headerRows as headerRow (headerRow.id)}
|
|
165
|
+
<Subscribe
|
|
166
|
+
rowAttrs={headerRow.attrs()}
|
|
167
|
+
let:rowAttrs
|
|
168
|
+
rowProps={headerRow.props()}
|
|
169
|
+
let:rowProps
|
|
170
|
+
>
|
|
171
|
+
<tr {...rowAttrs} class="bg-primary-300">
|
|
172
|
+
{#each headerRow.cells as cell (cell.id)}
|
|
173
|
+
<Subscribe attrs={cell.attrs()} props={cell.props()} let:props let:attrs>
|
|
174
|
+
<th scope="col" class="!p-2" {...attrs}>
|
|
175
|
+
<div class="flex w-full justify-between items-center">
|
|
176
|
+
<div class="flex gap-1">
|
|
177
|
+
<span
|
|
178
|
+
class:underline={props.sort.order}
|
|
179
|
+
class:normal-case={cell.id !== cell.label}
|
|
180
|
+
on:click={props.sort.toggle}
|
|
181
|
+
on:keydown={props.sort.toggle}
|
|
182
|
+
>
|
|
183
|
+
{cell.render()}
|
|
184
|
+
</span>
|
|
185
|
+
<div class="w-2">
|
|
186
|
+
{#if props.sort.order === 'asc'}
|
|
187
|
+
▾
|
|
188
|
+
{:else if props.sort.order === 'desc'}
|
|
189
|
+
▴
|
|
190
|
+
{/if}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
{#if cell.isData()}
|
|
194
|
+
{#if props.colFilter?.render}
|
|
195
|
+
<div>
|
|
196
|
+
<Render of={props.colFilter.render} />
|
|
197
|
+
</div>
|
|
198
|
+
{/if}
|
|
199
|
+
{/if}
|
|
200
|
+
</div>
|
|
201
|
+
</th>
|
|
202
|
+
</Subscribe>
|
|
203
|
+
{/each}
|
|
204
|
+
</tr>
|
|
205
|
+
</Subscribe>
|
|
206
|
+
{/each}
|
|
207
|
+
</thead>
|
|
208
|
+
|
|
209
|
+
<tbody class="" {...$tableBodyAttrs}>
|
|
210
|
+
{#each $pageRows as row (row.id)}
|
|
211
|
+
<Subscribe rowAttrs={row.attrs()} let:rowAttrs>
|
|
212
|
+
<tr {...rowAttrs}>
|
|
213
|
+
{#each row.cells as cell (cell?.id)}
|
|
214
|
+
<Subscribe attrs={cell.attrs()} let:attrs>
|
|
215
|
+
<td {...attrs} class="!p-2">
|
|
216
|
+
<div class="flex items-center w-full h-full table-cell-fit">
|
|
217
|
+
<Render of={cell.render()} />
|
|
218
|
+
</div>
|
|
219
|
+
</td>
|
|
220
|
+
</Subscribe>
|
|
221
|
+
{/each}
|
|
222
|
+
</tr>
|
|
223
|
+
</Subscribe>
|
|
224
|
+
{/each}
|
|
225
|
+
</tbody>
|
|
226
|
+
</table>
|
|
227
|
+
</div>
|
|
228
|
+
|
|
229
|
+
<TablePagination pageConfig={pluginStates.page} {pageSizes} />
|
|
230
|
+
</div>
|
|
@@ -67,6 +67,32 @@
|
|
|
67
67
|
value: 'ends',
|
|
68
68
|
label: 'Ends with'
|
|
69
69
|
}
|
|
70
|
+
],
|
|
71
|
+
date: [
|
|
72
|
+
{
|
|
73
|
+
value: 'ison',
|
|
74
|
+
label: 'Is on'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
value: 'isstartingfrom',
|
|
78
|
+
label: 'Is starting from'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
value: 'isafter',
|
|
82
|
+
label: 'Is after'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
value: 'isuntil',
|
|
86
|
+
label: 'Is until'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
value: 'isbefore',
|
|
90
|
+
label: 'Is before'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
value: 'isnoton',
|
|
94
|
+
label: 'Is not on'
|
|
95
|
+
}
|
|
70
96
|
]
|
|
71
97
|
};
|
|
72
98
|
|
|
@@ -78,7 +104,12 @@
|
|
|
78
104
|
placement: 'bottom-start'
|
|
79
105
|
};
|
|
80
106
|
|
|
81
|
-
|
|
107
|
+
let type: string = typeof $values[0];
|
|
108
|
+
if (type === 'object') {
|
|
109
|
+
if ($values[0] instanceof Date) {
|
|
110
|
+
type = 'date';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
82
113
|
</script>
|
|
83
114
|
|
|
84
115
|
<form class="">
|
|
@@ -95,7 +126,7 @@
|
|
|
95
126
|
<div class="card p-3 absolute grid gap-2 shadow-lg z-10 w-min">
|
|
96
127
|
<button
|
|
97
128
|
class="btn variant-filled-primary btn-sm"
|
|
98
|
-
type="
|
|
129
|
+
type="button"
|
|
99
130
|
on:click|preventDefault={() => {
|
|
100
131
|
firstOption = 'isequal';
|
|
101
132
|
firstValue = undefined;
|
|
@@ -126,13 +157,20 @@
|
|
|
126
157
|
bind:value={firstValue}
|
|
127
158
|
on:click|stopPropagation
|
|
128
159
|
/>
|
|
129
|
-
{:else}
|
|
160
|
+
{:else if type === 'string'}
|
|
130
161
|
<input
|
|
131
162
|
type="text"
|
|
132
163
|
class="input p-1 border border-primary-500"
|
|
133
164
|
bind:value={firstValue}
|
|
134
165
|
on:click|stopPropagation
|
|
135
166
|
/>
|
|
167
|
+
{:else}
|
|
168
|
+
<input
|
|
169
|
+
type="date"
|
|
170
|
+
class="input p-1 border border-primary-500"
|
|
171
|
+
bind:value={firstValue}
|
|
172
|
+
on:click|stopPropagation
|
|
173
|
+
/>
|
|
136
174
|
{/if}
|
|
137
175
|
</div>
|
|
138
176
|
<label for="" class="label normal-case">And</label>
|
|
@@ -154,18 +192,25 @@
|
|
|
154
192
|
bind:value={secondValue}
|
|
155
193
|
on:click|stopPropagation
|
|
156
194
|
/>
|
|
157
|
-
{:else}
|
|
195
|
+
{:else if type === 'string'}
|
|
158
196
|
<input
|
|
159
197
|
type="text"
|
|
160
198
|
class="input p-1 border border-primary-500"
|
|
161
199
|
bind:value={secondValue}
|
|
162
200
|
on:click|stopPropagation
|
|
163
201
|
/>
|
|
202
|
+
{:else}
|
|
203
|
+
<input
|
|
204
|
+
type="date"
|
|
205
|
+
class="input p-1 border border-primary-500"
|
|
206
|
+
bind:value={secondValue}
|
|
207
|
+
on:click|stopPropagation
|
|
208
|
+
/>
|
|
164
209
|
{/if}
|
|
165
210
|
</div>
|
|
166
211
|
<button
|
|
167
212
|
class="btn variant-filled-primary btn-sm"
|
|
168
|
-
type="
|
|
213
|
+
type="button"
|
|
169
214
|
on:click|preventDefault={() => {
|
|
170
215
|
active = firstValue?.toString().length > 0 || secondValue?.toString().length > 0;
|
|
171
216
|
$filterValue = [firstOption, firstValue, secondOption, secondValue];
|