@lavalogic/scoria 0.40.0 → 0.40.2
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 +58 -58
- package/dist/Components/AccordionGroup.svelte +46 -46
- package/dist/Components/AccordionGroupButton.svelte +76 -76
- package/dist/Components/Action.svelte +136 -136
- package/dist/Components/AlertModal.svelte +195 -195
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +729 -729
- package/dist/Components/Base/BaseModal.svelte +125 -125
- package/dist/Components/Base/ContextWrapper.svelte +72 -72
- package/dist/Components/Base/Pagination.svelte +198 -198
- package/dist/Components/Base/Snippets.svelte +36 -36
- package/dist/Components/BigRadioSet.svelte +38 -38
- package/dist/Components/Bubble.svelte +101 -101
- package/dist/Components/Button.svelte +209 -209
- package/dist/Components/Checkbox.svelte +86 -86
- package/dist/Components/CollapsibleCard.svelte +78 -78
- package/dist/Components/Contexts/ContextMenu.svelte +164 -164
- package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
- package/dist/Components/Contexts/ContextMenuOption.svelte +60 -60
- package/dist/Components/Contexts/Toast.svelte +86 -86
- package/dist/Components/Contexts/ToastContainer.svelte +65 -65
- package/dist/Components/Contexts/Tooltip.svelte +37 -37
- package/dist/Components/DataMatrixIcon.svelte +112 -112
- package/dist/Components/DateInput.svelte +148 -148
- package/dist/Components/DatePicker.svelte +300 -300
- package/dist/Components/DesktopModal.svelte +90 -90
- package/dist/Components/Dial.svelte +204 -204
- package/dist/Components/DimensionInput.svelte +170 -170
- package/dist/Components/DragMenu/DragMenuHolder.svelte +119 -119
- package/dist/Components/DragMenu/DraggableCard.svelte +77 -77
- package/dist/Components/FileCard.svelte +24 -24
- package/dist/Components/FileUpload.svelte +236 -236
- package/dist/Components/GridInput.svelte +196 -196
- package/dist/Components/GridInputSet.svelte +29 -29
- package/dist/Components/HorizontalTabGroup.svelte +82 -82
- package/dist/Components/HorizontalTabGroupButton.svelte +44 -44
- package/dist/Components/Icon.svelte +128 -128
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/InfoAlert.svelte +35 -35
- package/dist/Components/LoadingAnimation.svelte +29 -29
- package/dist/Components/LoadingModal.svelte +45 -45
- package/dist/Components/LoadingOverlay.svelte +25 -25
- package/dist/Components/Modal.svelte +258 -258
- package/dist/Components/MultiSelect.svelte +220 -220
- package/dist/Components/Nav/Nav.svelte +110 -110
- package/dist/Components/Nav/NavServiceMenuList.svelte +43 -43
- package/dist/Components/Nav/NavTab.svelte +62 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +112 -112
- package/dist/Components/Nav/ServicesNav.svelte +80 -80
- package/dist/Components/NumberInput.svelte +157 -157
- package/dist/Components/PageHeading.svelte +25 -25
- package/dist/Components/PasswordInput.svelte +88 -88
- package/dist/Components/Portal.svelte +36 -36
- package/dist/Components/ProgressBubble.svelte +107 -107
- package/dist/Components/QuerySelect.svelte +366 -366
- package/dist/Components/SingleSelect.svelte +250 -250
- package/dist/Components/StepButton.svelte +70 -70
- package/dist/Components/StepForm.svelte +140 -140
- package/dist/Components/Switch.svelte +69 -69
- package/dist/Components/Table/ARCHITECTURE.md +298 -298
- package/dist/Components/Table/Body/QuickSearchCell.svelte +679 -679
- package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +51 -51
- package/dist/Components/Table/Body/Rows/ColumnList.svelte +59 -59
- package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +454 -454
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +79 -79
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +185 -185
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +124 -124
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +131 -120
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +234 -234
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +105 -105
- package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +87 -87
- package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +126 -126
- package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +159 -159
- package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +246 -246
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +216 -216
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +252 -252
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +179 -179
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +221 -221
- package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +197 -197
- package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +190 -190
- package/dist/Components/Table/Body/Rows/TableRow.svelte +290 -290
- package/dist/Components/Table/Body/TableBody.svelte +155 -155
- package/dist/Components/Table/ColumnFactory.svelte.js +1 -0
- package/dist/Components/Table/Headers/HighlightAllHeader.svelte +41 -41
- package/dist/Components/Table/Headers/SelectAllHeader.svelte +30 -30
- package/dist/Components/Table/Headers/TableHead.svelte +415 -415
- package/dist/Components/Table/Misc/ColumnPanel.svelte +39 -39
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +39 -39
- package/dist/Components/Table/Misc/FilterInput.svelte +641 -641
- package/dist/Components/Table/Misc/FilterPanel.svelte +190 -190
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +31 -31
- package/dist/Components/Table/Misc/ShareViewModal.svelte +291 -291
- package/dist/Components/Table/Misc/SidePanel.svelte +35 -35
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +644 -644
- package/dist/Components/Table/Misc/TableFooter.svelte +340 -340
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +140 -140
- package/dist/Components/Table/Misc/TableSidebar.svelte +200 -200
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +105 -105
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +100 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +107 -107
- package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +192 -192
- package/dist/Components/Table/NestedTable.svelte +130 -130
- package/dist/Components/Table/Table.svelte +692 -692
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.d.ts +5 -0
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.js +3 -0
- package/dist/Components/Table/Types/Public/ColumnOptions.d.ts +10 -0
- package/dist/Components/Test/TestContextConsumer.svelte +13 -13
- package/dist/Components/TextArea.svelte +130 -130
- package/dist/Components/TextInput.svelte +176 -176
- package/dist/Components/ThreeStateRadio.svelte +131 -131
- package/dist/Components/Touch/BoolCard.svelte +45 -45
- package/dist/Components/Touch/DateModal.svelte +209 -209
- package/dist/Components/Touch/EditCard.svelte +59 -59
- package/dist/Components/Touch/InfoCard.svelte +31 -31
- package/dist/Components/Touch/InfoTextCard.svelte +28 -28
- package/dist/Components/Touch/ModalExplanation.svelte +17 -17
- package/dist/Components/Touch/NumberKeyboard.svelte +225 -225
- package/dist/Components/Touch/NumberModal.svelte +79 -79
- package/dist/Components/Touch/PlusMinusCard.svelte +46 -46
- package/dist/Components/Touch/SelectModal.svelte +127 -127
- package/dist/Components/Touch/SummaryCard.svelte +93 -93
- package/dist/Components/Touch/TextAreaModal.svelte +95 -95
- package/dist/Components/Touch/TextModal.svelte +106 -106
- package/dist/Components/Touch/TouchCard.svelte +33 -33
- package/dist/Components/Touch/TouchModal.svelte +274 -274
- package/dist/Components/Touch/UtilityButton.svelte +109 -109
- package/dist/Components/VerticalTabGroup.svelte +79 -79
- package/dist/Components/VerticalTabGroupButton.svelte +58 -58
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Types/Examples/ExampleModal.svelte +35 -35
- package/dist/scss/_basics.scss +12 -12
- package/dist/scss/_colours.scss +134 -134
- package/dist/scss/_mixins.scss +3392 -3392
- package/dist/scss/_motion.scss +57 -57
- package/dist/scss/_sizing.scss +85 -85
- package/dist/scss/_transitions.scss +8 -8
- package/package.json +1 -1
|
@@ -1,218 +1,218 @@
|
|
|
1
|
-
<svelte:options runes />
|
|
2
|
-
|
|
3
|
-
<script
|
|
4
|
-
lang="ts"
|
|
5
|
-
module
|
|
6
|
-
>
|
|
7
|
-
import type { TableCell } from '../../../Types/Columns/TableCell.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Props for {@link TableNumberInput}. The cell renders a `NumberInput`
|
|
11
|
-
* when the row enters edit mode, otherwise shows the awaited display
|
|
12
|
-
* value. Cell value is parsed to `number` through `parseFloat` so that
|
|
13
|
-
* decimal values are preserved.
|
|
14
|
-
*/
|
|
15
|
-
export interface TableNumberInputProps<T extends object> {
|
|
16
|
-
/** The number cell to render. */
|
|
17
|
-
cell: TableCell<T>;
|
|
18
|
-
}
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<script
|
|
22
|
-
lang="ts"
|
|
23
|
-
generics="T extends object, RowIdType extends Primitive"
|
|
24
|
-
>
|
|
25
|
-
import NumberInput from '../../../../NumberInput.svelte';
|
|
26
|
-
import { NumberInputDef } from '../../../Types/Columns/Definitions/Accessors/NumberInputDef.svelte.js';
|
|
27
|
-
import { TableContext } from '../../../Types/Context/TableContext.svelte.js';
|
|
28
|
-
import { type Primitive } from '../../../Types/Context/TableInitOptions.js';
|
|
29
|
-
import { devCatch, loadingText } from '../../../../../Helpers/Helpers.svelte.js';
|
|
30
|
-
import { InputVariant } from '../../../../../Types/Internal/InputVariant.js';
|
|
31
|
-
import { Validity } from '../../../../../Types/Internal/Validity.js';
|
|
32
|
-
import { getContext, tick, untrack } from 'svelte';
|
|
33
|
-
import { useAsyncEditable } from './_helpers/useAsyncEditable.svelte.js';
|
|
34
|
-
|
|
35
|
-
const { cell }: TableNumberInputProps<T> = $props();
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Coerce the cell value (which may be a string, number, null, or a promise)
|
|
39
|
-
* into a numeric (or numeric-string / null) value usable by `NumberInput`.
|
|
40
|
-
* `parseFloat` preserves decimals (the original used `parseInt`, which was
|
|
41
|
-
* a P2 workorder finding because it silently truncated `12.34` to `12`).
|
|
42
|
-
*/
|
|
43
|
-
const value: Promise<number | string | null> | number | string | null = $derived.by(() => {
|
|
44
|
-
const _value = cell.getValue();
|
|
45
|
-
|
|
46
|
-
return typeof _value === 'string'
|
|
47
|
-
? parseFloat(_value)
|
|
48
|
-
: typeof _value === 'number'
|
|
49
|
-
? _value
|
|
50
|
-
: ((_value as Promise<string | number | null | undefined> | null | undefined)?.then((v) => {
|
|
51
|
-
return typeof v === 'string' ? parseFloat(v) : (v ?? null);
|
|
52
|
-
}) ?? null);
|
|
53
|
-
});
|
|
54
|
-
let tempNumericValue: number = $state(0);
|
|
55
|
-
|
|
56
|
-
const visibleValue = $derived(
|
|
57
|
-
cell.column.columnDef.getDisplayValue?.(cell.row.original, cell.row.originalIndex) ?? value
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
$effect(() => {
|
|
61
|
-
void value;
|
|
62
|
-
untrack(() => {
|
|
63
|
-
resetValue();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
function resetValue() {
|
|
68
|
-
tempNumericValue = typeof value === 'string' ? parseFloat(value) : (value as number);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let tdref: HTMLElement | undefined = $state();
|
|
72
|
-
let inputRef: HTMLInputElement | undefined = $state();
|
|
73
|
-
|
|
74
|
-
const tableContext = getContext<TableContext<T, RowIdType>>(TableContext.identifier);
|
|
75
|
-
|
|
76
|
-
function onBlur(): void {
|
|
77
|
-
const oldValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
78
|
-
|
|
79
|
-
if (oldValue != tempNumericValue) {
|
|
80
|
-
tableContext
|
|
81
|
-
.onEditCell(cell.row.original, editable.focusDetails.coordinates, tempNumericValue)
|
|
82
|
-
.catch(devCatch);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!tableContext.singleClickEditing) {
|
|
86
|
-
tableContext.focusStartIsBeingEdited = false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const editable = useAsyncEditable<T, RowIdType>({
|
|
91
|
-
cell: () => cell,
|
|
92
|
-
onLeaveEdit: () => {
|
|
93
|
-
onBlur();
|
|
94
|
-
},
|
|
95
|
-
onAfterEnterEdit: () => {
|
|
96
|
-
inputRef?.select();
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
function handleInputKeydown(e: KeyboardEvent) {
|
|
101
|
-
switch (e.key) {
|
|
102
|
-
case 'Escape':
|
|
103
|
-
e.preventDefault();
|
|
104
|
-
e.stopPropagation();
|
|
105
|
-
|
|
106
|
-
resetValue();
|
|
107
|
-
editable.leaveEditingViaKeyboard(tdref);
|
|
108
|
-
break;
|
|
109
|
-
case 'Enter':
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
e.stopPropagation();
|
|
112
|
-
|
|
113
|
-
(e.target as HTMLInputElement).blur();
|
|
114
|
-
editable.leaveEditingViaKeyboard(tdref);
|
|
115
|
-
break;
|
|
116
|
-
default: {
|
|
117
|
-
//ignore other keys
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function onInputFocus(e: FocusEvent) {
|
|
124
|
-
(e.target as HTMLInputElement).scrollIntoView({
|
|
125
|
-
behavior: 'instant',
|
|
126
|
-
block: 'nearest',
|
|
127
|
-
inline: 'nearest',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Effect wires the custom `edit` event via the shared
|
|
133
|
-
* `useAsyncEditable` helper, which returns a cleanup unsubscriber so the
|
|
134
|
-
* listener is removed when `tdref` is remounted or the cell unmounts.
|
|
135
|
-
*/
|
|
136
|
-
$effect(() => editable.attachEditListener(tdref));
|
|
137
|
-
</script>
|
|
138
|
-
|
|
139
|
-
{#if editable.isBeingEdited}
|
|
140
|
-
<div class="input-cell">
|
|
141
|
-
<NumberInput
|
|
142
|
-
id={`${tableContext.tableName}-cell-${cell.row.visibleIndex}-${cell.column.id}`}
|
|
143
|
-
min={(cell.column.columnDef as NumberInputDef<T>).min}
|
|
144
|
-
max={(cell.column.columnDef as NumberInputDef<T>).max}
|
|
145
|
-
variant={InputVariant.Table}
|
|
146
|
-
onkeydown={handleInputKeydown}
|
|
147
|
-
bind:value={tempNumericValue}
|
|
148
|
-
onfocus={onInputFocus}
|
|
149
|
-
bind:inputRef
|
|
150
|
-
/>
|
|
151
|
-
<!-- HACK this onBlur is now being called by an effect because otherwise it fires twice -->
|
|
152
|
-
</div>
|
|
153
|
-
{:else}
|
|
154
|
-
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
|
155
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
156
|
-
<div
|
|
157
|
-
style={editable.focusDetails.outline}
|
|
158
|
-
id={`${tableContext.tableName}-cell-${cell.row.visibleIndex}-${cell.column.id}`}
|
|
159
|
-
onmousedown={(e) => {
|
|
160
|
-
// start focus only on left click
|
|
161
|
-
if (e.button === 0) {
|
|
162
|
-
if (e.shiftKey) {
|
|
163
|
-
e.preventDefault();
|
|
164
|
-
tableContext.setFocusEnd(editable.focusDetails.coordinates);
|
|
165
|
-
} else {
|
|
166
|
-
tableContext.startFocus(editable.focusDetails.coordinates);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}}
|
|
170
|
-
onmouseover={() => {
|
|
171
|
-
if (tableContext.isMousingDown) {
|
|
172
|
-
tableContext.setFocusEnd(editable.focusDetails.coordinates);
|
|
173
|
-
}
|
|
174
|
-
}}
|
|
175
|
-
onmouseup={() => {
|
|
176
|
-
const wasHandled = editable.handleSingleClickFocus();
|
|
177
|
-
if (wasHandled) {
|
|
178
|
-
resetValue();
|
|
179
|
-
tick()
|
|
180
|
-
.then(() => {
|
|
181
|
-
inputRef?.focus();
|
|
182
|
-
})
|
|
183
|
-
.catch(devCatch);
|
|
184
|
-
} else {
|
|
185
|
-
tableContext.endFocus(editable.focusDetails.coordinates);
|
|
186
|
-
}
|
|
187
|
-
}}
|
|
188
|
-
bind:this={tdref}
|
|
189
|
-
tabIndex="0"
|
|
190
|
-
class:editable={editable.editable}
|
|
191
|
-
class="focusable"
|
|
192
|
-
class:multifocus={editable.focusDetails.isMultiFocused}
|
|
193
|
-
class:multifocus-start={editable.focusDetails.isMultiFocusStart}
|
|
194
|
-
class:info={editable.validity == Validity.Info}
|
|
195
|
-
class:success={editable.validity == Validity.Valid}
|
|
196
|
-
class:warning={editable.validity == Validity.Warning}
|
|
197
|
-
class:error={editable.validity == Validity.Invalid}
|
|
198
|
-
ondblclick={() => {
|
|
199
|
-
const wasHandled = editable.handleDoubleClickFocus();
|
|
200
|
-
if (wasHandled) {
|
|
201
|
-
resetValue();
|
|
202
|
-
tick()
|
|
203
|
-
.then(() => {
|
|
204
|
-
inputRef?.focus();
|
|
205
|
-
})
|
|
206
|
-
.catch(devCatch);
|
|
207
|
-
}
|
|
208
|
-
}}
|
|
209
|
-
>
|
|
210
|
-
{#await visibleValue}
|
|
211
|
-
{loadingText}
|
|
212
|
-
{:then value}{value ?? '-'}{/await}
|
|
213
|
-
</div>
|
|
214
|
-
{/if}
|
|
215
|
-
|
|
1
|
+
<svelte:options runes />
|
|
2
|
+
|
|
3
|
+
<script
|
|
4
|
+
lang="ts"
|
|
5
|
+
module
|
|
6
|
+
>
|
|
7
|
+
import type { TableCell } from '../../../Types/Columns/TableCell.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Props for {@link TableNumberInput}. The cell renders a `NumberInput`
|
|
11
|
+
* when the row enters edit mode, otherwise shows the awaited display
|
|
12
|
+
* value. Cell value is parsed to `number` through `parseFloat` so that
|
|
13
|
+
* decimal values are preserved.
|
|
14
|
+
*/
|
|
15
|
+
export interface TableNumberInputProps<T extends object> {
|
|
16
|
+
/** The number cell to render. */
|
|
17
|
+
cell: TableCell<T>;
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<script
|
|
22
|
+
lang="ts"
|
|
23
|
+
generics="T extends object, RowIdType extends Primitive"
|
|
24
|
+
>
|
|
25
|
+
import NumberInput from '../../../../NumberInput.svelte';
|
|
26
|
+
import { NumberInputDef } from '../../../Types/Columns/Definitions/Accessors/NumberInputDef.svelte.js';
|
|
27
|
+
import { TableContext } from '../../../Types/Context/TableContext.svelte.js';
|
|
28
|
+
import { type Primitive } from '../../../Types/Context/TableInitOptions.js';
|
|
29
|
+
import { devCatch, loadingText } from '../../../../../Helpers/Helpers.svelte.js';
|
|
30
|
+
import { InputVariant } from '../../../../../Types/Internal/InputVariant.js';
|
|
31
|
+
import { Validity } from '../../../../../Types/Internal/Validity.js';
|
|
32
|
+
import { getContext, tick, untrack } from 'svelte';
|
|
33
|
+
import { useAsyncEditable } from './_helpers/useAsyncEditable.svelte.js';
|
|
34
|
+
|
|
35
|
+
const { cell }: TableNumberInputProps<T> = $props();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Coerce the cell value (which may be a string, number, null, or a promise)
|
|
39
|
+
* into a numeric (or numeric-string / null) value usable by `NumberInput`.
|
|
40
|
+
* `parseFloat` preserves decimals (the original used `parseInt`, which was
|
|
41
|
+
* a P2 workorder finding because it silently truncated `12.34` to `12`).
|
|
42
|
+
*/
|
|
43
|
+
const value: Promise<number | string | null> | number | string | null = $derived.by(() => {
|
|
44
|
+
const _value = cell.getValue();
|
|
45
|
+
|
|
46
|
+
return typeof _value === 'string'
|
|
47
|
+
? parseFloat(_value)
|
|
48
|
+
: typeof _value === 'number'
|
|
49
|
+
? _value
|
|
50
|
+
: ((_value as Promise<string | number | null | undefined> | null | undefined)?.then((v) => {
|
|
51
|
+
return typeof v === 'string' ? parseFloat(v) : (v ?? null);
|
|
52
|
+
}) ?? null);
|
|
53
|
+
});
|
|
54
|
+
let tempNumericValue: number = $state(0);
|
|
55
|
+
|
|
56
|
+
const visibleValue = $derived(
|
|
57
|
+
cell.column.columnDef.getDisplayValue?.(cell.row.original, cell.row.originalIndex) ?? value
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
$effect(() => {
|
|
61
|
+
void value;
|
|
62
|
+
untrack(() => {
|
|
63
|
+
resetValue();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
function resetValue() {
|
|
68
|
+
tempNumericValue = typeof value === 'string' ? parseFloat(value) : (value as number);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let tdref: HTMLElement | undefined = $state();
|
|
72
|
+
let inputRef: HTMLInputElement | undefined = $state();
|
|
73
|
+
|
|
74
|
+
const tableContext = getContext<TableContext<T, RowIdType>>(TableContext.identifier);
|
|
75
|
+
|
|
76
|
+
function onBlur(): void {
|
|
77
|
+
const oldValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
78
|
+
|
|
79
|
+
if (oldValue != tempNumericValue) {
|
|
80
|
+
tableContext
|
|
81
|
+
.onEditCell(cell.row.original, editable.focusDetails.coordinates, tempNumericValue)
|
|
82
|
+
.catch(devCatch);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!tableContext.singleClickEditing) {
|
|
86
|
+
tableContext.focusStartIsBeingEdited = false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const editable = useAsyncEditable<T, RowIdType>({
|
|
91
|
+
cell: () => cell,
|
|
92
|
+
onLeaveEdit: () => {
|
|
93
|
+
onBlur();
|
|
94
|
+
},
|
|
95
|
+
onAfterEnterEdit: () => {
|
|
96
|
+
inputRef?.select();
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
function handleInputKeydown(e: KeyboardEvent) {
|
|
101
|
+
switch (e.key) {
|
|
102
|
+
case 'Escape':
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
e.stopPropagation();
|
|
105
|
+
|
|
106
|
+
resetValue();
|
|
107
|
+
editable.leaveEditingViaKeyboard(tdref);
|
|
108
|
+
break;
|
|
109
|
+
case 'Enter':
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
e.stopPropagation();
|
|
112
|
+
|
|
113
|
+
(e.target as HTMLInputElement).blur();
|
|
114
|
+
editable.leaveEditingViaKeyboard(tdref);
|
|
115
|
+
break;
|
|
116
|
+
default: {
|
|
117
|
+
//ignore other keys
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function onInputFocus(e: FocusEvent) {
|
|
124
|
+
(e.target as HTMLInputElement).scrollIntoView({
|
|
125
|
+
behavior: 'instant',
|
|
126
|
+
block: 'nearest',
|
|
127
|
+
inline: 'nearest',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Effect wires the custom `edit` event via the shared
|
|
133
|
+
* `useAsyncEditable` helper, which returns a cleanup unsubscriber so the
|
|
134
|
+
* listener is removed when `tdref` is remounted or the cell unmounts.
|
|
135
|
+
*/
|
|
136
|
+
$effect(() => editable.attachEditListener(tdref));
|
|
137
|
+
</script>
|
|
138
|
+
|
|
139
|
+
{#if editable.isBeingEdited}
|
|
140
|
+
<div class="input-cell">
|
|
141
|
+
<NumberInput
|
|
142
|
+
id={`${tableContext.tableName}-cell-${cell.row.visibleIndex}-${cell.column.id}`}
|
|
143
|
+
min={(cell.column.columnDef as NumberInputDef<T>).min}
|
|
144
|
+
max={(cell.column.columnDef as NumberInputDef<T>).max}
|
|
145
|
+
variant={InputVariant.Table}
|
|
146
|
+
onkeydown={handleInputKeydown}
|
|
147
|
+
bind:value={tempNumericValue}
|
|
148
|
+
onfocus={onInputFocus}
|
|
149
|
+
bind:inputRef
|
|
150
|
+
/>
|
|
151
|
+
<!-- HACK this onBlur is now being called by an effect because otherwise it fires twice -->
|
|
152
|
+
</div>
|
|
153
|
+
{:else}
|
|
154
|
+
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
|
155
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
156
|
+
<div
|
|
157
|
+
style={editable.focusDetails.outline}
|
|
158
|
+
id={`${tableContext.tableName}-cell-${cell.row.visibleIndex}-${cell.column.id}`}
|
|
159
|
+
onmousedown={(e) => {
|
|
160
|
+
// start focus only on left click
|
|
161
|
+
if (e.button === 0) {
|
|
162
|
+
if (e.shiftKey) {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
tableContext.setFocusEnd(editable.focusDetails.coordinates);
|
|
165
|
+
} else {
|
|
166
|
+
tableContext.startFocus(editable.focusDetails.coordinates);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}}
|
|
170
|
+
onmouseover={() => {
|
|
171
|
+
if (tableContext.isMousingDown) {
|
|
172
|
+
tableContext.setFocusEnd(editable.focusDetails.coordinates);
|
|
173
|
+
}
|
|
174
|
+
}}
|
|
175
|
+
onmouseup={() => {
|
|
176
|
+
const wasHandled = editable.handleSingleClickFocus();
|
|
177
|
+
if (wasHandled) {
|
|
178
|
+
resetValue();
|
|
179
|
+
tick()
|
|
180
|
+
.then(() => {
|
|
181
|
+
inputRef?.focus();
|
|
182
|
+
})
|
|
183
|
+
.catch(devCatch);
|
|
184
|
+
} else {
|
|
185
|
+
tableContext.endFocus(editable.focusDetails.coordinates);
|
|
186
|
+
}
|
|
187
|
+
}}
|
|
188
|
+
bind:this={tdref}
|
|
189
|
+
tabIndex="0"
|
|
190
|
+
class:editable={editable.editable}
|
|
191
|
+
class="focusable"
|
|
192
|
+
class:multifocus={editable.focusDetails.isMultiFocused}
|
|
193
|
+
class:multifocus-start={editable.focusDetails.isMultiFocusStart}
|
|
194
|
+
class:info={editable.validity == Validity.Info}
|
|
195
|
+
class:success={editable.validity == Validity.Valid}
|
|
196
|
+
class:warning={editable.validity == Validity.Warning}
|
|
197
|
+
class:error={editable.validity == Validity.Invalid}
|
|
198
|
+
ondblclick={() => {
|
|
199
|
+
const wasHandled = editable.handleDoubleClickFocus();
|
|
200
|
+
if (wasHandled) {
|
|
201
|
+
resetValue();
|
|
202
|
+
tick()
|
|
203
|
+
.then(() => {
|
|
204
|
+
inputRef?.focus();
|
|
205
|
+
})
|
|
206
|
+
.catch(devCatch);
|
|
207
|
+
}
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
{#await visibleValue}
|
|
211
|
+
{loadingText}
|
|
212
|
+
{:then value}{value ?? '-'}{/await}
|
|
213
|
+
</div>
|
|
214
|
+
{/if}
|
|
215
|
+
|
|
216
216
|
<style>.focusable,
|
|
217
217
|
.checkbox-cell,
|
|
218
218
|
.input-cell,
|
|
@@ -279,4 +279,4 @@
|
|
|
279
279
|
.input-cell {
|
|
280
280
|
padding: unset;
|
|
281
281
|
box-sizing: border-box;
|
|
282
|
-
}</style>
|
|
282
|
+
}</style>
|