@lavalogic/scoria 0.24.0 → 0.25.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/Base/ContextWrapper.svelte +1 -0
- package/dist/Components/Base/Pagination.svelte +28 -7
- package/dist/Components/Base/Pagination.svelte.d.ts +8 -0
- package/dist/Components/Base/PaginationProps.d.ts +4 -2
- package/dist/Components/Base/Snippets.svelte +3 -0
- package/dist/Components/Base/Snippets.svelte.d.ts +1 -0
- package/dist/Components/Contexts/ContextMenu.svelte +87 -8
- package/dist/Components/Contexts/ContextMenuOption.svelte +35 -9
- package/dist/Components/Contexts/ContextMenuOptionProps.d.ts +1 -0
- package/dist/Components/Contexts/MaybeFocusable.d.ts +3 -0
- package/dist/Components/Contexts/MaybeFocusable.js +1 -0
- package/dist/Components/Contexts/Toast.svelte +18 -10
- package/dist/Components/HorizontalTabGroup.svelte +0 -23
- package/dist/Components/Table/Body/Rows/TableRow.svelte +86 -60
- package/dist/Components/Table/Body/Rows/TableRow.svelte.d.ts +22 -13
- package/dist/Components/Table/Body/TableBody.svelte +23 -28
- package/dist/Components/Table/Body/TableBody.svelte.d.ts +10 -2
- package/dist/Components/Table/Body/TableBodyProps.d.ts +2 -0
- package/dist/Components/Table/ColumnDefinitions/ExampleItemColumnDefRepository.svelte.js +1 -1
- package/dist/Components/Table/Table.svelte +54 -56
- package/dist/Components/Table/Types/Context/TableContext.svelte.d.ts +1 -1
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +4 -1
- package/dist/Components/Touch/NumberKeyboard.svelte +58 -19
- package/dist/Components/VerticalTabGroup.svelte +1 -29
- package/dist/Types/Internal/TabOption.d.ts +0 -1
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
setContext(AlertContext.identifier, alertContext);
|
|
35
35
|
|
|
36
36
|
// NOTE known limitation. Not expected to mutate after instantiation
|
|
37
|
+
// svelte-ignore state_referenced_locally
|
|
37
38
|
const untypedListenerContext = new UntypedInputContext(debug);
|
|
38
39
|
setContext(UntypedInputContext.identifier, untypedListenerContext);
|
|
39
40
|
</script>
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
<svelte:options runes />
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<!-- @component
|
|
4
|
+
Allows for automated pagination of local content in cases where a collection may become a performance concern
|
|
5
|
+
|
|
6
|
+
### Usage
|
|
7
|
+
```svelte
|
|
8
|
+
<Pagination snippet={itemSnippet} pageSize={20} items={dataWrapper.value} key="id" />
|
|
9
|
+
```
|
|
10
|
+
-->
|
|
11
|
+
<script
|
|
12
|
+
lang="ts"
|
|
13
|
+
generics="T extends object"
|
|
14
|
+
>
|
|
4
15
|
import { autoPluralise, generateShortUUID } from '../../Helpers/Helpers.svelte.js';
|
|
5
16
|
import { Colour } from '../../scss/colours.js';
|
|
6
17
|
import { Side } from '../../Types/Internal/Side.js';
|
|
@@ -20,7 +31,7 @@
|
|
|
20
31
|
border = false,
|
|
21
32
|
padding = '1.5rem', //sizing.$regular-padding
|
|
22
33
|
gap = '1.5rem', // sizing.$regular-gap
|
|
23
|
-
height
|
|
34
|
+
height,
|
|
24
35
|
}: PaginationProps<T> = $props();
|
|
25
36
|
|
|
26
37
|
const _uuid = generateShortUUID();
|
|
@@ -101,18 +112,28 @@
|
|
|
101
112
|
|
|
102
113
|
<div class="scrollable">
|
|
103
114
|
<div class="block">
|
|
104
|
-
<Icon
|
|
115
|
+
<Icon
|
|
116
|
+
name="paper"
|
|
117
|
+
colour={Colour['$ui-blue-6']}
|
|
118
|
+
/>
|
|
105
119
|
<span>{lastPage} {autoPluralise('Page', lastPage)}</span>
|
|
106
120
|
</div>
|
|
107
121
|
|
|
108
122
|
<div class="block">
|
|
109
123
|
<label for="{_uuid}-jump-to-page"
|
|
110
|
-
><Icon
|
|
124
|
+
><Icon
|
|
125
|
+
name="arrow-move-horizontal"
|
|
126
|
+
colour={Colour['$ui-blue-6']}
|
|
127
|
+
/></label
|
|
111
128
|
>
|
|
112
129
|
|
|
113
130
|
<label for="{_uuid}-jump-to-page">Jump to page:</label>
|
|
114
131
|
|
|
115
|
-
<NumberInput
|
|
132
|
+
<NumberInput
|
|
133
|
+
id="{_uuid}-jump-to-page"
|
|
134
|
+
value={pageValue}
|
|
135
|
+
oninput={onNumberInput}
|
|
136
|
+
/>
|
|
116
137
|
</div>
|
|
117
138
|
|
|
118
139
|
<div class="block nopad page-arrow">
|
|
@@ -126,7 +147,7 @@
|
|
|
126
147
|
size={Size.FillHeight}
|
|
127
148
|
iconLeft={{
|
|
128
149
|
name: 'left-close',
|
|
129
|
-
size: Size.FillHeight
|
|
150
|
+
size: Size.FillHeight,
|
|
130
151
|
}}>Previous Page</Button
|
|
131
152
|
>
|
|
132
153
|
</div>
|
|
@@ -158,7 +179,7 @@
|
|
|
158
179
|
disabled={pageIndex == lastPageIndex}
|
|
159
180
|
iconRight={{
|
|
160
181
|
name: 'right-close',
|
|
161
|
-
size: Size.FillHeight
|
|
182
|
+
size: Size.FillHeight,
|
|
162
183
|
}}>Next Page</Button
|
|
163
184
|
>
|
|
164
185
|
</div>
|
|
@@ -20,6 +20,14 @@ interface $$IsomorphicComponent {
|
|
|
20
20
|
<T extends object>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
21
21
|
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Allows for automated pagination of local content in cases where a collection may become a performance concern
|
|
25
|
+
*
|
|
26
|
+
* ### Usage
|
|
27
|
+
* ```svelte
|
|
28
|
+
* <Pagination snippet={itemSnippet} pageSize={20} items={dataWrapper.value} key="id" />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
23
31
|
declare const Pagination: $$IsomorphicComponent;
|
|
24
32
|
type Pagination<T extends object> = InstanceType<typeof Pagination<T>>;
|
|
25
33
|
export default Pagination;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
export interface PaginationProps<T extends object> {
|
|
3
|
-
|
|
3
|
+
/** Used to index each item for a unique key. Duplicate values will result in error */
|
|
4
4
|
key: string & keyof T;
|
|
5
|
-
|
|
5
|
+
items: Array<T>;
|
|
6
|
+
/** Second argument is the index */
|
|
6
7
|
snippet: Snippet<[T, number]>;
|
|
8
|
+
pageSize?: number;
|
|
7
9
|
itemName?: string;
|
|
8
10
|
border?: boolean;
|
|
9
11
|
padding?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const pending: () => ReturnType<import("svelte").Snippet>;
|
|
2
2
|
export declare const failed: (e: unknown, retry?: () => void) => ReturnType<import("svelte").Snippet>;
|
|
3
|
+
/** An empty component that only exists to export common snippets */
|
|
3
4
|
declare const Snippets: import("svelte").Component<Record<string, never>, {}, "">;
|
|
4
5
|
type Snippets = ReturnType<typeof Snippets>;
|
|
5
6
|
export default Snippets;
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
<svelte:options runes />
|
|
2
2
|
|
|
3
|
+
<!--
|
|
4
|
+
@component
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
-->
|
|
3
8
|
<script lang="ts">
|
|
4
9
|
import { ContextMenuContext } from '../../Contexts/ContextMenuContext.svelte.js';
|
|
5
10
|
import { devCatch } from '../../Helpers/Helpers.svelte.js';
|
|
6
|
-
import { getContext, tick } from 'svelte';
|
|
11
|
+
import { getContext, tick, untrack } from 'svelte';
|
|
7
12
|
import { fade } from 'svelte/transition';
|
|
8
13
|
import ContextMenuOption from './ContextMenuOption.svelte';
|
|
14
|
+
import type { MaybeFocusable } from './MaybeFocusable.js';
|
|
9
15
|
|
|
10
16
|
const contextMenuContext = getContext<ContextMenuContext>(ContextMenuContext.identifier);
|
|
11
17
|
|
|
@@ -36,8 +42,8 @@
|
|
|
36
42
|
.catch(devCatch);
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
let menuEl
|
|
40
|
-
function
|
|
45
|
+
let menuEl = $state<HTMLUListElement | undefined>();
|
|
46
|
+
function closeOnClickOutside(e: MouseEvent) {
|
|
41
47
|
if (!menuEl) {
|
|
42
48
|
return;
|
|
43
49
|
}
|
|
@@ -46,14 +52,81 @@
|
|
|
46
52
|
}
|
|
47
53
|
contextMenuContext.closeMenu();
|
|
48
54
|
}
|
|
55
|
+
|
|
56
|
+
let previousElement = $state<MaybeFocusable | null | undefined>();
|
|
57
|
+
|
|
58
|
+
$effect.pre(() => {
|
|
59
|
+
if (contextMenuContext.showMenu) {
|
|
60
|
+
untrack(() => {
|
|
61
|
+
previousElement = document.activeElement as MaybeFocusable;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
function refocusPrevious() {
|
|
67
|
+
previousElement?.focus?.();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function focusNext() {
|
|
71
|
+
if (!menuEl) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const items = [...menuEl.querySelectorAll<HTMLElement>('[role="menuitem"]')];
|
|
75
|
+
const index = items.indexOf(document.activeElement as HTMLElement);
|
|
76
|
+
const found = items.at((index + 1) % items.length);
|
|
77
|
+
if (!found) {
|
|
78
|
+
console.warn(`could not find next item`);
|
|
79
|
+
}
|
|
80
|
+
found?.focus();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function focusPrev() {
|
|
84
|
+
if (!menuEl) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const items = [...menuEl.querySelectorAll<HTMLElement>('[role="menuitem"]')];
|
|
88
|
+
const index = items.indexOf(document.activeElement as HTMLElement);
|
|
89
|
+
|
|
90
|
+
const found = items.at((index - 1 + items.length) % items.length);
|
|
91
|
+
if (!found) {
|
|
92
|
+
console.warn('could not find prev item');
|
|
93
|
+
}
|
|
94
|
+
found?.focus();
|
|
95
|
+
}
|
|
49
96
|
</script>
|
|
50
97
|
|
|
51
|
-
<svelte:body onclick={
|
|
98
|
+
<svelte:body onclick={closeOnClickOutside} />
|
|
52
99
|
|
|
53
100
|
{#if contextMenuContext.showMenu}
|
|
54
|
-
<
|
|
55
|
-
{
|
|
101
|
+
<ul
|
|
102
|
+
transition:fade={{ duration: 50 }}
|
|
103
|
+
bind:this={menuEl}
|
|
104
|
+
style="top: {_y}px; left: {_x}px;"
|
|
105
|
+
role="menu"
|
|
106
|
+
aria-label="Context menu"
|
|
107
|
+
onkeydown={(e) => {
|
|
108
|
+
if (e.key === 'Escape') {
|
|
109
|
+
e.stopImmediatePropagation();
|
|
110
|
+
e.stopPropagation();
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
contextMenuContext.closeMenu();
|
|
113
|
+
refocusPrevious();
|
|
114
|
+
} else if (e.key == 'ArrowUp') {
|
|
115
|
+
e.stopImmediatePropagation();
|
|
116
|
+
e.stopPropagation();
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
focusPrev();
|
|
119
|
+
} else if (e.key == 'ArrowDown') {
|
|
120
|
+
e.stopImmediatePropagation();
|
|
121
|
+
e.stopPropagation();
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
focusNext();
|
|
124
|
+
}
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
{#each contextMenuContext.items as item, index (item)}
|
|
56
128
|
<ContextMenuOption
|
|
129
|
+
{index}
|
|
57
130
|
disabled={item.disabled}
|
|
58
131
|
onclick={() => {
|
|
59
132
|
item.callback();
|
|
@@ -62,17 +135,23 @@
|
|
|
62
135
|
text={item.text}
|
|
63
136
|
/>
|
|
64
137
|
{/each}
|
|
65
|
-
</
|
|
138
|
+
</ul>
|
|
66
139
|
{/if}
|
|
67
140
|
|
|
68
141
|
<style>
|
|
69
|
-
|
|
142
|
+
ul {
|
|
143
|
+
padding: 4px;
|
|
70
144
|
position: fixed;
|
|
71
145
|
display: grid;
|
|
72
146
|
border: 1px solid #0003;
|
|
73
147
|
box-shadow: 2px 2px 5px 0px #0002;
|
|
148
|
+
gap: 4px;
|
|
74
149
|
background: white;
|
|
75
150
|
z-index: 9999;
|
|
76
151
|
line-height: initial;
|
|
77
152
|
}
|
|
153
|
+
|
|
154
|
+
ul:focus {
|
|
155
|
+
outline: none;
|
|
156
|
+
}
|
|
78
157
|
</style>
|
|
@@ -1,21 +1,40 @@
|
|
|
1
1
|
<svelte:options runes />
|
|
2
2
|
|
|
3
3
|
<script lang="ts">
|
|
4
|
+
import { devCatch } from '../../Helpers/Helpers.svelte.js';
|
|
5
|
+
import { tick } from 'svelte';
|
|
4
6
|
import type { ContextMenuOptionProps } from './ContextMenuOptionProps.js';
|
|
5
7
|
|
|
6
8
|
let {
|
|
7
9
|
text = $bindable(''),
|
|
10
|
+
index,
|
|
8
11
|
disabled = false,
|
|
9
12
|
onclick,
|
|
10
|
-
children
|
|
13
|
+
children,
|
|
11
14
|
}: ContextMenuOptionProps = $props();
|
|
15
|
+
|
|
16
|
+
let element = $state<HTMLButtonElement | undefined>();
|
|
17
|
+
|
|
18
|
+
$effect(() => {
|
|
19
|
+
void element;
|
|
20
|
+
if (index == 0) {
|
|
21
|
+
tick()
|
|
22
|
+
.then(() => {
|
|
23
|
+
if (element) {
|
|
24
|
+
element.focus();
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
.catch(devCatch);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
12
30
|
</script>
|
|
13
31
|
|
|
14
|
-
|
|
15
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
16
|
-
<div
|
|
32
|
+
<button
|
|
17
33
|
class="context-menu-item"
|
|
34
|
+
role="menuitem"
|
|
18
35
|
class:disabled
|
|
36
|
+
tabindex={index}
|
|
37
|
+
bind:this={element}
|
|
19
38
|
onclick={(e) => {
|
|
20
39
|
e.stopImmediatePropagation();
|
|
21
40
|
e.stopPropagation();
|
|
@@ -28,9 +47,11 @@
|
|
|
28
47
|
{:else if children}
|
|
29
48
|
{@render children()}
|
|
30
49
|
{/if}
|
|
31
|
-
</
|
|
50
|
+
</button>
|
|
32
51
|
|
|
33
|
-
<style>
|
|
52
|
+
<style>button {
|
|
53
|
+
background-color: #ffffff;
|
|
54
|
+
border: none;
|
|
34
55
|
padding: 4px 15px;
|
|
35
56
|
cursor: default;
|
|
36
57
|
font-size: 14px;
|
|
@@ -40,14 +61,19 @@
|
|
|
40
61
|
user-select: none;
|
|
41
62
|
}
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
button:focus,
|
|
65
|
+
button:focus-within {
|
|
66
|
+
outline: solid 1px #259fc7;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
button:hover {
|
|
44
70
|
background: rgba(0, 0, 0, 0.1333333333);
|
|
45
71
|
}
|
|
46
72
|
|
|
47
|
-
|
|
73
|
+
button.disabled {
|
|
48
74
|
color: rgba(0, 0, 0, 0.4);
|
|
49
75
|
}
|
|
50
76
|
|
|
51
|
-
|
|
77
|
+
button.disabled:hover {
|
|
52
78
|
background: #ffffff;
|
|
53
79
|
}</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<svelte:options runes />
|
|
2
2
|
|
|
3
|
-
<script
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
module
|
|
6
|
+
>
|
|
4
7
|
import { ColourSet } from '../../scss/colours.js';
|
|
5
8
|
import { Size } from '../../Types/Internal/Size.js';
|
|
6
9
|
import { Validity } from '../../Types/Internal/Validity.js';
|
|
@@ -14,7 +17,9 @@
|
|
|
14
17
|
let { toast, copy }: ToastProps = $props();
|
|
15
18
|
</script>
|
|
16
19
|
|
|
17
|
-
<
|
|
20
|
+
<output
|
|
21
|
+
role={toast.result == Validity.Invalid ? 'alert' : 'status'}
|
|
22
|
+
aria-live={toast.result == Validity.Invalid ? 'assertive' : 'polite'}
|
|
18
23
|
class:info={toast.result == Validity.Info}
|
|
19
24
|
class:success={toast.result == Validity.Valid}
|
|
20
25
|
class:warning={toast.result == Validity.Warning}
|
|
@@ -31,7 +36,10 @@
|
|
|
31
36
|
colourSet={ColourSet.Auxiliary}
|
|
32
37
|
/>
|
|
33
38
|
{:else}
|
|
34
|
-
<Icon
|
|
39
|
+
<Icon
|
|
40
|
+
name="info"
|
|
41
|
+
size={Size.MediumLarge}
|
|
42
|
+
/>
|
|
35
43
|
{/if}
|
|
36
44
|
</div>
|
|
37
45
|
<span>{toast.message}</span>
|
|
@@ -48,36 +56,36 @@
|
|
|
48
56
|
</div>
|
|
49
57
|
{/if}
|
|
50
58
|
</div>
|
|
51
|
-
</
|
|
59
|
+
</output>
|
|
52
60
|
|
|
53
|
-
<style>
|
|
61
|
+
<style>output {
|
|
54
62
|
font-weight: 700;
|
|
55
63
|
font-size: 1.125rem;
|
|
56
64
|
padding: 0.75rem;
|
|
57
65
|
border-radius: 4px;
|
|
58
66
|
}
|
|
59
|
-
|
|
67
|
+
output.info, output.success {
|
|
60
68
|
color: #ffffff;
|
|
61
69
|
--colour: #ffffff;
|
|
62
70
|
background-color: #259fc7;
|
|
63
71
|
}
|
|
64
|
-
|
|
72
|
+
output.warning {
|
|
65
73
|
color: #ffffff;
|
|
66
74
|
--colour: #ffffff;
|
|
67
75
|
background-color: #e7b500;
|
|
68
76
|
}
|
|
69
|
-
|
|
77
|
+
output.error {
|
|
70
78
|
color: #ffffff;
|
|
71
79
|
--colour: #ffffff;
|
|
72
80
|
background-color: #aa1414;
|
|
73
81
|
}
|
|
74
|
-
|
|
82
|
+
output > div {
|
|
75
83
|
display: flex;
|
|
76
84
|
flex-flow: row nowrap;
|
|
77
85
|
gap: 0.75rem;
|
|
78
86
|
align-items: center;
|
|
79
87
|
}
|
|
80
|
-
|
|
88
|
+
output span {
|
|
81
89
|
text-wrap: nowrap;
|
|
82
90
|
word-break: keep-all;
|
|
83
91
|
overflow: hidden;
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
lang="ts"
|
|
5
5
|
generics="CommonDenominator"
|
|
6
6
|
>
|
|
7
|
-
import { dev } from '$app/environment';
|
|
8
|
-
|
|
9
7
|
import HorizontalTabGroupButton from './HorizontalTabGroupButton.svelte';
|
|
10
8
|
import type { HorizontalTabGroupProps } from './HorizontalTabGroupProps.js';
|
|
11
9
|
let {
|
|
@@ -16,27 +14,6 @@
|
|
|
16
14
|
noRadius = false,
|
|
17
15
|
grow = false,
|
|
18
16
|
}: HorizontalTabGroupProps<CommonDenominator> = $props();
|
|
19
|
-
|
|
20
|
-
$effect(() => {
|
|
21
|
-
if (!dev) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
for (const tab of tabs) {
|
|
25
|
-
if (tab.debug) {
|
|
26
|
-
$inspect(
|
|
27
|
-
tab.label,
|
|
28
|
-
tab.content,
|
|
29
|
-
tab.onclick,
|
|
30
|
-
tab.args,
|
|
31
|
-
tab.iconLeft,
|
|
32
|
-
tab.iconRight,
|
|
33
|
-
tab.isValid,
|
|
34
|
-
tab.disabled,
|
|
35
|
-
tab.visible
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
17
|
</script>
|
|
41
18
|
|
|
42
19
|
<div
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<script
|
|
4
4
|
lang="ts"
|
|
5
|
-
generics="T extends object"
|
|
5
|
+
generics="T extends object, RowIdType extends Primitive"
|
|
6
6
|
>
|
|
7
7
|
import { dev } from '$app/environment';
|
|
8
8
|
import { devCatch, generateShortUUID } from '../../../../Helpers/Helpers.svelte.js';
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
import type { DefsWrapper } from '../../Types/Columns/DefsWrapper.js';
|
|
13
13
|
import type { TableCell } from '../../Types/Columns/TableCell.js';
|
|
14
14
|
import { TableContext } from '../../Types/Context/TableContext.svelte.js';
|
|
15
|
+
import { type Primitive } from '../../Types/Context/TableInitOptions.js';
|
|
15
16
|
import ColumnHighlight from './ColumnHighlight.svelte';
|
|
16
17
|
import TableColumn from './Columns/TableColumn.svelte';
|
|
17
18
|
import type { TableRowProps } from './TableRowProps.js';
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
const tableContext = getContext<TableContext<T, RowIdType>>(TableContext.identifier);
|
|
19
21
|
|
|
20
22
|
const { row, side, odd = false, customHeight, includeHighlight }: TableRowProps<T> = $props();
|
|
21
23
|
|
|
@@ -50,10 +52,28 @@
|
|
|
50
52
|
let prevExpandedColumnDef: ExpandDef<T, object> | undefined = $state();
|
|
51
53
|
|
|
52
54
|
const rowIndex = $derived(cells.at(0) && cells[0].row.visibleIndex);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
)
|
|
55
|
+
let id = $state<RowIdType | undefined>();
|
|
56
|
+
const highlighted = $derived(id != undefined && tableContext.highlightedItems.has(id));
|
|
57
|
+
|
|
58
|
+
$effect(() => {
|
|
59
|
+
void row.original;
|
|
60
|
+
void tableContext.selectionExtractor;
|
|
61
|
+
|
|
62
|
+
if (rowIndex != undefined) {
|
|
63
|
+
const maybePromise = tableContext.selectionExtractor(row.original);
|
|
64
|
+
if (maybePromise instanceof Promise) {
|
|
65
|
+
maybePromise
|
|
66
|
+
.then((it) => {
|
|
67
|
+
id = it;
|
|
68
|
+
})
|
|
69
|
+
.catch(devCatch);
|
|
70
|
+
} else {
|
|
71
|
+
id = maybePromise;
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
id = undefined;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
57
77
|
|
|
58
78
|
const showHighlightButton = $derived(rowIndex != null && includeHighlight);
|
|
59
79
|
|
|
@@ -94,66 +114,70 @@
|
|
|
94
114
|
}
|
|
95
115
|
}
|
|
96
116
|
|
|
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
|
-
|
|
117
|
+
let trRef: HTMLTableRowElement | undefined = $state();
|
|
118
|
+
let _trHeight = $state(0);
|
|
119
|
+
|
|
120
|
+
let innerTrRef: HTMLTableRowElement | undefined = $state();
|
|
121
|
+
let _innerTrHeight = $state(0);
|
|
122
|
+
|
|
123
|
+
$effect(() => {
|
|
124
|
+
void trRef;
|
|
125
|
+
void customHeight;
|
|
126
|
+
|
|
127
|
+
return untrack(() => {
|
|
128
|
+
if (trRef && customHeight == null) {
|
|
129
|
+
const observer = new ResizeObserver((entries) => {
|
|
130
|
+
_trHeight = entries[0].borderBoxSize[0].blockSize;
|
|
131
|
+
});
|
|
132
|
+
observer.observe(trRef);
|
|
133
|
+
|
|
134
|
+
const currenttrRef = trRef;
|
|
135
|
+
return () => {
|
|
136
|
+
observer.unobserve(currenttrRef);
|
|
137
|
+
_trHeight = 0;
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
_trHeight = 0;
|
|
141
|
+
}
|
|
142
|
+
return () => {};
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
$effect(() => {
|
|
147
|
+
void innerTrRef;
|
|
148
|
+
return untrack(() => {
|
|
149
|
+
if (innerTrRef) {
|
|
150
|
+
const observer = new ResizeObserver((entries) => {
|
|
151
|
+
_innerTrHeight = entries[0].borderBoxSize[0].blockSize;
|
|
152
|
+
});
|
|
153
|
+
observer.observe(innerTrRef);
|
|
154
|
+
|
|
155
|
+
const currentinnerTrRef = innerTrRef;
|
|
156
|
+
return () => {
|
|
157
|
+
observer.unobserve(currentinnerTrRef);
|
|
158
|
+
};
|
|
159
|
+
} else {
|
|
160
|
+
_innerTrHeight = 0;
|
|
161
|
+
}
|
|
162
|
+
return () => {};
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const _totalTrHeight = $derived(_trHeight + _innerTrHeight);
|
|
167
|
+
export const totalTrHeight = {
|
|
168
|
+
get value() {
|
|
169
|
+
return _totalTrHeight;
|
|
170
|
+
},
|
|
171
|
+
};
|
|
146
172
|
</script>
|
|
147
173
|
|
|
148
|
-
<!-- onMouseEnter={onMouseEnter}
|
|
149
|
-
onMouseLeave={onMouseLeave} -->
|
|
150
174
|
<tr
|
|
151
175
|
class:hoverable
|
|
152
176
|
class:alt={tableContext.alternateRowColours && odd}
|
|
153
177
|
class:highlighted
|
|
154
178
|
style={customHeight ? `height: ${customHeight}px !important;` : null}
|
|
179
|
+
bind:this={trRef}
|
|
155
180
|
>
|
|
156
|
-
<!-- bind:this={trRef} -->
|
|
157
181
|
{#if showHighlightButton}
|
|
158
182
|
<ColumnHighlight
|
|
159
183
|
rowIndex={rowIndex ??
|
|
@@ -181,8 +205,10 @@ onMouseLeave={onMouseLeave} -->
|
|
|
181
205
|
{#if expandedColumnDef}
|
|
182
206
|
<!-- TODO re-test and re-implement these -->
|
|
183
207
|
<!-- transition:slide={{ duration: 150, axis: 'y', delay: 0 }} -->
|
|
184
|
-
|
|
185
|
-
|
|
208
|
+
<tr
|
|
209
|
+
class="inner-table"
|
|
210
|
+
bind:this={innerTrRef}
|
|
211
|
+
>
|
|
186
212
|
{#await innerDataPromise}
|
|
187
213
|
<td {colspan}>loading…</td>
|
|
188
214
|
{:then data}
|
|
@@ -1,25 +1,34 @@
|
|
|
1
|
+
import { type Primitive } from '../../Types/Context/TableInitOptions.js';
|
|
1
2
|
import type { TableRowProps } from './TableRowProps.js';
|
|
2
|
-
declare function $$render<T extends object>(): {
|
|
3
|
+
declare function $$render<T extends object, RowIdType extends Primitive>(): {
|
|
3
4
|
props: TableRowProps<T>;
|
|
4
|
-
exports: {
|
|
5
|
+
exports: {
|
|
6
|
+
totalTrHeight: {
|
|
7
|
+
readonly value: number;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
5
10
|
bindings: "";
|
|
6
11
|
slots: {};
|
|
7
12
|
events: {};
|
|
8
13
|
};
|
|
9
|
-
declare class __sveltets_Render<T extends object> {
|
|
10
|
-
props(): ReturnType<typeof $$render<T>>['props'];
|
|
11
|
-
events(): ReturnType<typeof $$render<T>>['events'];
|
|
12
|
-
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
14
|
+
declare class __sveltets_Render<T extends object, RowIdType extends Primitive> {
|
|
15
|
+
props(): ReturnType<typeof $$render<T, RowIdType>>['props'];
|
|
16
|
+
events(): ReturnType<typeof $$render<T, RowIdType>>['events'];
|
|
17
|
+
slots(): ReturnType<typeof $$render<T, RowIdType>>['slots'];
|
|
13
18
|
bindings(): "";
|
|
14
|
-
exports(): {
|
|
19
|
+
exports(): {
|
|
20
|
+
totalTrHeight: {
|
|
21
|
+
readonly value: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
15
24
|
}
|
|
16
25
|
interface $$IsomorphicComponent {
|
|
17
|
-
new <T extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
18
|
-
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
19
|
-
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
20
|
-
<T extends object>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
21
|
-
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
26
|
+
new <T extends object, RowIdType extends Primitive>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T, RowIdType>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T, RowIdType>['props']>, ReturnType<__sveltets_Render<T, RowIdType>['events']>, ReturnType<__sveltets_Render<T, RowIdType>['slots']>> & {
|
|
27
|
+
$$bindings?: ReturnType<__sveltets_Render<T, RowIdType>['bindings']>;
|
|
28
|
+
} & ReturnType<__sveltets_Render<T, RowIdType>['exports']>;
|
|
29
|
+
<T extends object, RowIdType extends Primitive>(internal: unknown, props: ReturnType<__sveltets_Render<T, RowIdType>['props']> & {}): ReturnType<__sveltets_Render<T, RowIdType>['exports']>;
|
|
30
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
22
31
|
}
|
|
23
32
|
declare const TableRow: $$IsomorphicComponent;
|
|
24
|
-
type TableRow<T extends object> = InstanceType<typeof TableRow<T>>;
|
|
33
|
+
type TableRow<T extends object, RowIdType extends Primitive> = InstanceType<typeof TableRow<T, RowIdType>>;
|
|
25
34
|
export default TableRow;
|
|
@@ -4,38 +4,34 @@
|
|
|
4
4
|
lang="ts"
|
|
5
5
|
generics="T extends object"
|
|
6
6
|
>
|
|
7
|
+
import type { RefWrapper } from '../../../Types/Internal/RefWrapper.js';
|
|
7
8
|
import { getContext } from 'svelte';
|
|
8
9
|
import { TableContext } from '../Types/Context/TableContext.svelte.js';
|
|
9
10
|
import QuickSearchCell from './QuickSearchCell.svelte';
|
|
10
11
|
import TableRow from './Rows/TableRow.svelte';
|
|
11
12
|
import type { TableBodyProps } from './TableBodyProps.js';
|
|
12
13
|
|
|
13
|
-
let {
|
|
14
|
-
side,
|
|
15
|
-
// heights,
|
|
16
|
-
columns,
|
|
17
|
-
includeHighlight,
|
|
18
|
-
}: TableBodyProps<T> = $props();
|
|
14
|
+
let { side, heights, columns, includeHighlight }: TableBodyProps<T> = $props();
|
|
19
15
|
|
|
20
16
|
const tableContext = getContext<TableContext<T, never>>(TableContext.identifier);
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// const _rowHeights = $derived(
|
|
27
|
-
// // HACK terrible type casting due to svelte type gen not being liked by eslint
|
|
28
|
-
// rows.map((it) => (it as HasHeight | undefined)?.trHeight.value ?? 0)
|
|
29
|
-
// );
|
|
30
|
-
// export const rowHeights = {
|
|
31
|
-
// get value() {
|
|
32
|
-
// return _rowHeights;
|
|
33
|
-
// }
|
|
34
|
-
// };
|
|
18
|
+
type HasHeight = {
|
|
19
|
+
totalTrHeight?: RefWrapper<number>;
|
|
20
|
+
};
|
|
21
|
+
const rows: Array<TableRow<T, never>> = $state([]);
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
23
|
+
const _rowHeights = $derived(
|
|
24
|
+
// HACK terrible type casting due to svelte type gen not being liked by eslint
|
|
25
|
+
rows.map((it) => {
|
|
26
|
+
return (it as HasHeight | undefined)?.totalTrHeight?.value ?? 0;
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const rowHeights = {
|
|
31
|
+
get value() {
|
|
32
|
+
return _rowHeights;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
39
35
|
</script>
|
|
40
36
|
|
|
41
37
|
<tbody>
|
|
@@ -54,18 +50,17 @@
|
|
|
54
50
|
{/if}
|
|
55
51
|
|
|
56
52
|
{#each tableContext.paginationRowModel.rows as row, index (row.visibleIndex)}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<!-- {customHeight} -->
|
|
53
|
+
{@const customHeight = heights[index]?.applyTo.includes(side)
|
|
54
|
+
? heights[index].maxHeight
|
|
55
|
+
: undefined}
|
|
61
56
|
<TableRow
|
|
62
|
-
customHeight
|
|
57
|
+
{customHeight}
|
|
63
58
|
{includeHighlight}
|
|
64
59
|
{row}
|
|
65
60
|
{side}
|
|
66
61
|
odd={index % 2 == 1}
|
|
62
|
+
bind:this={rows[index]}
|
|
67
63
|
/>
|
|
68
|
-
<!-- bind:this={rows[index]} -->
|
|
69
64
|
{/each}
|
|
70
65
|
</tbody>
|
|
71
66
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { TableBodyProps } from './TableBodyProps.js';
|
|
2
2
|
declare function $$render<T extends object>(): {
|
|
3
3
|
props: TableBodyProps<T>;
|
|
4
|
-
exports: {
|
|
4
|
+
exports: {
|
|
5
|
+
rowHeights: {
|
|
6
|
+
readonly value: number[];
|
|
7
|
+
};
|
|
8
|
+
};
|
|
5
9
|
bindings: "";
|
|
6
10
|
slots: {};
|
|
7
11
|
events: {};
|
|
@@ -11,7 +15,11 @@ declare class __sveltets_Render<T extends object> {
|
|
|
11
15
|
events(): ReturnType<typeof $$render<T>>['events'];
|
|
12
16
|
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
13
17
|
bindings(): "";
|
|
14
|
-
exports(): {
|
|
18
|
+
exports(): {
|
|
19
|
+
rowHeights: {
|
|
20
|
+
readonly value: number[];
|
|
21
|
+
};
|
|
22
|
+
};
|
|
15
23
|
}
|
|
16
24
|
interface $$IsomorphicComponent {
|
|
17
25
|
new <T extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Column } from '../Types/Columns/Column.js';
|
|
2
|
+
import type { HeightData } from './HeightData.js';
|
|
2
3
|
export interface TableBodyProps<T extends object> {
|
|
3
4
|
side: 'left' | 'centre' | 'right';
|
|
5
|
+
heights: Array<HeightData<T>>;
|
|
4
6
|
columns: Array<Column<T>>;
|
|
5
7
|
includeHighlight: boolean;
|
|
6
8
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import type { RefWrapper } from '../../Types/Internal/RefWrapper.js';
|
|
13
13
|
import { getContext, onMount, setContext, tick, untrack } from 'svelte';
|
|
14
14
|
import LoadingOverlay from '../LoadingOverlay.svelte';
|
|
15
|
+
import type { HeightData } from './Body/HeightData.js';
|
|
15
16
|
import { shownPopup } from './Body/Rows/Columns/ActionsCell.svelte';
|
|
16
17
|
import TableBody from './Body/TableBody.svelte';
|
|
17
18
|
import TableHead from './Headers/TableHead.svelte';
|
|
@@ -48,6 +49,7 @@
|
|
|
48
49
|
const { nested = false, tableContext }: TableProps<T, IdType> = $props();
|
|
49
50
|
|
|
50
51
|
// NOTE: known limitation. This is passed as a wrapper, and they should never require reassignment. It is deeply reactive
|
|
52
|
+
// svelte-ignore state_referenced_locally
|
|
51
53
|
setContext(TableContext.identifier, tableContext);
|
|
52
54
|
|
|
53
55
|
const { openContextMenu: _openContextMenu } = getContext<ContextMenuContext>(
|
|
@@ -181,16 +183,7 @@
|
|
|
181
183
|
const minNestedHeight = $derived(20 * remPxRatio);
|
|
182
184
|
|
|
183
185
|
// HACK please figure this one out
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
//intentionally not using derived here as we sometimes need to manually change it
|
|
187
|
-
// while also allowing it to auto-pickup min height mutations
|
|
188
|
-
// eslint-disable-next-line svelte/prefer-writable-derived
|
|
189
|
-
let nestedHeight = $state(0);
|
|
190
|
-
|
|
191
|
-
$effect(() => {
|
|
192
|
-
nestedHeight = minNestedHeight;
|
|
193
|
-
});
|
|
186
|
+
let nestedHeight = $derived(minNestedHeight);
|
|
194
187
|
|
|
195
188
|
let tableRef: HTMLDivElement | undefined = undefined;
|
|
196
189
|
let mousedDownEmptySpace = $state(false);
|
|
@@ -275,46 +268,51 @@
|
|
|
275
268
|
}
|
|
276
269
|
});
|
|
277
270
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
271
|
+
type SvelteTableElement = {
|
|
272
|
+
rowHeights: RefWrapper<Array<number>>;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
let leftTable: SvelteTableElement | undefined = $state();
|
|
276
|
+
let centreTable: SvelteTableElement | undefined = $state();
|
|
277
|
+
let rightTable: SvelteTableElement | undefined = $state();
|
|
278
|
+
|
|
279
|
+
const totalRowSizes: Array<HeightData<T>> = $derived.by(() => {
|
|
280
|
+
if (!leftTable || !centreTable || !rightTable) {
|
|
281
|
+
return [];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// console.debug(`got refs for all tables`);
|
|
285
|
+
const centre = centreTable.rowHeights.value;
|
|
286
|
+
const right = rightTable.rowHeights.value;
|
|
287
|
+
|
|
288
|
+
return leftTable.rowHeights.value.map((_leftHeight, index) => {
|
|
289
|
+
const leftHeight = _leftHeight || 0;
|
|
290
|
+
const centreHeight = centre[index] || 0;
|
|
291
|
+
const rightHeight = right[index] || 0;
|
|
292
|
+
|
|
293
|
+
const maxHeight = Math.max(leftHeight, centreHeight, rightHeight);
|
|
294
|
+
const applyTo: HeightData<T>['applyTo'] = [];
|
|
295
|
+
|
|
296
|
+
if (leftHeight < maxHeight) {
|
|
297
|
+
// console.debug(`left (${leftHeight}) was lower than max (${maxHeight})`);
|
|
298
|
+
applyTo.push('left');
|
|
299
|
+
}
|
|
300
|
+
if (centreHeight < maxHeight) {
|
|
301
|
+
// console.debug(`centre (${centreHeight}) was lower than max (${maxHeight})`);
|
|
302
|
+
applyTo.push('centre');
|
|
303
|
+
}
|
|
304
|
+
if (rightHeight < maxHeight) {
|
|
305
|
+
// console.debug(`right (${rightHeight}) was lower than max (${maxHeight})`);
|
|
306
|
+
applyTo.push('right');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
index,
|
|
311
|
+
applyTo,
|
|
312
|
+
maxHeight,
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
});
|
|
318
316
|
</script>
|
|
319
317
|
|
|
320
318
|
<svelte:window
|
|
@@ -427,9 +425,9 @@
|
|
|
427
425
|
includeHighlight={appropriateSide == 'left'}
|
|
428
426
|
columns={leftColumns}
|
|
429
427
|
side="left"
|
|
428
|
+
heights={totalRowSizes}
|
|
429
|
+
bind:this={leftTable}
|
|
430
430
|
/>
|
|
431
|
-
<!-- heights={totalRowSizes} -->
|
|
432
|
-
<!-- bind:this={leftTable} -->
|
|
433
431
|
</table>
|
|
434
432
|
<!-- {/if} -->
|
|
435
433
|
|
|
@@ -447,9 +445,9 @@
|
|
|
447
445
|
includeHighlight={appropriateSide == 'centre'}
|
|
448
446
|
columns={centreColumns}
|
|
449
447
|
side="centre"
|
|
448
|
+
heights={totalRowSizes}
|
|
449
|
+
bind:this={centreTable}
|
|
450
450
|
/>
|
|
451
|
-
<!-- heights={totalRowSizes}
|
|
452
|
-
bind:this={centreTable} -->
|
|
453
451
|
</table>
|
|
454
452
|
<!-- {/if} -->
|
|
455
453
|
|
|
@@ -466,9 +464,9 @@
|
|
|
466
464
|
includeHighlight={appropriateSide == 'right'}
|
|
467
465
|
columns={rightColumns}
|
|
468
466
|
side="right"
|
|
467
|
+
heights={totalRowSizes}
|
|
468
|
+
bind:this={rightTable}
|
|
469
469
|
/>
|
|
470
|
-
<!-- heights={totalRowSizes}
|
|
471
|
-
bind:this={rightTable} -->
|
|
472
470
|
</table>
|
|
473
471
|
<!-- {/if} -->
|
|
474
472
|
</div>
|
|
@@ -77,7 +77,7 @@ export declare class TableContext<T extends object, RowIdType extends Primitive>
|
|
|
77
77
|
private _focusedRowIndices;
|
|
78
78
|
get focusedRowIndices(): ReadonlySet<number>;
|
|
79
79
|
private readonly _highlightedItems;
|
|
80
|
-
get highlightedItems(): SvelteMap<
|
|
80
|
+
get highlightedItems(): SvelteMap<RowIdType, T>;
|
|
81
81
|
_focusedColumnIds: ReadonlySet<string>;
|
|
82
82
|
get focusedColumnIds(): ReadonlySet<string>;
|
|
83
83
|
private _isMousingDown;
|
|
@@ -314,7 +314,6 @@ export class TableContext {
|
|
|
314
314
|
if (browser) {
|
|
315
315
|
this._getUserDefaults();
|
|
316
316
|
const removeInvalidPresets = () => {
|
|
317
|
-
console.warn('invalid presets. removing:', localStorage.getItem(`${this.userId}-${tableName}-presets`));
|
|
318
317
|
localStorage.removeItem(`${this.userId}-${tableName}-presets`);
|
|
319
318
|
localStorage.removeItem(`${this.userId}-${tableName}-selected-preset-name`);
|
|
320
319
|
const visibilityState = {};
|
|
@@ -1241,6 +1240,7 @@ export class TableContext {
|
|
|
1241
1240
|
};
|
|
1242
1241
|
onHighlightAll = () => {
|
|
1243
1242
|
if (this.allHighlighted) {
|
|
1243
|
+
// console.debug('All were highlighted. Clearing');
|
|
1244
1244
|
this.highlightedItems.clear();
|
|
1245
1245
|
return Promise.resolve();
|
|
1246
1246
|
}
|
|
@@ -2155,6 +2155,9 @@ export class TableContext {
|
|
|
2155
2155
|
}
|
|
2156
2156
|
indices.set(item, rowIndex);
|
|
2157
2157
|
}
|
|
2158
|
+
selectedRows.sort((left, right) => {
|
|
2159
|
+
return (indices.get(left) ?? -1) - (indices.get(right) ?? -1);
|
|
2160
|
+
});
|
|
2158
2161
|
// TODO somewhere between here and the ending of the copy functionality, we end up with issues where instead of it using the accessor fn, it tries to pick up the select option, and ends up using the value ("1", etc)
|
|
2159
2162
|
const selectedCells = [];
|
|
2160
2163
|
const rowLength = selectedRows.length;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts">
|
|
4
4
|
import { devCatch, passthrough } from '../../Helpers/Helpers.svelte.js';
|
|
5
5
|
import { InputVariant } from '../../Types/Internal/InputVariant.js';
|
|
6
|
-
import { tick } from 'svelte';
|
|
6
|
+
import { tick, untrack } from 'svelte';
|
|
7
7
|
import Icon from '../Icon.svelte';
|
|
8
8
|
import TextInput from '../TextInput.svelte';
|
|
9
9
|
import type { NumberKeyboardProps } from './NumberKeyboardProps.js';
|
|
@@ -17,10 +17,29 @@
|
|
|
17
17
|
max,
|
|
18
18
|
decimal = false,
|
|
19
19
|
inputRef = $bindable(),
|
|
20
|
-
coerceValue =
|
|
20
|
+
coerceValue = false,
|
|
21
21
|
}: NumberKeyboardProps = $props();
|
|
22
22
|
|
|
23
|
-
let _value: string = $derived(
|
|
23
|
+
let _value: string = $derived(
|
|
24
|
+
value != null && value % 1 == 0 ? value.toString() : getDecimalValue()
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
function getDecimalPlaces(value: number): number {
|
|
28
|
+
const str = value.toString();
|
|
29
|
+
if (!str.includes('.')) {
|
|
30
|
+
return decimal ? 2 : 0;
|
|
31
|
+
}
|
|
32
|
+
return str.split('.')[1].length;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const decimalPlaces = $derived(
|
|
36
|
+
min != null ? getDecimalPlaces(min) : max != null ? getDecimalPlaces(max) : decimal ? 2 : 0
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
function getDecimalValue(): string {
|
|
40
|
+
//HACK this absolutely moronic line is intentional. It's the best way to allow arbitrary decimal places without adding leading zeroes
|
|
41
|
+
return value ? parseFloat(value.toFixed(decimalPlaces)).toString() : '';
|
|
42
|
+
}
|
|
24
43
|
|
|
25
44
|
const newValue = $derived.by(() => {
|
|
26
45
|
const v = decimal ? parseFloat(_value) : parseInt(_value);
|
|
@@ -32,22 +51,32 @@
|
|
|
32
51
|
|
|
33
52
|
$effect(() => {
|
|
34
53
|
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
54
|
+
if (coerceValue) {
|
|
55
|
+
const v =
|
|
56
|
+
min != undefined && newValue != null && min > newValue
|
|
57
|
+
? min
|
|
58
|
+
: max != undefined && newValue != null && max < newValue
|
|
59
|
+
? max
|
|
60
|
+
: newValue;
|
|
42
61
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
value = v;
|
|
63
|
+
} else {
|
|
64
|
+
value = newValue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
untrack(() => {
|
|
68
|
+
refocus();
|
|
69
|
+
});
|
|
48
70
|
}
|
|
49
71
|
});
|
|
50
72
|
|
|
73
|
+
function refocus() {
|
|
74
|
+
tick()
|
|
75
|
+
.then(() => {
|
|
76
|
+
inputRef?.focus();
|
|
77
|
+
})
|
|
78
|
+
.catch(devCatch);
|
|
79
|
+
}
|
|
51
80
|
function getPrevValue() {
|
|
52
81
|
if (inputRef) {
|
|
53
82
|
if (
|
|
@@ -62,6 +91,7 @@
|
|
|
62
91
|
|
|
63
92
|
function addDecimal() {
|
|
64
93
|
_value = getPrevValue() + '.';
|
|
94
|
+
refocus();
|
|
65
95
|
}
|
|
66
96
|
|
|
67
97
|
/* due to the fact that number inputs won't allow a leading dot, we have to use a text input
|
|
@@ -74,16 +104,24 @@
|
|
|
74
104
|
|
|
75
105
|
function backspace() {
|
|
76
106
|
const preVvalue = getPrevValue();
|
|
77
|
-
|
|
107
|
+
const v = preVvalue && _value.slice(0, _value.length - 1);
|
|
108
|
+
_value = v;
|
|
78
109
|
}
|
|
79
110
|
|
|
80
111
|
function minus() {
|
|
81
|
-
|
|
112
|
+
const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) - 1;
|
|
113
|
+
|
|
114
|
+
_value = (min != null ? Math.max(min, v) : v).toString();
|
|
82
115
|
}
|
|
83
116
|
|
|
84
117
|
function plus() {
|
|
85
|
-
|
|
118
|
+
const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) + 1;
|
|
119
|
+
|
|
120
|
+
_value = (max != null ? Math.min(max, v) : v).toString();
|
|
86
121
|
}
|
|
122
|
+
|
|
123
|
+
const lessThanMin = $derived(min != null && (value == null || value < min));
|
|
124
|
+
const moreThanMax = $derived(max != null && (value == null || value > max));
|
|
87
125
|
</script>
|
|
88
126
|
|
|
89
127
|
<div class="number-input-wrapper">
|
|
@@ -98,6 +136,7 @@
|
|
|
98
136
|
bind:value={_value}
|
|
99
137
|
variant={InputVariant.Modal}
|
|
100
138
|
required
|
|
139
|
+
invalid={lessThanMin || moreThanMax}
|
|
101
140
|
/>
|
|
102
141
|
{#if max != undefined}
|
|
103
142
|
<TextInput
|
|
@@ -204,7 +243,7 @@
|
|
|
204
243
|
<button
|
|
205
244
|
onkeydown={passthrough}
|
|
206
245
|
type="button"
|
|
207
|
-
disabled={!decimal || (value != null && value % 1 !== 0)}
|
|
246
|
+
disabled={!decimal || (value != null && value % 1 !== 0) || _value.endsWith('.')}
|
|
208
247
|
onclick={addDecimal}>.</button
|
|
209
248
|
>
|
|
210
249
|
<button
|
|
@@ -2,18 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
<script
|
|
4
4
|
lang="ts"
|
|
5
|
-
|
|
5
|
+
generics="CommonDenominator"
|
|
6
6
|
>
|
|
7
|
-
import { dev } from '$app/environment';
|
|
8
7
|
import { onMount, untrack } from 'svelte';
|
|
9
8
|
import VerticalTabGroupButton from './VerticalTabGroupButton.svelte';
|
|
10
9
|
import type { VerticalTabGroupProps } from './VerticalTabGroupProps.js';
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<script
|
|
14
|
-
lang="ts"
|
|
15
|
-
generics="CommonDenominator"
|
|
16
|
-
>
|
|
17
10
|
let {
|
|
18
11
|
name,
|
|
19
12
|
tabs,
|
|
@@ -24,27 +17,6 @@
|
|
|
24
17
|
nohistory = false,
|
|
25
18
|
}: VerticalTabGroupProps<CommonDenominator> = $props();
|
|
26
19
|
|
|
27
|
-
$effect(() => {
|
|
28
|
-
if (!dev) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
for (const tab of tabs) {
|
|
32
|
-
if (tab.debug) {
|
|
33
|
-
$inspect(
|
|
34
|
-
tab.label,
|
|
35
|
-
tab.content,
|
|
36
|
-
tab.onclick,
|
|
37
|
-
tab.args,
|
|
38
|
-
tab.iconLeft,
|
|
39
|
-
tab.iconRight,
|
|
40
|
-
tab.isValid,
|
|
41
|
-
tab.disabled,
|
|
42
|
-
tab.visible
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
20
|
onMount(() => {
|
|
49
21
|
if (name && !nohistory) {
|
|
50
22
|
const tabName = sessionStorage.getItem(`${name}-active-tab`);
|