@lavalogic/scoria 0.18.1 → 0.19.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.
Files changed (23) hide show
  1. package/dist/Components/Base/Snippets.svelte +26 -0
  2. package/dist/Components/Base/Snippets.svelte.d.ts +5 -0
  3. package/dist/Components/CollapsibleCard.svelte +6 -3
  4. package/dist/Components/GridInput.svelte +18 -6
  5. package/dist/Components/LoadingAnimation.svelte +7 -2
  6. package/dist/Components/Table/Body/QuickSearchCell.svelte +30 -32
  7. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +1 -1
  8. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +15 -21
  9. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +8 -2
  10. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +43 -39
  11. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +60 -44
  12. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +57 -69
  13. package/dist/Components/Table/Body/TableBody.svelte +15 -16
  14. package/dist/Components/Table/ColumnDefinitions/ExampleItemColumnDefRepository.svelte.js +7 -7
  15. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +6 -3
  16. package/dist/Components/Table/Headers/SelectAllHeader.svelte +4 -1
  17. package/dist/Components/Table/Table.svelte +128 -133
  18. package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.d.ts +2 -2
  19. package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.js +1 -1
  20. package/dist/Components/Touch/TouchModal.svelte +20 -6
  21. package/dist/Helpers/Helpers.svelte.d.ts +1 -0
  22. package/dist/Helpers/Helpers.svelte.js +2 -1
  23. package/package.json +1 -1
