@lavalogic/scoria 0.7.2 → 0.8.0
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/Components/QuerySelect.svelte +9 -5
- package/dist/Components/Table/Body/QuickSearchCell.svelte +3 -1
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +58 -18
- package/dist/Components/Table/ColumnDefinitions/ExampleItemColumnDef.svelte.js +20 -0
- package/dist/Components/Table/Misc/FilterInput.svelte +2 -1
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/QueryDef.svelte.d.ts +0 -2
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/QueryDef.svelte.js +0 -2
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +3 -3
- package/dist/Types/Examples/ExampleItem.d.ts +2 -0
- package/package.json +15 -15
|
@@ -23,14 +23,18 @@
|
|
|
23
23
|
isValid?: (item: V | null) => boolean;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export interface QuerySelectPropsAsObject<
|
|
27
|
-
extends
|
|
26
|
+
export interface QuerySelectPropsAsObject<
|
|
27
|
+
V extends object,
|
|
28
|
+
VP extends ValueProp<V>
|
|
29
|
+
> extends QuerySelectPropsAsObjectCommonProps<V, VP> {
|
|
28
30
|
valueAsObject: true;
|
|
29
31
|
value: V | null;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
export interface QuerySelectPropsAsPrimitive<
|
|
33
|
-
extends
|
|
34
|
+
export interface QuerySelectPropsAsPrimitive<
|
|
35
|
+
V extends object,
|
|
36
|
+
VP extends ValueProp<V>
|
|
37
|
+
> extends QuerySelectPropsAsObjectCommonProps<V, VP> {
|
|
34
38
|
valueAsObject: false;
|
|
35
39
|
value: V[VP] | null;
|
|
36
40
|
options: V[];
|
|
@@ -312,7 +316,7 @@
|
|
|
312
316
|
forceShowDropdown(e);
|
|
313
317
|
onfocus?.(e);
|
|
314
318
|
}}
|
|
315
|
-
placeholder="Please Select
|
|
319
|
+
placeholder="Please Select{name ? ` ${an} ${name}` : ''}"
|
|
316
320
|
bind:this={ref}
|
|
317
321
|
{inputId}
|
|
318
322
|
{disabled}
|
|
@@ -62,8 +62,10 @@
|
|
|
62
62
|
);
|
|
63
63
|
|
|
64
64
|
const isSearchable = $derived(
|
|
65
|
-
|
|
65
|
+
def.allowFiltering != false &&
|
|
66
|
+
((hasFilterFn && hasAcceptableColumnType) || customFilters?.has(def.id) == true)
|
|
66
67
|
);
|
|
68
|
+
|
|
67
69
|
const isNumeric = $derived(
|
|
68
70
|
def instanceof NumberInputDef ||
|
|
69
71
|
def.filterValueType == 'Number' ||
|
|
@@ -29,9 +29,7 @@
|
|
|
29
29
|
<script lang="ts" generics="T extends object,">
|
|
30
30
|
const { cell }: TableQuerySelectProps<T> = $props();
|
|
31
31
|
|
|
32
|
-
const value = $derived(
|
|
33
|
-
(cell.getValue() ?? null) as SelectOption<unknown> | Promise<SelectOption<unknown>> | null
|
|
34
|
-
);
|
|
32
|
+
const value = $derived((cell.getValue() ?? null) as unknown | Promise<unknown> | null);
|
|
35
33
|
|
|
36
34
|
const visibleValue = $derived(
|
|
37
35
|
cell.column.columnDef.getDisplayValue(cell.row.original, cell.row.originalIndex)
|
|
@@ -52,26 +50,65 @@
|
|
|
52
50
|
);
|
|
53
51
|
let editable = $state(false);
|
|
54
52
|
|
|
55
|
-
let
|
|
53
|
+
let valueAsyncCounter = 0;
|
|
54
|
+
$effect(() => {
|
|
55
|
+
void value;
|
|
56
|
+
void lastOptions;
|
|
57
|
+
|
|
58
|
+
untrack(() => {
|
|
59
|
+
const localCounter = (valueAsyncCounter = valueAsyncCounter + 1);
|
|
60
|
+
(async () => {
|
|
61
|
+
try {
|
|
62
|
+
const awaitedValue = await value;
|
|
63
|
+
const label = (await visibleValue) ?? awaitedValue?.toString();
|
|
64
|
+
|
|
65
|
+
if (awaitedValue != null && valueAsyncCounter === localCounter) {
|
|
66
|
+
if (label == null) {
|
|
67
|
+
throw new Error('invalid label and value');
|
|
68
|
+
}
|
|
69
|
+
if (!lastOptions.some((it) => it.value == awaitedValue)) {
|
|
70
|
+
lastOptions.push({
|
|
71
|
+
label,
|
|
72
|
+
value: awaitedValue
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
} else if (dev || columnDef.debug) {
|
|
76
|
+
console.log('skipping async option insertion because it is stale');
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
if (dev || columnDef.debug) {
|
|
80
|
+
console.error(e);
|
|
81
|
+
}
|
|
82
|
+
if (valueAsyncCounter === localCounter) {
|
|
83
|
+
//nothing happens
|
|
84
|
+
} else if (dev || columnDef.debug) {
|
|
85
|
+
console.log('skipping caught async option insertion error because it is stale');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
})();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
let editableAsyncCounter = 0;
|
|
56
93
|
$effect(() => {
|
|
57
94
|
void editableAsync;
|
|
58
95
|
untrack(() => {
|
|
59
|
-
const localCounter = (
|
|
96
|
+
const localCounter = (editableAsyncCounter = editableAsyncCounter + 1);
|
|
60
97
|
(async () => {
|
|
61
98
|
try {
|
|
62
99
|
const isEditable = await editableAsync;
|
|
63
|
-
if (
|
|
100
|
+
if (editableAsyncCounter === localCounter) {
|
|
64
101
|
editable = isEditable;
|
|
65
|
-
} else if (dev) {
|
|
102
|
+
} else if (dev || columnDef.debug) {
|
|
66
103
|
console.log('skipping async editable because it is stale');
|
|
67
104
|
}
|
|
68
105
|
} catch (e) {
|
|
69
|
-
if (dev) {
|
|
106
|
+
if (dev || columnDef.debug) {
|
|
70
107
|
console.error(e);
|
|
71
108
|
}
|
|
72
|
-
if (
|
|
109
|
+
if (editableAsyncCounter === localCounter) {
|
|
73
110
|
editable = false;
|
|
74
|
-
} else if (dev) {
|
|
111
|
+
} else if (dev || columnDef.debug) {
|
|
75
112
|
console.log('skipping async editable because it is stale');
|
|
76
113
|
}
|
|
77
114
|
}
|
|
@@ -93,6 +130,7 @@
|
|
|
93
130
|
);
|
|
94
131
|
|
|
95
132
|
let isBeingEdited = $state(false);
|
|
133
|
+
|
|
96
134
|
$effect(() => {
|
|
97
135
|
if (wantsToBeEdited) {
|
|
98
136
|
if (editable) {
|
|
@@ -237,11 +275,13 @@
|
|
|
237
275
|
let prevtdref: HTMLTableCellElement | undefined = undefined;
|
|
238
276
|
$effect(() => {
|
|
239
277
|
if (tdref) {
|
|
240
|
-
|
|
241
|
-
tdref
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
278
|
+
untrack(() => {
|
|
279
|
+
if (tdref != prevtdref) {
|
|
280
|
+
tdref!.addEventListener('edit', handleTDFocus);
|
|
281
|
+
} else {
|
|
282
|
+
prevtdref = tdref;
|
|
283
|
+
}
|
|
284
|
+
});
|
|
245
285
|
}
|
|
246
286
|
});
|
|
247
287
|
</script>
|
|
@@ -256,14 +296,14 @@
|
|
|
256
296
|
focusOnLoad
|
|
257
297
|
name={cell.column.columnDef.id}
|
|
258
298
|
valueProp="value"
|
|
259
|
-
clearable={cell.column.columnDef.clearable ?? true}
|
|
260
299
|
labelProp="label"
|
|
261
|
-
|
|
300
|
+
clearable={cell.column.columnDef.clearable ?? true}
|
|
301
|
+
valueAsObject={false}
|
|
262
302
|
{value}
|
|
263
303
|
query={(v) => columnDef.query(v, cell.row.original, cell.row.originalIndex)}
|
|
264
304
|
bind:options={lastOptions}
|
|
265
305
|
onfocus={addKeydownEvent}
|
|
266
|
-
onchange={(newValue) => {
|
|
306
|
+
onchange={(newValue: SelectOption<unknown> | null) => {
|
|
267
307
|
if (newValue?.value !== value) {
|
|
268
308
|
tableContext.onEditCell(
|
|
269
309
|
cell.row.original,
|
|
@@ -11,6 +11,7 @@ import { DisplayDef } from '../Types/Columns/Definitions/Display/DisplayDef.svel
|
|
|
11
11
|
import { ProgressBarDef } from '../Types/Columns/Definitions/Display/ProgressBarDef.svelte.js';
|
|
12
12
|
import { ValidityDef } from '../Types/Columns/Definitions/Display/ValidityDef.svelte.js';
|
|
13
13
|
import { asyncSleep } from '../../../Helpers/Helpers.svelte.js';
|
|
14
|
+
import { QueryDef } from '../Types/Columns/Definitions/Accessors/QueryDef.svelte.js';
|
|
14
15
|
export class ExampleItemColumnDef {
|
|
15
16
|
static generateExampleItemColumnDefs(modal) {
|
|
16
17
|
let defs = $state([
|
|
@@ -39,6 +40,25 @@ export class ExampleItemColumnDef {
|
|
|
39
40
|
id: 'id',
|
|
40
41
|
filterValueType: 'Number'
|
|
41
42
|
}),
|
|
43
|
+
new QueryDef({
|
|
44
|
+
header: 'simulated query def',
|
|
45
|
+
getDisplayValue: async (item, index) => {
|
|
46
|
+
return item.simulatedQuery?.value ?? null;
|
|
47
|
+
},
|
|
48
|
+
isEditable: () => true,
|
|
49
|
+
id: 'simulatedQuery',
|
|
50
|
+
query: async (v, item, index) => {
|
|
51
|
+
asyncSleep(25);
|
|
52
|
+
return item.someDate
|
|
53
|
+
? new Array(5).fill(0).map((it, index) => {
|
|
54
|
+
return {
|
|
55
|
+
label: (it + index).toString(),
|
|
56
|
+
value: { value: (it + index).toString() }
|
|
57
|
+
};
|
|
58
|
+
})
|
|
59
|
+
: [];
|
|
60
|
+
}
|
|
61
|
+
}),
|
|
42
62
|
new TextInputDef({
|
|
43
63
|
header: 'Name',
|
|
44
64
|
id: 'name',
|
|
@@ -106,7 +106,8 @@
|
|
|
106
106
|
);
|
|
107
107
|
|
|
108
108
|
const isSearchable = $derived(
|
|
109
|
-
|
|
109
|
+
def.allowFiltering != false &&
|
|
110
|
+
((hasFilterFn && hasAcceptableColumnType) || customFilters?.has(def.id) == true)
|
|
110
111
|
);
|
|
111
112
|
|
|
112
113
|
const hasQuery = $derived(isRemoteSelect && customFilter?.query);
|
|
@@ -4,7 +4,6 @@ import type { FilterFn, SelectFilterValueType } from '../../../Filtering/FilterF
|
|
|
4
4
|
import type { ColumnDefProps } from '../ColumnDef.svelte.js';
|
|
5
5
|
import { AccessorDef } from './AccessorDef.svelte.js';
|
|
6
6
|
export interface QueryDefProps<T extends object> extends ColumnDefProps<T, SelectFilterValueType<T>> {
|
|
7
|
-
valueAsObject: boolean;
|
|
8
7
|
query: (queryString: string, item: T, index: number) => Promise<Array<SelectOption<unknown>>>;
|
|
9
8
|
getDisplayValue: (item: T, index: number) => string | null | Promise<string | null>;
|
|
10
9
|
clearable?: boolean;
|
|
@@ -13,7 +12,6 @@ export declare class QueryDef<T extends object> extends AccessorDef<T, SelectFil
|
|
|
13
12
|
readonly accessorType: "Query";
|
|
14
13
|
constructor(props: QueryDefProps<T>);
|
|
15
14
|
readonly filterFn: CustomFilterFn | FilterFn<T, SelectFilterValueType<T>> | undefined;
|
|
16
|
-
readonly valueAsObject: boolean;
|
|
17
15
|
get getDisplayValue(): (item: T, index: number) => string | null | Promise<string | null>;
|
|
18
16
|
readonly query: (queryString: string, item: T, index: number) => Promise<Array<SelectOption<unknown>>>;
|
|
19
17
|
readonly clearable: boolean;
|
|
@@ -4,12 +4,10 @@ export class QueryDef extends AccessorDef {
|
|
|
4
4
|
accessorType = AccessorType.Query;
|
|
5
5
|
constructor(props) {
|
|
6
6
|
super(props);
|
|
7
|
-
this.valueAsObject = $derived(props.valueAsObject);
|
|
8
7
|
this.query = $derived(props.query);
|
|
9
8
|
this.clearable = $derived(props.clearable ?? true);
|
|
10
9
|
}
|
|
11
10
|
filterFn;
|
|
12
|
-
valueAsObject;
|
|
13
11
|
get getDisplayValue() {
|
|
14
12
|
return this._getDisplayValue;
|
|
15
13
|
}
|
|
@@ -1918,9 +1918,9 @@ export class TableContext {
|
|
|
1918
1918
|
this.assertNoDuplicateIds();
|
|
1919
1919
|
const adjustedDefsPromises = this.defaultColumnDefs.defs.map(async (def) => {
|
|
1920
1920
|
if (def instanceof AccessorDef) {
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1921
|
+
if (def.allowFiltering == false) {
|
|
1922
|
+
return def;
|
|
1923
|
+
}
|
|
1924
1924
|
if (!('minSize' in def) || !def.minSize) {
|
|
1925
1925
|
if (typeof def.header === 'string') {
|
|
1926
1926
|
const minWidth = this.measureHeaderWidth(def);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SQLDate } from '../Internal/Misc.js';
|
|
2
|
+
import type { SelectOption } from '../Internal/SelectOption.js';
|
|
2
3
|
import type { ExampleSelectEnum } from './ExampleSelectEnum.js';
|
|
3
4
|
export interface ExampleItem {
|
|
4
5
|
id: number;
|
|
@@ -12,4 +13,5 @@ export interface ExampleItem {
|
|
|
12
13
|
floDateWithTime: SQLDate | null;
|
|
13
14
|
someSelect: ExampleSelectEnum | null;
|
|
14
15
|
someBubbles: string[];
|
|
16
|
+
simulatedQuery: SelectOption<string> | null;
|
|
15
17
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lavalogic/scoria",
|
|
3
3
|
"description": "Svelte components used for the FloWMS Web Frontend",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "restricted"
|
|
7
7
|
},
|
|
@@ -33,19 +33,19 @@
|
|
|
33
33
|
"@eslint/compat": "^2.0.0",
|
|
34
34
|
"@eslint/js": "^9.39.2",
|
|
35
35
|
"@playwright/test": "^1.57.0",
|
|
36
|
-
"@storybook/addon-a11y": "^10.1.
|
|
37
|
-
"@storybook/addon-docs": "^10.1.
|
|
36
|
+
"@storybook/addon-a11y": "^10.1.11",
|
|
37
|
+
"@storybook/addon-docs": "^10.1.11",
|
|
38
38
|
"@storybook/addon-svelte-csf": "^5.0.10",
|
|
39
|
-
"@storybook/addon-vitest": "^10.1.
|
|
40
|
-
"@storybook/sveltekit": "^10.1.
|
|
39
|
+
"@storybook/addon-vitest": "^10.1.11",
|
|
40
|
+
"@storybook/sveltekit": "^10.1.11",
|
|
41
41
|
"@sveltejs/adapter-node": "^5.4.0",
|
|
42
|
-
"@sveltejs/kit": "^2.49.
|
|
42
|
+
"@sveltejs/kit": "^2.49.3",
|
|
43
43
|
"@sveltejs/package": "^2.5.7",
|
|
44
|
-
"@sveltejs/vite-plugin-svelte": "^6.2.
|
|
44
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.2",
|
|
45
45
|
"@types/eslint": "^9.6.1",
|
|
46
46
|
"@types/node": "^24.10.4",
|
|
47
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
48
|
-
"@typescript-eslint/parser": "^8.
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.52.0",
|
|
48
|
+
"@typescript-eslint/parser": "^8.52.0",
|
|
49
49
|
"@vitest/browser": "^4.0.16",
|
|
50
50
|
"eslint": "^9.39.2",
|
|
51
51
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"prettier": "^3.7.4",
|
|
58
58
|
"prettier-plugin-svelte": "^3.4.1",
|
|
59
59
|
"publint": "^0.3.16",
|
|
60
|
-
"sass-embedded": "^1.97.
|
|
61
|
-
"storybook": "^10.1.
|
|
62
|
-
"svelte": "^5.46.
|
|
63
|
-
"svelte-check": "^4.3.
|
|
60
|
+
"sass-embedded": "^1.97.2",
|
|
61
|
+
"storybook": "^10.1.11",
|
|
62
|
+
"svelte": "^5.46.1",
|
|
63
|
+
"svelte-check": "^4.3.5",
|
|
64
64
|
"svelte-render-scan": "^1.1.0",
|
|
65
65
|
"typescript": "^5.9.3",
|
|
66
|
-
"typescript-eslint": "^8.
|
|
66
|
+
"typescript-eslint": "^8.52.0",
|
|
67
67
|
"vite": "^7.3.0",
|
|
68
68
|
"vite-plugin-devtools-json": "^1.0.0",
|
|
69
69
|
"vitest": "^4.0.16",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
],
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"svelecte": "^5.3.0",
|
|
77
|
-
"svelte-dnd-action": "^0.9.
|
|
77
|
+
"svelte-dnd-action": "^0.9.69"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"dev": "vite dev",
|