@@ -0,0 +1,26 @@
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ module
6
+ >
7
+ import { getErrorMessage, loadingText } from '../../Helpers/Helpers.svelte.js';
8
+ import Button from '../Button.svelte';
9
+
10
+ export const pending = _pending;
11
+ export const failed = _failed;
12
+ </script>
13
+
14
+ {#snippet _pending()}
15
+ {loadingText}
16
+ {/snippet}
17
+ {#snippet _failed(e: unknown, retry?: () => void)}
18
+ Error: {getErrorMessage(e)}
19
+ {#if retry}
20
+ <Button
21
+ onclick={() => {
22
+ retry();
23
+ }}>Retry</Button
24
+ >
25
+ {/if}
26
+ {/snippet}
@@ -0,0 +1,5 @@
1
+ export declare const pending: () => ReturnType<import("svelte").Snippet>;
2
+ export declare const failed: (e: unknown, retry?: () => void) => ReturnType<import("svelte").Snippet>;
3
+ declare const Snippets: import("svelte").Component<Record<string, never>, {}, "">;
4
+ type Snippets = ReturnType<typeof Snippets>;
5
+ export default Snippets;
@@ -12,7 +12,7 @@
12
12
  maxHeight: maxHeight,
13
13
  children,
14
14
  grow,
15
- isCollapsed = $bindable(false)
15
+ isCollapsed = $bindable(false),
16
16
  }: CollapsibleCardProps = $props();
17
17
 
18
18
  let cardRef: HTMLDivElement | undefined = $state();
@@ -50,13 +50,16 @@
50
50
  icon={{
51
51
  name: isCollapsed ? 'circle-plus' : 'circle-minus',
52
52
  colour: Colour['$ui-blue-5'],
53
- size: Size.Medium
53
+ size: Size.Medium,
54
54
  }}
55
55
  />
56
56
  </div>
57
57
  </div>
58
58
 
59
- <div class="content" class:is-collapsed={isCollapsed}>
59
+ <div
60
+ class="content"
61
+ class:is-collapsed={isCollapsed}
62
+ >
60
63
  {#if children}
61
64
  {@render children()}
62
65
  {/if}
@@ -1,18 +1,21 @@
1
1
  <svelte:options runes />
2
2
 
3
- <script lang="ts" module>
3
+ <script
4
+ lang="ts"
5
+ module
6
+ >
4
7
  import { dev } from '$app/environment';
5
8
  import type { GridItem } from '../Types/Internal/GridItem.js';
6
9
  import type {
7
10
  GridMultiSelectItem,
8
11
  GridMultiSelectItemAsObject,
9
- GridMultiSelectItemAsPrimitive
12
+ GridMultiSelectItemAsPrimitive,
10
13
  } from '../Types/Internal/GridMultiSelectItem.js';
11
14
  import type { GridSelectItem } from '../Types/Internal/GridSelectItem.js';
12
15
  import type {
13
16
  GridSingleSelectItem,
14
17
  GridSingleSelectItemAsObject,
15
- GridSingleSelectItemAsPrimitive
18
+ GridSingleSelectItemAsPrimitive,
16
19
  } from '../Types/Internal/GridSingleSelectItem.js';
17
20
  import type { GridTextItem } from '../Types/Internal/GridTextItem.js';
18
21
  import type { ValueProp } from '../Types/Internal/Misc.js';
@@ -24,7 +27,10 @@
24
27
  const textTypes = new Set(['text', 'email', 'tel']);
25
28
  </script>
26
29
 
27
- <script lang="ts" generics="V extends object,VP extends ValueProp<V>">
30
+ <script
31
+ lang="ts"
32
+ generics="V extends object,VP extends ValueProp<V>"
33
+ >
28
34
  const { item, first, last }: GridInputProps<V, VP> = $props();
29
35
 
30
36
  let value = $derived(isText(item) ? (item.value ?? '') : '');
@@ -76,9 +82,15 @@
76
82
  }
77
83
  </script>
78
84
 
79
- <label class:first class:last>
85
+ <label
86
+ class:first
87
+ class:last
88
+ >
80
89
  <div class="left">
81
- <span class:first class:last>{item.label}</span>
90
+ <span
91
+ class:first
92
+ class:last>{item.label}</span
93
+ >
82
94
  </div>
83
95
  {#if isText(item)}
84
96
  <TextInput
@@ -1,12 +1,17 @@
1
1
  <svelte:options runes />
2
2
 
3
- <script lang="ts" module>
3
+ <script
4
+ lang="ts"
5
+ module
6
+ >
4
7
  export interface LoadingAnimationProps {
5
8
  showText?: boolean;
6
9
  }
7
10
  </script>
8
11
 
9
12
  <script lang="ts">
13
+ import { loadingText } from '../Helpers/Helpers.svelte.js';
14
+
10
15
  let { showText = true }: LoadingAnimationProps = $props();
11
16
  </script>
12
17
 
@@ -14,7 +19,7 @@
14
19
  <div id="cube">
15
20
  <div class="front"></div>
16
21
  <div class="front">
17
- {#if showText}<span>loading…</span>{/if}
22
+ {#if showText}<span>{loadingText}</span>{/if}
18
23
  </div>
19
24
  <div class="back"></div>
20
25
  <div class="right"></div>
@@ -478,38 +478,36 @@
478
478
  />
479
479
  </div>
480
480
  {:else}
481
- <svelte:boundary>
482
- <div class="input-wrapper right">
483
- {#await isNullFilter}
484
- loading
485
- {:then isNullFilter}
486
- {#if isNullFilter}
487
- <TextInput
488
- data-type="quicksearch"
489
- id={inputId}
490
- value="is Null"
491
- disabled
492
- variant={InputVariant.Table}
493
- />
494
- {:else}
495
- <!-- NOTE: This is a text input in order to support the __in functionality, which is a comma separated list of numbers -->
496
- <TextInput
497
- data-type="quicksearch"
498
- id={inputId}
499
- bind:value={asdfvalue as string | null}
500
- placeholder="Filter&hellip;"
501
- variant={InputVariant.Table}
502
- oninput={() => {
503
- tableContext.paginationRepo?.filterBy(def.id, [asdfvalue || null]);
504
- }}
505
- onkeydown={closeOnCtrlF}
506
- />
507
- {/if}
508
- {:catch e}
509
- {@debug e}
510
- {/await}
511
- </div>
512
- </svelte:boundary>
481
+ <div class="input-wrapper right">
482
+ {#await isNullFilter}
483
+ loading
484
+ {:then isNullFilter}
485
+ {#if isNullFilter}
486
+ <TextInput
487
+ data-type="quicksearch"
488
+ id={inputId}
489
+ value="is Null"
490
+ disabled
491
+ variant={InputVariant.Table}
492
+ />
493
+ {:else}
494
+ <!-- NOTE: This is a text input in order to support the __in functionality, which is a comma separated list of numbers -->
495
+ <TextInput
496
+ data-type="quicksearch"
497
+ id={inputId}
498
+ bind:value={asdfvalue as string | null}
499
+ placeholder="Filter&hellip;"
500
+ variant={InputVariant.Table}
501
+ oninput={() => {
502
+ tableContext.paginationRepo?.filterBy(def.id, [asdfvalue || null]);
503
+ }}
504
+ onkeydown={closeOnCtrlF}
505
+ />
506
+ {/if}
507
+ {:catch e}
508
+ {@debug e}
509
+ {/await}
510
+ </div>
513
511
  {/if}
514
512
  {:else if asdfvalue == null || typeof asdfvalue == 'string'}
515
513
  <div class="input-wrapper right">
@@ -25,7 +25,7 @@
25
25
 
26
26
  const cellTypes: Record<
27
27
  'Number' | 'Date' | 'Select' | 'Checkbox' | 'Query' | 'Text',
28
- Component<any>
28
+ object & Component<any>
29
29
  > = {
30
30
  Number: TableNumberInput,
31
31
  Date: TableDatePicker,
@@ -6,7 +6,7 @@
6
6
  >
7
7
  import { TableContext } from '../../../Types/Context/TableContext.svelte.js';
8
8
  import { TableFocusDetails } from '../../../Types/Focus/TableFocusDetails.svelte.js';
9
- import { devCatch, getErrorMessage, isValidityTuple } from '../../../../../Helpers/Helpers.svelte.js';
9
+ import { devCatch, isValidityTuple } from '../../../../../Helpers/Helpers.svelte.js';
10
10
  import type { SelectOption } from '../../../../../Types/Internal/SelectOption.js';
11
11
  import { Validity } from '../../../../../Types/Internal/Validity.js';
12
12
  import { getContext } from 'svelte';
@@ -87,16 +87,10 @@ class:bottom={focusDetails.bottomEdge} -->
87
87
  tableContext.endFocus(focusDetails.coordinates);
88
88
  }}
89
89
  >
90
- <svelte:boundary>
91
- {#snippet pending()}
90
+ {#if hasValue}
91
+ {#await visibleValue}
92
92
  loading…
93
- {/snippet}
94
- {#snippet onerror(e)}
95
- Error: {getErrorMessage(e)}
96
- {/snippet}
97
- {#if hasValue}
98
- {@const v = await visibleValue}
99
-
93
+ {:then v}
100
94
  {(v instanceof Date
101
95
  ? v.toLocaleDateString()
102
96
  : options.length
@@ -104,17 +98,17 @@ class:bottom={focusDetails.bottomEdge} -->
104
98
  : v) ??
105
99
  v ??
106
100
  ''}
107
- {:else if children}
108
- <div
109
- class="slot-wrapper"
110
- class:multifocus={focusDetails.isMultiFocused}
111
- class:multifocus-start={focusDetails.isMultiFocusStart}
112
- >
113
- <!-- TODO {focusDetails.isMultiFocusStart} -->
114
- {@render children()}
115
- </div>
116
- {/if}
117
- </svelte:boundary>
101
+ {/await}
102
+ {:else if children}
103
+ <div
104
+ class="slot-wrapper"
105
+ class:multifocus={focusDetails.isMultiFocused}
106
+ class:multifocus-start={focusDetails.isMultiFocusStart}
107
+ >
108
+ <!-- TODO {focusDetails.isMultiFocusStart} -->
109
+ {@render children()}
110
+ </div>
111
+ {/if}
118
112
  </td>
119
113
 
120
114
  <style>td {
@@ -1,6 +1,9 @@
1
1
  <svelte:options runes />
2
2
 
3
- <script lang="ts" module>
3
+ <script
4
+ lang="ts"
5
+ module
6
+ >
4
7
  import Button from '../../../../Button.svelte';
5
8
  import type { TableActionButton } from '../../../Types/Columns/TableActionButton.js';
6
9
  import { getErrorMessage } from '../../../../../Helpers/Helpers.svelte.js';
@@ -14,7 +17,10 @@
14
17
  }
15
18
  </script>
16
19
 
17
- <script lang="ts" generics="T extends object,FilterValueType">
20
+ <script
21
+ lang="ts"
22
+ generics="T extends object,FilterValueType"
23
+ >
18
24
  const { action, cell }: TableActionProps<T, FilterValueType> = $props();
19
25
 
20
26
  const isEnabledPromise: boolean | Promise<boolean> = $derived.by(() => {
@@ -29,44 +29,17 @@
29
29
  id: columnDef.id,
30
30
  });
31
31
 
32
- const editableAsync = $derived(
32
+ const editable = $derived(
33
33
  cell.column.columnDef.isEditable(cell.row.original, cell.row.originalIndex)
34
34
  );
35
- let editable = $state(false);
36
-
37
- let asyncCounter = 0;
38
- $effect(() => {
39
- void editableAsync;
40
- const localCounter = (asyncCounter = asyncCounter + 1);
41
- (async () => {
42
- try {
43
- const isEditable = await editableAsync;
44
- if (asyncCounter === localCounter) {
45
- editable = isEditable;
46
- } else if (cell.column.columnDef.debug) {
47
- console.log('skipping async editable because it is stale');
48
- }
49
- } catch (e) {
50
- if (cell.column.columnDef.debug) {
51
- console.error(e);
52
- }
53
- if (asyncCounter === localCounter) {
54
- editable = false;
55
- } else if (cell.column.columnDef.debug) {
56
- console.log('skipping async editable because it is stale');
57
- }
58
- }
59
- })().catch(devCatch);
60
- });
61
35
  const focusDetails: TableFocusDetails<T, never> = $derived(
62
36
  new TableFocusDetails(cell, tableContext)
63
37
  );
64
38
 
65
39
  let modalLock = $state(false);
66
40
 
67
- const isBeingEdited = $derived(
68
- editable &&
69
- tableContext.focusStart?.column === focusDetails.coordinates.column &&
41
+ const wantsToBeEdited = $derived(
42
+ tableContext.focusStart?.column === focusDetails.coordinates.column &&
70
43
  tableContext.focusEnd?.column === focusDetails.coordinates.column &&
71
44
  tableContext.focusStart.row === focusDetails.coordinates.row &&
72
45
  tableContext.focusEnd.row === focusDetails.coordinates.row &&
@@ -74,10 +47,33 @@
74
47
  );
75
48
 
76
49
  $effect(() => {
77
- if (isBeingEdited) {
50
+ void editable;
51
+ if (wantsToBeEdited) {
52
+ editable
53
+ .then((isEditable) => {
54
+ if (isEditable) {
55
+ return tick().then(() => {
56
+ modalLock = true;
57
+ });
58
+ } else {
59
+ if (modalLock) {
60
+ return tick().then(() => {
61
+ if (!tableContext.singleClickEditing) {
62
+ tableContext.focusStartIsBeingEdited = false;
63
+ }
64
+ modalLock = false;
65
+ });
66
+ }
67
+
68
+ return;
69
+ }
70
+ })
71
+ .catch(devCatch);
72
+ } else {
78
73
  tick()
79
74
  .then(() => {
80
- modalLock = true;
75
+ modalLock = false;
76
+ tableContext.focusStartIsBeingEdited = false;
81
77
  })
82
78
  .catch(devCatch);
83
79
  }
@@ -86,9 +82,9 @@
86
82
  let tdref: HTMLTableCellElement | undefined = $state();
87
83
 
88
84
  const id = $derived(`${tableContext.tableName}-cell-${cell.row.visibleIndex}-${cell.column.id}`);
89
- function handleSingleClick(event?: Event) {
85
+ async function handleSingleClick(event?: Event) {
90
86
  if (
91
- editable &&
87
+ (await editable) &&
92
88
  tableContext.singleClickEditing &&
93
89
  (!event || !event.target || (event.target as HTMLElement).id === id)
94
90
  ) {
@@ -118,8 +114,8 @@
118
114
  .catch(devCatch);
119
115
  });
120
116
 
121
- const handleDoubleClick = () => {
122
- if (editable) {
117
+ const handleDoubleClick = async () => {
118
+ if (await editable) {
123
119
  tableContext.focusStartIsBeingEdited = true;
124
120
  }
125
121
  };
@@ -134,11 +130,15 @@
134
130
  .catch(devCatch);
135
131
  }
136
132
 
133
+ function tryHandleDoubleClick() {
134
+ handleDoubleClick().catch(devCatch);
135
+ }
136
+
137
137
  let prevtdref: HTMLTableCellElement | undefined = undefined;
138
138
  $effect(() => {
139
139
  if (tdref) {
140
140
  if (tdref != prevtdref) {
141
- tdref.addEventListener('edit', handleDoubleClick);
141
+ tdref.addEventListener('edit', tryHandleDoubleClick);
142
142
  } else {
143
143
  prevtdref = tdref;
144
144
  }
@@ -184,8 +184,12 @@
184
184
  onmouseup={() => {
185
185
  tableContext.endFocus(coordinates);
186
186
  }}
187
- onclick={handleSingleClick}
188
- ondblclick={handleDoubleClick}
187
+ onclick={() => {
188
+ handleSingleClick().catch(devCatch);
189
+ }}
190
+ ondblclick={() => {
191
+ handleDoubleClick().catch(devCatch);
192
+ }}
189
193
  >
190
194
  {#if modalLock}
191
195
  <DateModal
@@ -4,12 +4,11 @@
4
4
  lang="ts"
5
5
  generics="T extends object,"
6
6
  >
7
- import { dev } from '$app/environment';
8
7
  import QuerySelect from '../../../../QuerySelect.svelte';
9
8
  import type { QueryDef } from '../../../Types/Columns/Definitions/Accessors/QueryDef.svelte.js';
10
9
  import { TableContext } from '../../../Types/Context/TableContext.svelte.js';
11
10
  import { TableFocusDetails } from '../../../Types/Focus/TableFocusDetails.svelte.js';
12
- import { devCatch, isValidityTuple } from '../../../../../Helpers/Helpers.svelte.js';
11
+ import { devCatch, isValidityTuple, loadingText } from '../../../../../Helpers/Helpers.svelte.js';
13
12
  import type { SelectOption } from '../../../../../Types/Internal/SelectOption.js';
14
13
  import { Validity } from '../../../../../Types/Internal/Validity.js';
15
14
  import { getContext, tick, untrack } from 'svelte';
@@ -32,10 +31,9 @@
32
31
 
33
32
  const tableContext = getContext<TableContext<T, never>>(TableContext.identifier);
34
33
 
35
- const editableAsync = $derived(
34
+ const editable = $derived(
36
35
  cell.column.columnDef.isEditable(cell.row.original, cell.row.originalIndex)
37
36
  );
38
- let editable = $state(false);
39
37
 
40
38
  let valueAsyncCounter = 0;
41
39
  $effect(() => {
@@ -76,33 +74,6 @@
76
74
  });
77
75
  });
78
76
 
79
- let editableAsyncCounter = 0;
80
- $effect(() => {
81
- void editableAsync;
82
- untrack(() => {
83
- const localCounter = (editableAsyncCounter = editableAsyncCounter + 1);
84
- (async () => {
85
- try {
86
- const isEditable = await editableAsync;
87
- if (editableAsyncCounter === localCounter) {
88
- editable = isEditable;
89
- } else if (dev || columnDef.debug) {
90
- console.log('skipping async editable because it is stale');
91
- }
92
- } catch (e) {
93
- if (dev || columnDef.debug) {
94
- console.error(e);
95
- }
96
- if (editableAsyncCounter === localCounter) {
97
- editable = false;
98
- } else if (dev || columnDef.debug) {
99
- console.log('skipping async editable because it is stale');
100
- }
101
- }
102
- })().catch(devCatch);
103
- });
104
- });
105
-
106
77
  const focusDetails: TableFocusDetails<T, never> = $derived(
107
78
  new TableFocusDetails(cell, tableContext)
108
79
  );
@@ -118,7 +89,9 @@
118
89
 
119
90
  let isBeingEdited = $state(false);
120
91
 
121
- $effect(() => {
92
+ /*
93
+ $effect(() => {
94
+ void editable;
122
95
  if (wantsToBeEdited) {
123
96
  if (editable) {
124
97
  tick()
@@ -153,6 +126,42 @@
153
126
  }
154
127
  }
155
128
  });
129
+ */
130
+ $effect(() => {
131
+ void editable;
132
+ if (wantsToBeEdited) {
133
+ editable
134
+ .then((isEditable) => {
135
+ if (isEditable) {
136
+ return tick().then(() => {
137
+ isBeingEdited = true;
138
+ });
139
+ } else {
140
+ if (isBeingEdited) {
141
+ return tick()
142
+ .then(() => {
143
+ if (!tableContext.singleClickEditing) {
144
+ tableContext.focusStartIsBeingEdited = false;
145
+ }
146
+
147
+ isBeingEdited = false;
148
+ })
149
+ .catch(devCatch);
150
+ }
151
+ }
152
+
153
+ return;
154
+ })
155
+
156
+ .catch(devCatch);
157
+ } else {
158
+ tick()
159
+ .then(() => {
160
+ tableContext.focusStartIsBeingEdited = false;
161
+ })
162
+ .catch(devCatch);
163
+ }
164
+ });
156
165
 
157
166
  let validity: Validity = $state(Validity.Valid);
158
167
  $effect(() => {
@@ -171,9 +180,9 @@
171
180
  .catch(devCatch);
172
181
  });
173
182
 
174
- const handleTDFocus = () => {
183
+ const handleTDFocus = async () => {
175
184
  if (
176
- editable &&
185
+ (await editable) &&
177
186
  tableContext.focusStart?.column === focusDetails.coordinates.column &&
178
187
  tableContext.focusStart.row === focusDetails.coordinates.row
179
188
  ) {
@@ -192,11 +201,15 @@
192
201
  return false;
193
202
  };
194
203
 
195
- function handleSingleClick() {
196
- return tableContext.singleClickEditing && handleTDFocus();
204
+ async function handleSingleClick(): Promise<boolean> {
205
+ return tableContext.singleClickEditing && (await handleTDFocus());
197
206
  }
198
- function handleDoubleClick() {
199
- return !tableContext.singleClickEditing && handleTDFocus();
207
+ async function handleDoubleClick(): Promise<boolean> {
208
+ return !tableContext.singleClickEditing && (await handleTDFocus());
209
+ }
210
+
211
+ function tryHandleTDFocus() {
212
+ handleTDFocus().catch(devCatch);
200
213
  }
201
214
 
202
215
  function handleUnfocus(e: KeyboardEvent) {
@@ -251,7 +264,7 @@
251
264
  void tdref;
252
265
  untrack(() => {
253
266
  if (tdref && tdref != prevtdref) {
254
- tdref.addEventListener('edit', handleTDFocus);
267
+ tdref.addEventListener('edit', tryHandleTDFocus);
255
268
  } else {
256
269
  prevtdref = tdref;
257
270
  }
@@ -329,14 +342,17 @@
329
342
  }
330
343
  }}
331
344
  onmouseup={() => {
332
- const wasHandled = handleSingleClick();
333
- if (!wasHandled) {
334
- tableContext.endFocus(focusDetails.coordinates);
335
- }
345
+ handleSingleClick()
346
+ .then((wasHandled) => {
347
+ if (!wasHandled) {
348
+ tableContext.endFocus(focusDetails.coordinates);
349
+ }
350
+ })
351
+ .catch(devCatch);
336
352
  }}
337
353
  >
338
354
  {#await visibleValue}
339
- loading…
355
+ {loadingText}
340
356
  {:then v}
341
357
  {v}
342
358
  {/await}