@lavalogic/scoria 0.37.44 → 0.37.45
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/ActionProps.d.ts +2 -6
- package/dist/Components/AlertModal.svelte +195 -183
- package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +702 -702
- 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/ButtonProps.d.ts +2 -6
- 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 +83 -83
- 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/DataMatrixIconProps.d.ts +3 -13
- 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/DialProps.d.ts +1 -18
- 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 -200
- 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/IconProps.d.ts +2 -7
- package/dist/Components/Icons.js +357 -357
- package/dist/Components/LoadingAnimation.svelte +29 -29
- package/dist/Components/LoadingModal.svelte +45 -45
- package/dist/Components/LoadingOverlay.svelte +25 -25
- package/dist/Components/LoadingOverlayProps.d.ts +3 -7
- package/dist/Components/Modal.svelte +258 -258
- package/dist/Components/ModalProps.d.ts +0 -3
- package/dist/Components/MultiSelect.svelte +220 -220
- package/dist/Components/MultiSelectCommonProps.d.ts +6 -17
- package/dist/Components/Nav/Nav.svelte +99 -99
- package/dist/Components/Nav/NavProps.d.ts +4 -11
- package/dist/Components/Nav/NavServiceMenuList.svelte +43 -43
- package/dist/Components/Nav/NavTab.svelte +62 -62
- package/dist/Components/Nav/ServiceMenuItem.svelte +100 -100
- 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 -108
- package/dist/Components/ProgressBubbleProps.d.ts +3 -3
- package/dist/Components/QuerySelect.svelte +366 -366
- package/dist/Components/QuerySelectProps.d.ts +4 -14
- package/dist/Components/SingleSelect.svelte +250 -250
- package/dist/Components/SingleSelectCommonProps.d.ts +3 -19
- 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 -0
- package/dist/Components/Table/Body/QuickSearchCell.svelte +679 -694
- 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 +456 -478
- package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +79 -79
- package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +185 -188
- package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +124 -124
- package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +120 -120
- package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +230 -230
- package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +105 -105
- package/dist/Components/Table/Body/Rows/Columns/SelectColumn.d.ts +12 -9
- package/dist/Components/Table/Body/Rows/Columns/SelectTableCell.d.ts +5 -5
- 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/TableDatePickerProps.d.ts +4 -4
- package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +216 -216
- package/dist/Components/Table/Body/Rows/Columns/TableQueryCell.d.ts +6 -5
- package/dist/Components/Table/Body/Rows/Columns/TableQueryColumn.d.ts +7 -6
- package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +252 -257
- package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +179 -179
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +221 -229
- package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte.d.ts +11 -11
- 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/ColumnDefinitions/ExampleItemColumnDefRepository.svelte.js +2 -3
- package/dist/Components/Table/ColumnFactory.svelte.d.ts +9 -11
- package/dist/Components/Table/ColumnFactory.svelte.js +101 -118
- package/dist/Components/Table/ColumnKindRegistry.d.ts +112 -0
- package/dist/Components/Table/ColumnKindRegistry.js +63 -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 -413
- package/dist/Components/Table/Misc/ColumnPanel.svelte +94 -94
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +112 -112
- package/dist/Components/Table/Misc/FilterInput.svelte +620 -644
- package/dist/Components/Table/Misc/FilterInput.svelte.d.ts +12 -12
- package/dist/Components/Table/Misc/FilterInputProps.d.ts +2 -2
- package/dist/Components/Table/Misc/FilterPanel.svelte +257 -257
- package/dist/Components/Table/Misc/FilterPanelModal.svelte +30 -30
- package/dist/Components/Table/Misc/SidePanel.svelte +35 -35
- package/dist/Components/Table/Misc/TableFooter.svelte +311 -311
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +125 -125
- package/dist/Components/Table/Misc/TableSidebar.svelte +157 -157
- package/dist/Components/Table/Misc/ToolboxPanel.svelte +100 -100
- package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +107 -107
- package/dist/Components/Table/NestedTable.svelte +130 -133
- package/dist/Components/Table/SubApis.svelte.d.ts +1 -5
- package/dist/Components/Table/SubApis.svelte.js +33 -32
- package/dist/Components/Table/Table.svelte +692 -745
- package/dist/Components/Table/TableHelpers.svelte.d.ts +6 -19
- package/dist/Components/Table/TableHelpers.svelte.js +6 -14
- package/dist/Components/Table/Types/Columns/Column.d.ts +2 -2
- package/dist/Components/Table/Types/Columns/DateColumn.d.ts +3 -3
- package/dist/Components/Table/Types/Columns/DateTableCell.d.ts +7 -7
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/AccessorDef.svelte.d.ts +7 -8
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/AccessorDef.svelte.js +4 -5
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/CheckboxDef.svelte.d.ts +11 -14
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/CheckboxDef.svelte.js +3 -4
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/DateInputDef.svelte.d.ts +7 -11
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/DateInputDef.svelte.js +3 -3
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/NumberInputDef.svelte.d.ts +13 -18
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/NumberInputDef.svelte.js +4 -5
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/QueryDef.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/QueryDef.svelte.js +2 -2
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/SelectDef.svelte.d.ts +15 -12
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/SelectDef.svelte.js +4 -5
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/TextInputDef.svelte.d.ts +8 -12
- package/dist/Components/Table/Types/Columns/Definitions/Accessors/TextInputDef.svelte.js +3 -3
- package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.d.ts +6 -6
- package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.js +3 -3
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.d.ts +49 -16
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.js +27 -5
- package/dist/Components/Table/Types/Columns/Definitions/Display/AbstractDisplayDef.svelte.d.ts +7 -7
- package/dist/Components/Table/Types/Columns/Definitions/Display/AbstractDisplayDef.svelte.js +4 -4
- package/dist/Components/Table/Types/Columns/Definitions/Display/BubbleDef.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/Definitions/Display/BubbleDef.svelte.js +2 -2
- package/dist/Components/Table/Types/Columns/Definitions/Display/DisplayDef.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/Definitions/Display/DisplayDef.svelte.js +2 -2
- package/dist/Components/Table/Types/Columns/Definitions/Display/ProgressBarDef.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/Definitions/Display/ProgressBarDef.svelte.js +2 -2
- package/dist/Components/Table/Types/Columns/Definitions/Display/ValidityDef.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/Definitions/Display/ValidityDef.svelte.js +2 -2
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.d.ts +11 -19
- package/dist/Components/Table/Types/Columns/Definitions/Expand/ExpandDef.svelte.js +4 -8
- package/dist/Components/Table/Types/Columns/Definitions/FilterOnly/FilterOnlyDef.svelte.d.ts +6 -7
- package/dist/Components/Table/Types/Columns/Definitions/FilterOnly/FilterOnlyDef.svelte.js +3 -4
- package/dist/Components/Table/Types/Columns/Definitions/RowSelection/RowSelectionDef.svelte.d.ts +9 -9
- package/dist/Components/Table/Types/Columns/Definitions/RowSelection/RowSelectionDef.svelte.js +4 -4
- package/dist/Components/Table/Types/Columns/ExpandTableCell.d.ts +5 -5
- package/dist/Components/Table/Types/Columns/ProgressBarTableCell.d.ts +6 -6
- package/dist/Components/Table/Types/Columns/TableCell.d.ts +7 -6
- package/dist/Components/Table/Types/Context/ClipboardState.svelte.d.ts +98 -0
- package/dist/Components/Table/Types/Context/ClipboardState.svelte.js +290 -0
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.d.ts +17 -45
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.js +17 -45
- package/dist/Components/Table/Types/Context/FilteringState.svelte.d.ts +9 -20
- package/dist/Components/Table/Types/Context/FilteringState.svelte.js +9 -20
- package/dist/Components/Table/Types/Context/FocusState.svelte.d.ts +23 -42
- package/dist/Components/Table/Types/Context/FocusState.svelte.js +32 -59
- package/dist/Components/Table/Types/Context/ITable.d.ts +5 -8
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.d.ts +29 -56
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.js +28 -55
- package/dist/Components/Table/Types/Context/QueryValuesState.svelte.d.ts +50 -0
- package/dist/Components/Table/Types/Context/QueryValuesState.svelte.js +62 -0
- package/dist/Components/Table/Types/Context/SelectionState.svelte.d.ts +17 -28
- package/dist/Components/Table/Types/Context/SelectionState.svelte.js +17 -28
- package/dist/Components/Table/Types/Context/SortingState.svelte.d.ts +15 -29
- package/dist/Components/Table/Types/Context/SortingState.svelte.js +17 -31
- package/dist/Components/Table/Types/Context/TableContext.svelte.d.ts +212 -325
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +292 -706
- package/dist/Components/Table/Types/Context/VirtualisationState.svelte.d.ts +62 -79
- package/dist/Components/Table/Types/Context/VirtualisationState.svelte.js +54 -73
- package/dist/Components/Table/Types/DataRepository/BuiltInRemoteRepository.svelte.d.ts +16 -27
- package/dist/Components/Table/Types/DataRepository/BuiltInRemoteRepository.svelte.js +16 -27
- package/dist/Components/Table/Types/DataRepository/IDataRepository.d.ts +12 -15
- package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.d.ts +15 -30
- package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.js +16 -28
- package/dist/Components/Table/Types/Header.d.ts +4 -4
- package/dist/Components/Table/Types/HeaderGroup.d.ts +5 -5
- package/dist/Components/Table/Types/Public/index.d.ts +2 -4
- package/dist/Components/Table/Types/Public/index.js +2 -4
- package/dist/Components/Table/clipboardEscape.d.ts +32 -0
- package/dist/Components/Table/clipboardEscape.js +45 -0
- package/dist/Components/Table/createTable.svelte.d.ts +8 -18
- package/dist/Components/Table/createTable.svelte.js +19 -47
- 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 +123 -123
- 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/Contexts/ToastContext.svelte.js +3 -4
- package/dist/Helpers/Datamatrix.d.ts +19 -19
- package/dist/Helpers/Datamatrix.js +291 -291
- package/dist/Helpers/Helpers.svelte.d.ts +2 -4
- package/dist/Helpers/Helpers.svelte.js +2 -4
- package/dist/Helpers/dropdownPortal.d.ts +26 -41
- package/dist/Helpers/dropdownPortal.js +62 -116
- package/dist/Types/Examples/ExampleModal.svelte +35 -35
- package/dist/index.d.ts +0 -1
- package/dist/scss/_basics.scss +12 -12
- package/dist/scss/_colours.scss +134 -134
- package/dist/scss/_mixins.scss +3348 -3360
- package/dist/scss/_motion.scss +57 -57
- package/dist/scss/_sizing.scss +85 -85
- package/dist/scss/_transitions.scss +8 -8
- package/package.json +2 -1
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { browser, dev } from '$app/environment';
|
|
2
2
|
import { asyncAll, asyncMap, devCatch, getCanvasContext, isKeyOf, } from '../../../../Helpers/Helpers.svelte.js';
|
|
3
|
+
import { COLUMN_KIND_REGISTRY, resolveDefaultFilter, } from '../../ColumnKindRegistry.js';
|
|
4
|
+
import { ClipboardState } from './ClipboardState.svelte.js';
|
|
3
5
|
import { PreferencesState } from './PreferencesState.svelte.js';
|
|
6
|
+
import { QueryValuesState } from './QueryValuesState.svelte.js';
|
|
4
7
|
import { SelectionState } from './SelectionState.svelte.js';
|
|
5
8
|
import { tick, untrack } from 'svelte';
|
|
6
9
|
import { SvelteMap } from 'svelte/reactivity';
|
|
7
10
|
import { ColumnType } from '../Columns/ColumnType.js';
|
|
8
11
|
import { AccessorDef } from '../Columns/Definitions/Accessors/AccessorDef.svelte.js';
|
|
9
|
-
import { CheckboxDef } from '../Columns/Definitions/Accessors/CheckboxDef.svelte.js';
|
|
10
|
-
import { DateInputDef } from '../Columns/Definitions/Accessors/DateInputDef.svelte.js';
|
|
11
12
|
import { NumberInputDef } from '../Columns/Definitions/Accessors/NumberInputDef.svelte.js';
|
|
12
|
-
import { SelectDef } from '../Columns/Definitions/Accessors/SelectDef.svelte.js';
|
|
13
|
-
import { TextInputDef } from '../Columns/Definitions/Accessors/TextInputDef.svelte.js';
|
|
14
|
-
import { BubbleDef } from '../Columns/Definitions/Display/BubbleDef.svelte.js';
|
|
15
|
-
import { DisplayDef } from '../Columns/Definitions/Display/DisplayDef.svelte.js';
|
|
16
|
-
import { ProgressBarDef } from '../Columns/Definitions/Display/ProgressBarDef.svelte.js';
|
|
17
|
-
import { RowSelectionDef } from '../Columns/Definitions/RowSelection/RowSelectionDef.svelte.js';
|
|
18
13
|
import { SortingState } from './SortingState.svelte.js';
|
|
19
14
|
import { FilteringState } from './FilteringState.svelte.js';
|
|
20
15
|
import { ColumnLayoutState } from './ColumnLayoutState.svelte.js';
|
|
@@ -24,13 +19,6 @@ import { PaginationType } from '../Pagination/PaginationType.js';
|
|
|
24
19
|
import { ToolbarPosition } from '../Toolbar/ToolbarPosition.js';
|
|
25
20
|
const SORTING_ICON_WIDTH = 24;
|
|
26
21
|
const InternalSymbol = Symbol();
|
|
27
|
-
const uncopyableColumns = new Set([
|
|
28
|
-
// RowSelect column is a special case and is handled by tableContext directly
|
|
29
|
-
ColumnType.Expand,
|
|
30
|
-
ColumnType.Actions,
|
|
31
|
-
ColumnType.FilterOnly,
|
|
32
|
-
ColumnType.Custom,
|
|
33
|
-
]);
|
|
34
22
|
/**
|
|
35
23
|
* Default values applied by `TableContext.init` for any `TableInitOptions`
|
|
36
24
|
* field the consumer omits. Frozen so callers (notably `NestedTable`)
|
|
@@ -76,16 +64,12 @@ export class TableContext {
|
|
|
76
64
|
*/
|
|
77
65
|
static init(defaultColumnDefs, tableName, dataRepo, options) {
|
|
78
66
|
const context = new this(InternalSymbol, defaultColumnDefs, tableName, dataRepo, options.allowCopy ?? DEFAULT_TABLE_INIT_OPTIONS.allowCopy, options.enableResize ?? DEFAULT_TABLE_INIT_OPTIONS.enableResize, options.allowColumnReordering ?? DEFAULT_TABLE_INIT_OPTIONS.allowColumnReordering, options.allowQuickFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowQuickFiltering, options.showQuickFilterByDefault ?? DEFAULT_TABLE_INIT_OPTIONS.showQuickFilterByDefault, options.allowAdvancedFiltering ?? DEFAULT_TABLE_INIT_OPTIONS.allowAdvancedFiltering, options.toolbar ?? DEFAULT_TABLE_INIT_OPTIONS.toolbar, options.displayFooter ?? DEFAULT_TABLE_INIT_OPTIONS.displayFooter,
|
|
79
|
-
// Fallback identity extractor when no `selectionExtractor`
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// via the keying cache) and avoids the
|
|
86
|
-
// `tableContext.selectionExtractor is not a function`
|
|
87
|
-
// crash inside `SelectionState.cachedKey` /
|
|
88
|
-
// `TableRow.svelte`'s id-resolution effect.
|
|
67
|
+
// Fallback identity extractor when no `selectionExtractor` is
|
|
68
|
+
// supplied (some consumers build an options object directly
|
|
69
|
+
// without one). Returning the row object preserves identity
|
|
70
|
+
// (cell wrappers compare by reference via the keying cache)
|
|
71
|
+
// and avoids the `selectionExtractor is not a function` crash
|
|
72
|
+
// inside `SelectionState.cachedKey` and `TableRow.svelte`.
|
|
89
73
|
options.selectionExtractor ?? ((row) => row), options.getUserId, options.onEditCell, options.debug ?? DEFAULT_TABLE_INIT_OPTIONS.debug);
|
|
90
74
|
return context;
|
|
91
75
|
}
|
|
@@ -276,22 +260,17 @@ export class TableContext {
|
|
|
276
260
|
if (current !== latest_sortedRowModel) {
|
|
277
261
|
throw new Error(`stale data`);
|
|
278
262
|
}
|
|
279
|
-
// Do NOT throw when `originalIndex` is missing.
|
|
280
|
-
// `originalRowIndices`
|
|
281
|
-
// re-derive asynchronously on
|
|
282
|
-
// changes;
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
// `
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
// snapshot and stopped editable cells from
|
|
291
|
-
// reflecting their post-edit state - the visible
|
|
292
|
-
// symptom on Receipt's SKU cell. Falling back to
|
|
293
|
-
// `unsortedIndex = index` is a fine approximation
|
|
294
|
-
// for the missing entry; the next reactive pass
|
|
263
|
+
// Do NOT throw when `originalIndex` is missing.
|
|
264
|
+
// `originalRowIndices` and the sortedRowModel
|
|
265
|
+
// rebuild re-derive asynchronously on
|
|
266
|
+
// `dataRepo.data` changes; on a row addition the
|
|
267
|
+
// sortedRowModel can win the race and run against
|
|
268
|
+
// a still-stale `ori` map. Throwing would reject
|
|
269
|
+
// the whole `Promise.all` and pin
|
|
270
|
+
// `_sortedRowModel` to the pre-edit snapshot, so
|
|
271
|
+
// editable cells would not reflect post-edit
|
|
272
|
+
// state. Falling back to `unsortedIndex = index`
|
|
273
|
+
// is a fine approximation; the next reactive pass
|
|
295
274
|
// (after `originalRowIndices` catches up) refines
|
|
296
275
|
// it.
|
|
297
276
|
return this.createRow(item, index, unsortedIndex);
|
|
@@ -436,10 +415,8 @@ export class TableContext {
|
|
|
436
415
|
this._paginationRepo = v;
|
|
437
416
|
}
|
|
438
417
|
/**
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
* owns the `allowQuickFiltering` gate so the setter logic stays
|
|
442
|
-
* identical to the pre-extraction implementation.
|
|
418
|
+
* Delegates to `_filtering.showQuickFiltering`. The sub-context owns
|
|
419
|
+
* the `allowQuickFiltering` gate inside the setter.
|
|
443
420
|
*/
|
|
444
421
|
get showQuickFiltering() {
|
|
445
422
|
return this._filtering.showQuickFiltering;
|
|
@@ -455,19 +432,15 @@ export class TableContext {
|
|
|
455
432
|
this._dataRepo = v;
|
|
456
433
|
}
|
|
457
434
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* `_filtering.setRemoteFilters` during column-def setup to write the
|
|
461
|
-
* caller-supplied value.
|
|
435
|
+
* Delegates to `_filtering.remoteFilters`. The write path is
|
|
436
|
+
* `_filtering.setRemoteFilters`, called during column-def setup.
|
|
462
437
|
*/
|
|
463
438
|
get remoteFilters() {
|
|
464
439
|
return this._filtering.remoteFilters;
|
|
465
440
|
}
|
|
466
441
|
/**
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
* preserves the idempotency short-circuit (re-assigning the same
|
|
470
|
-
* value is a no-op).
|
|
442
|
+
* Delegates to `_filtering.showSelectedOnly`. Re-assigning the same
|
|
443
|
+
* value is a no-op (idempotency short-circuit in the sub-context).
|
|
471
444
|
*/
|
|
472
445
|
get showSelectedOnly() {
|
|
473
446
|
return this._filtering.showSelectedOnly;
|
|
@@ -476,11 +449,8 @@ export class TableContext {
|
|
|
476
449
|
this._filtering.showSelectedOnly = v;
|
|
477
450
|
}
|
|
478
451
|
/**
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
* `paginationRepo` via the thunk so the source of truth stays
|
|
482
|
-
* with the data repository; consumers that bind these getters
|
|
483
|
-
* (notably `setupDefaultColumnDefs`) need no migration.
|
|
452
|
+
* Per-type `FilterFn` getters. Delegate to `_filtering`, which reads
|
|
453
|
+
* the source-of-truth from `paginationRepo` via thunk.
|
|
484
454
|
*/
|
|
485
455
|
get dateFilter() {
|
|
486
456
|
return this._filtering.dateFilter;
|
|
@@ -511,12 +481,7 @@ export class TableContext {
|
|
|
511
481
|
set dragTarget(v) {
|
|
512
482
|
this._dragTarget = v;
|
|
513
483
|
}
|
|
514
|
-
/**
|
|
515
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
516
|
-
* actual `$state` slot lives on `_columnLayout`; this getter / setter
|
|
517
|
-
* pair forwards reads and writes so existing consumers need no
|
|
518
|
-
* migration. See `_columnLayout` below for the sub-context.
|
|
519
|
-
*/
|
|
484
|
+
/** Delegates to `_columnLayout.columnDefs`. */
|
|
520
485
|
get columnDefs() {
|
|
521
486
|
return this._columnLayout.columnDefs;
|
|
522
487
|
}
|
|
@@ -524,21 +489,15 @@ export class TableContext {
|
|
|
524
489
|
this._columnLayout.columnDefs = v;
|
|
525
490
|
}
|
|
526
491
|
/**
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
* write path goes through `saveColumnPreset` (which also persists
|
|
531
|
-
* the list to localStorage); internal call sites that need to
|
|
492
|
+
* Delegates to `_preferences._columnPresets`. The setter is private
|
|
493
|
+
* because the public write path is `saveColumnPreset` (which also
|
|
494
|
+
* persists to localStorage); internal call sites that need to
|
|
532
495
|
* mutate the list directly call `_preferences.setPresets(...)`.
|
|
533
496
|
*/
|
|
534
497
|
get columnPresets() {
|
|
535
498
|
return this._preferences.columnPresets;
|
|
536
499
|
}
|
|
537
|
-
/**
|
|
538
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
539
|
-
* actual `$state` slot lives on `_preferences._selectedPreset`
|
|
540
|
-
* (Phase 6.4). Reads / writes through to the sub-context.
|
|
541
|
-
*/
|
|
500
|
+
/** Delegates to `_preferences._selectedPreset`. */
|
|
542
501
|
get selectedPreset() {
|
|
543
502
|
return this._preferences.selectedPreset;
|
|
544
503
|
}
|
|
@@ -546,33 +505,22 @@ export class TableContext {
|
|
|
546
505
|
this._preferences.selectedPreset = v;
|
|
547
506
|
}
|
|
548
507
|
/**
|
|
549
|
-
*
|
|
550
|
-
* `$
|
|
551
|
-
* Populated by the parent's focus-derived `$effect` through
|
|
508
|
+
* Delegates to `_focus._focusedRowIndices`. Populated by the
|
|
509
|
+
* focus-derived `$effect` in the constructor through
|
|
552
510
|
* `_focus.setFocusedDerived(rows, cols)`.
|
|
553
511
|
*/
|
|
554
512
|
get focusedRowIndices() {
|
|
555
513
|
return this._focus.focusedRowIndices;
|
|
556
514
|
}
|
|
557
|
-
/**
|
|
558
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
559
|
-
* actual `$state` slot lives on `_selection._highlightedItems`
|
|
560
|
-
* (Phase 6.5).
|
|
561
|
-
*/
|
|
515
|
+
/** Delegates to `_selection._highlightedItems`. */
|
|
562
516
|
get highlightedItems() {
|
|
563
517
|
return this._selection.highlightedItems;
|
|
564
518
|
}
|
|
565
|
-
/**
|
|
566
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
567
|
-
* `$state` slot lives on `_focus._focusedColumnIds` (Phase 6.6).
|
|
568
|
-
*/
|
|
519
|
+
/** Delegates to `_focus._focusedColumnIds`. */
|
|
569
520
|
get focusedColumnIds() {
|
|
570
521
|
return this._focus.focusedColumnIds;
|
|
571
522
|
}
|
|
572
|
-
/**
|
|
573
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
574
|
-
* `$state` slot lives on `_focus._isMousingDown` (Phase 6.6).
|
|
575
|
-
*/
|
|
523
|
+
/** Delegates to `_focus._isMousingDown`. */
|
|
576
524
|
get isMousingDown() {
|
|
577
525
|
return this._focus.isMousingDown;
|
|
578
526
|
}
|
|
@@ -580,30 +528,22 @@ export class TableContext {
|
|
|
580
528
|
this._focus.isMousingDown = v;
|
|
581
529
|
}
|
|
582
530
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
* `endFocus` / `setFocusEnd` / `startFocus` (all delegated below).
|
|
531
|
+
* Delegates to `_focus._focusStart`. This surface is read-only; the
|
|
532
|
+
* write path is `moveFocus` / `unfocus` / `tabForward` /
|
|
533
|
+
* `tabBackward` / `endFocus` / `setFocusEnd` / `startFocus` (all
|
|
534
|
+
* delegated below).
|
|
588
535
|
*/
|
|
589
536
|
get focusStart() {
|
|
590
537
|
return this._focus.focusStart;
|
|
591
538
|
}
|
|
592
|
-
/**
|
|
593
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
594
|
-
* `$state` slot lives on `_focus._focusStartIsBeingEdited`
|
|
595
|
-
* (Phase 6.6).
|
|
596
|
-
*/
|
|
539
|
+
/** Delegates to `_focus._focusStartIsBeingEdited`. */
|
|
597
540
|
get focusStartIsBeingEdited() {
|
|
598
541
|
return this._focus.focusStartIsBeingEdited;
|
|
599
542
|
}
|
|
600
543
|
set focusStartIsBeingEdited(v) {
|
|
601
544
|
this._focus.focusStartIsBeingEdited = v;
|
|
602
545
|
}
|
|
603
|
-
/**
|
|
604
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
605
|
-
* `$state` slot lives on `_focus._focusEnd` (Phase 6.6).
|
|
606
|
-
*/
|
|
546
|
+
/** Delegates to `_focus._focusEnd`. */
|
|
607
547
|
get focusEnd() {
|
|
608
548
|
return this._focus.focusEnd;
|
|
609
549
|
}
|
|
@@ -638,23 +578,48 @@ export class TableContext {
|
|
|
638
578
|
set alternateRowColours(v) {
|
|
639
579
|
this._alternateRowColours = v;
|
|
640
580
|
}
|
|
641
|
-
|
|
581
|
+
/**
|
|
582
|
+
* Clipboard sub-context owning the two user-tunable preference flags
|
|
583
|
+
* (`copyWithHeaders`, `commaSeparatedCopy`) plus the
|
|
584
|
+
* `copyDataToClipboard` / `copyHighlightedRowsToClipboard` writers and
|
|
585
|
+
* their cell-serialisation internals. Dependency thunks below close
|
|
586
|
+
* over the parent reads it needs (column defs, sorted data, focus
|
|
587
|
+
* coordinates, etc.); the parent never sees the clipboard internals.
|
|
588
|
+
*/
|
|
589
|
+
_clipboard = new ClipboardState({
|
|
590
|
+
getColumnDefs: () => this.columnDefs,
|
|
591
|
+
getColumnVisibility: () => this.columnVisibility,
|
|
592
|
+
getHighlightedItems: () => this.highlightedItems,
|
|
593
|
+
getSelectedItems: () => this.selectedItems,
|
|
594
|
+
getSortedData: () => this.sortedData,
|
|
595
|
+
getCurrentPageData: () => this.currentPageData,
|
|
596
|
+
getPaginationRowModel: () => this.paginationRowModel,
|
|
597
|
+
getVisualColumns: () => this._visualColumns,
|
|
598
|
+
getFocusStart: () => this.focusStart,
|
|
599
|
+
getFocusEnd: () => this.focusEnd,
|
|
600
|
+
cachedKey: (item) => this._cachedKey(item),
|
|
601
|
+
columnVisualIndex: (id) => this.columnVisualIndex(id),
|
|
602
|
+
getAllowCopy: () => this.allowCopy,
|
|
603
|
+
persistSettings: () => {
|
|
604
|
+
this._updateLocalStorageSettings();
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
/** Delegates to `_clipboard.copyWithHeaders`. */
|
|
642
608
|
get copyWithHeaders() {
|
|
643
|
-
return this.
|
|
609
|
+
return this._clipboard.copyWithHeaders;
|
|
644
610
|
}
|
|
645
611
|
set copyWithHeaders(v) {
|
|
646
|
-
this.
|
|
612
|
+
this._clipboard.copyWithHeaders = v;
|
|
647
613
|
}
|
|
648
|
-
|
|
614
|
+
/** Delegates to `_clipboard.commaSeparatedCopy`. */
|
|
649
615
|
get commaSeparatedCopy() {
|
|
650
|
-
return this.
|
|
616
|
+
return this._clipboard.commaSeparatedCopy;
|
|
651
617
|
}
|
|
652
618
|
set commaSeparatedCopy(v) {
|
|
653
|
-
this.
|
|
619
|
+
this._clipboard.commaSeparatedCopy = v;
|
|
654
620
|
}
|
|
655
621
|
/**
|
|
656
|
-
*
|
|
657
|
-
* through to `_columnLayout.columnSizing`. Per-key mutations (e.g.
|
|
622
|
+
* Delegates to `_columnLayout.columnSizing`. Per-key mutations (e.g.
|
|
658
623
|
* `this.columnSizing[id] = w` in `autoResize`) work because the
|
|
659
624
|
* underlying `$state` slot is a Svelte proxy.
|
|
660
625
|
*/
|
|
@@ -665,8 +630,7 @@ export class TableContext {
|
|
|
665
630
|
this._columnLayout.columnSizing = v;
|
|
666
631
|
}
|
|
667
632
|
/**
|
|
668
|
-
*
|
|
669
|
-
* through to `_columnLayout.columnPinning`. The `setColumnPinning`
|
|
633
|
+
* Delegates to `_columnLayout.columnPinning`. The `setColumnPinning`
|
|
670
634
|
* updater below honours the `allowColumnReordering` master gate; the
|
|
671
635
|
* direct setter does not, by design (used for preset switches and
|
|
672
636
|
* the init flow where the gate has already been checked).
|
|
@@ -678,8 +642,7 @@ export class TableContext {
|
|
|
678
642
|
this._columnLayout.columnPinning = v;
|
|
679
643
|
}
|
|
680
644
|
/**
|
|
681
|
-
*
|
|
682
|
-
* through to `_columnLayout.columnVisibility`. Tri-state semantics
|
|
645
|
+
* Delegates to `_columnLayout.columnVisibility`. Tri-state semantics
|
|
683
646
|
* (`true` / `false` / `undefined`) are preserved.
|
|
684
647
|
*/
|
|
685
648
|
get columnVisibility() {
|
|
@@ -693,13 +656,12 @@ export class TableContext {
|
|
|
693
656
|
* `col.display({ modal })` modal is currently open, or `null` when no
|
|
694
657
|
* modal is open.
|
|
695
658
|
*
|
|
696
|
-
* Keyed on the **row object reference
|
|
697
|
-
* open-modal state is stable across pagination, sort, and filter
|
|
698
|
-
* changes
|
|
699
|
-
* openModalCell.row`. Visible-index
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
* change.
|
|
659
|
+
* Keyed on the **row object reference** (NOT on visible index) so
|
|
660
|
+
* the open-modal state is stable across pagination, sort, and filter
|
|
661
|
+
* changes; the cell renderer matches via
|
|
662
|
+
* `cell.row.original === openModalCell.row`. Visible-index keying
|
|
663
|
+
* would silently re-target the modal to whichever row happened to
|
|
664
|
+
* occupy the same index after a page change.
|
|
703
665
|
*/
|
|
704
666
|
_openModalCell = $state(null);
|
|
705
667
|
get openModalCell() {
|
|
@@ -708,10 +670,9 @@ export class TableContext {
|
|
|
708
670
|
set openModalCell(v) {
|
|
709
671
|
this._openModalCell = v;
|
|
710
672
|
}
|
|
711
|
-
// Per-table identifier of the ActionsCell that currently has its popup
|
|
712
|
-
// Lives on the context
|
|
713
|
-
// same page do not share open-popup state
|
|
714
|
-
// poisoning).
|
|
673
|
+
// Per-table identifier of the ActionsCell that currently has its popup
|
|
674
|
+
// open. Lives on the context (NOT at module scope) so multiple tables
|
|
675
|
+
// on the same page do not share open-popup state.
|
|
715
676
|
_shownActionsPopup = $state();
|
|
716
677
|
get shownActionsPopup() {
|
|
717
678
|
return this._shownActionsPopup;
|
|
@@ -720,36 +681,29 @@ export class TableContext {
|
|
|
720
681
|
this._shownActionsPopup = v;
|
|
721
682
|
}
|
|
722
683
|
/**
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
* `_selection.allSelectedInCurrentPage` (Phase 6.5).
|
|
684
|
+
* Delegates to `_selection.allSelectedInCurrentPage` (the `$derived`
|
|
685
|
+
* chain and the async-result cache live there).
|
|
726
686
|
*/
|
|
727
687
|
get allSelectedInCurrentPage() {
|
|
728
688
|
return this._selection.allSelectedInCurrentPage;
|
|
729
689
|
}
|
|
730
690
|
/**
|
|
731
|
-
*
|
|
732
|
-
*
|
|
733
|
-
*
|
|
734
|
-
*
|
|
735
|
-
* directly.
|
|
691
|
+
* Delegates to `_selection.allHighlighted`. The value is published
|
|
692
|
+
* by the `_allHighlightedEffect` below (which lives on this class
|
|
693
|
+
* because it reads `paginationRepo.pageStartIndex` /
|
|
694
|
+
* `pageEndIndexExclusive` directly).
|
|
736
695
|
*/
|
|
737
696
|
get allHighlighted() {
|
|
738
697
|
return this._selection.allHighlighted;
|
|
739
698
|
}
|
|
740
|
-
/**
|
|
741
|
-
* Delegating getter preserved for backwards compatibility. The
|
|
742
|
-
* `$derived` lives on `_selection.hasHighlightedItems` (Phase 6.5).
|
|
743
|
-
*/
|
|
699
|
+
/** Delegates to `_selection.hasHighlightedItems`. */
|
|
744
700
|
get hasHighlightedItems() {
|
|
745
701
|
return this._selection.hasHighlightedItems;
|
|
746
702
|
}
|
|
747
703
|
/**
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
* `toggleSelected` / `setSelected` / `resetSelectedItems` /
|
|
752
|
-
* `setSelectionMap` below.
|
|
704
|
+
* Delegates to `_selection.selectedItems`. Read-only at this surface;
|
|
705
|
+
* the public writers are `toggleSelected` / `setSelected` /
|
|
706
|
+
* `resetSelectedItems` / `setSelectionMap` below.
|
|
753
707
|
*/
|
|
754
708
|
get selectedItems() {
|
|
755
709
|
return this._selection.selectedItems;
|
|
@@ -768,24 +722,20 @@ export class TableContext {
|
|
|
768
722
|
this._hasInvalidSelectedItems = v;
|
|
769
723
|
}
|
|
770
724
|
/**
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
* (
|
|
774
|
-
*
|
|
775
|
-
* `private` field) so the dependent sub-contexts (`SortingState`)
|
|
776
|
-
* and helpers (`generateTableOptions`) can read it through the
|
|
777
|
-
* legacy surface without piercing the sub-context boundary.
|
|
725
|
+
* Delegates to `_columnLayout.columnDefsById`. `public get` (rather
|
|
726
|
+
* than a private field) so dependent sub-contexts (`SortingState`)
|
|
727
|
+
* and helpers (`generateTableOptions`) can read it without piercing
|
|
728
|
+
* the sub-context boundary.
|
|
778
729
|
*/
|
|
779
730
|
get columnDefsById() {
|
|
780
731
|
return this._columnLayout.columnDefsById;
|
|
781
732
|
}
|
|
782
733
|
/**
|
|
783
|
-
*
|
|
784
|
-
* `
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
788
|
-
* helper, and the `setNewPinningState` helper.
|
|
734
|
+
* Column-layout sub-context: `columnDefs`, `columnSizing`,
|
|
735
|
+
* `columnPinning`, `columnVisibility`, the `columnDefsById`
|
|
736
|
+
* reverse-lookup map, the `visualColumns` cached array (and paired
|
|
737
|
+
* `visualColumnIndexById` O(1) lookup), the gated `setColumnPinning`
|
|
738
|
+
* updater, `updateDefsBasedOnPinning`, and `setNewPinningState`.
|
|
789
739
|
*
|
|
790
740
|
* Dependencies are passed as thunks so the sub-context never holds
|
|
791
741
|
* a reference to the parent. The `allowColumnReordering` thunk
|
|
@@ -797,16 +747,15 @@ export class TableContext {
|
|
|
797
747
|
getDebug: () => this.debug,
|
|
798
748
|
});
|
|
799
749
|
/**
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* `
|
|
804
|
-
*
|
|
750
|
+
* Filtering sub-context: per-row filter result
|
|
751
|
+
* (`filteredIndices`), the `filteredData` derived chain, user-facing
|
|
752
|
+
* toggles (`showQuickFiltering`, `showSelectedOnly`), the per-type
|
|
753
|
+
* `FilterFn` relays, the remote-filter slot, and the `updateFilters`
|
|
754
|
+
* `OnChangeFn` slot.
|
|
805
755
|
*
|
|
806
|
-
* Dependencies are
|
|
807
|
-
*
|
|
808
|
-
* `
|
|
809
|
-
* `this.createRow` (parent concern) - the effect publishes its
|
|
756
|
+
* Dependencies are thunks so the sub-context never holds a parent
|
|
757
|
+
* reference. The population effect for `_filteredIndices` lives on
|
|
758
|
+
* `TableContext` because it calls `this.createRow`; it publishes its
|
|
810
759
|
* result via `this._filtering.setFilteredIndices`.
|
|
811
760
|
*/
|
|
812
761
|
_filtering = new FilteringState({
|
|
@@ -822,33 +771,40 @@ export class TableContext {
|
|
|
822
771
|
getDebug: () => this.debug,
|
|
823
772
|
});
|
|
824
773
|
/**
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
* `this.createRow` and must stay where `createRow` lives).
|
|
774
|
+
* Delegates to `_filtering.filteredIndices`. Populated by the per-row
|
|
775
|
+
* filter `$effect` in this class (which calls `this.createRow` and
|
|
776
|
+
* must stay where `createRow` lives).
|
|
829
777
|
*/
|
|
830
778
|
get filteredIndices() {
|
|
831
779
|
return this._filtering.filteredIndices;
|
|
832
780
|
}
|
|
833
781
|
/**
|
|
834
|
-
*
|
|
835
|
-
* through to `_filtering.filteredData`, which owns the local /
|
|
782
|
+
* Delegates to `_filtering.filteredData`, which owns the local /
|
|
836
783
|
* remote / show-selected-only branching.
|
|
837
784
|
*/
|
|
838
785
|
get filteredData() {
|
|
839
786
|
return this._filtering.filteredData;
|
|
840
787
|
}
|
|
841
788
|
/**
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
* `
|
|
846
|
-
|
|
847
|
-
|
|
789
|
+
* Typeahead-echo cache for QuerySelect-backed filter inputs. Keyed by
|
|
790
|
+
* `ColumnDef` so reads and writes cannot diverge on the key (a recurring
|
|
791
|
+
* regression from the legacy `Map<string, unknown>` shape). See
|
|
792
|
+
* `QueryValuesState` for the rationale.
|
|
793
|
+
*/
|
|
794
|
+
_queryValues = new QueryValuesState();
|
|
795
|
+
/** Public alias for `_queryValues`, used by filter input components. */
|
|
796
|
+
get queryValues() {
|
|
797
|
+
return this._queryValues;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Sort sub-context: owns the sort-related derived chain and the
|
|
801
|
+
* per-`ColumnDef` comparator dispatch. Dependency thunks close over
|
|
802
|
+
* `this.columnDefsById` / `this.filteredData` / `this.dataRepo` /
|
|
803
|
+
* `this.paginationRepo` / `this.debug`, so the sub-context never
|
|
804
|
+
* holds a parent reference and reactivity stays in `$derived`.
|
|
848
805
|
*
|
|
849
|
-
*
|
|
850
|
-
*
|
|
851
|
-
* pre-decomposition surface for backwards compatibility.
|
|
806
|
+
* Public field so consumers can read sorting state directly; the
|
|
807
|
+
* `sortedData` getter below preserves the legacy surface.
|
|
852
808
|
*/
|
|
853
809
|
_sorting = new SortingState({
|
|
854
810
|
getColumnDefsById: () => this.columnDefsById,
|
|
@@ -859,28 +815,27 @@ export class TableContext {
|
|
|
859
815
|
getDebug: () => this.debug,
|
|
860
816
|
});
|
|
861
817
|
/**
|
|
862
|
-
*
|
|
863
|
-
* concern previously held directly on `TableContext`:
|
|
818
|
+
* Persistence / preferences sub-context:
|
|
864
819
|
*
|
|
865
|
-
* -
|
|
820
|
+
* - saved column-presets list and currently-selected preset
|
|
866
821
|
* (`columnPresets`, `selectedPreset`);
|
|
867
|
-
* -
|
|
822
|
+
* - `userIdSegment` `$derived` (namespaces every
|
|
868
823
|
* `scoria-table:<user>:<tableName>:<suffix>` storage key);
|
|
869
|
-
* -
|
|
870
|
-
*
|
|
871
|
-
* -
|
|
872
|
-
*
|
|
873
|
-
* -
|
|
874
|
-
*
|
|
875
|
-
* -
|
|
876
|
-
*
|
|
824
|
+
* - `saveColumnPreset` / `setSelectedPreset` writers (apply layout
|
|
825
|
+
* AND persist);
|
|
826
|
+
* - `loadPresets` / `loadSelectedPresetName` / `loadSavedSettings`
|
|
827
|
+
* boot-time hydration helpers;
|
|
828
|
+
* - `persistSettings` writer used by the in-app settings toggles
|
|
829
|
+
* (`setIsCompact`, `setAlternateRowColours`, etc.);
|
|
830
|
+
* - schema-validation typeguards (exported alongside the sub-context
|
|
831
|
+
* for unit testing).
|
|
877
832
|
*
|
|
878
833
|
* The settings fields themselves (`isCompact`, `singleClickEditing`,
|
|
879
834
|
* `alternateRowColours`, etc.) stay on `TableContext` because each
|
|
880
|
-
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
* `
|
|
835
|
+
* drives reactive UI; only the localStorage round-trip lives here.
|
|
836
|
+
* Delegating getters / setters / methods on `TableContext` cover the
|
|
837
|
+
* full surface (`columnPresets`, `selectedPreset`, `saveColumnPreset`,
|
|
838
|
+
* `setSelectedPreset`, `setIsCompact`, etc.).
|
|
884
839
|
*/
|
|
885
840
|
_preferences = new PreferencesState({
|
|
886
841
|
getTableName: () => this.tableName,
|
|
@@ -904,31 +859,27 @@ export class TableContext {
|
|
|
904
859
|
getDebug: () => this.debug,
|
|
905
860
|
});
|
|
906
861
|
/**
|
|
907
|
-
*
|
|
908
|
-
* key-cache concern previously held directly on `TableContext`:
|
|
862
|
+
* Selection + highlighting + key-cache sub-context:
|
|
909
863
|
*
|
|
910
864
|
* - `selectedItems` / `invalidValues` / `highlightedItems`
|
|
911
865
|
* (`SvelteMap` slots, keyed by `selectionExtractor(item)`);
|
|
912
|
-
* -
|
|
913
|
-
*
|
|
914
|
-
* -
|
|
866
|
+
* - `WeakMap<T, RowIdType>` key-cache memoising the extractor result
|
|
867
|
+
* per row reference;
|
|
868
|
+
* - pending-flush buffer and its debounced microtask
|
|
915
869
|
* (`_pendingSelectionChanges` -> `tick().then(flush)`);
|
|
916
|
-
* -
|
|
917
|
-
*
|
|
870
|
+
* - `allSelectedInCurrentPage` `$derived` (with the async-result
|
|
871
|
+
* cache for promise-returning `selectionExtractor` /
|
|
918
872
|
* `RowSelectionDef.isSelectable`);
|
|
919
|
-
* -
|
|
873
|
+
* - `selectAllInCurrentPage` / `updateSelectedItems` /
|
|
920
874
|
* `onHighlightAll` flows;
|
|
921
|
-
* -
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
* class.
|
|
875
|
+
* - `handleItemMutation` split that powers the parent's `onEditCell`:
|
|
876
|
+
* the sub-context owns the key-cache delete + selection rebind; the
|
|
877
|
+
* user-supplied callback stays on this class.
|
|
925
878
|
*
|
|
926
|
-
* Dependencies are
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
* through `_selection.setAllHighlighted(...)` and
|
|
931
|
-
* `_selection.updateSelectedItems()`.
|
|
879
|
+
* Dependencies are thunks so the sub-context never holds a parent
|
|
880
|
+
* reference. The two `$effect`s that read `paginationRepo` directly
|
|
881
|
+
* stay on `TableContext` and publish via `_selection.setAllHighlighted`
|
|
882
|
+
* and `_selection.updateSelectedItems`.
|
|
932
883
|
*/
|
|
933
884
|
_selection = new SelectionState({
|
|
934
885
|
getSortedData: () => this.sortedData,
|
|
@@ -941,8 +892,7 @@ export class TableContext {
|
|
|
941
892
|
getDebug: () => this.debug,
|
|
942
893
|
});
|
|
943
894
|
/**
|
|
944
|
-
*
|
|
945
|
-
* concern previously held directly on `TableContext`:
|
|
895
|
+
* Focus + keyboard-navigation sub-context:
|
|
946
896
|
*
|
|
947
897
|
* - `focusStart` / `focusEnd` / `focusStartIsBeingEdited` /
|
|
948
898
|
* `isMousingDown` (the `$state` slots that define the focused
|
|
@@ -972,9 +922,8 @@ export class TableContext {
|
|
|
972
922
|
* because it reads `paginationRowModel` + `_visualColumns` directly;
|
|
973
923
|
* it calls `_focus.setFocusedDerived(rows, cols)` to publish.
|
|
974
924
|
*
|
|
975
|
-
*
|
|
976
|
-
*
|
|
977
|
-
* `FocusState` for the deferral rationale.
|
|
925
|
+
* Per-cell `TableFocusDetails` reuse cache is deferred; see the
|
|
926
|
+
* class-level JSDoc on `FocusState` for the rationale.
|
|
978
927
|
*/
|
|
979
928
|
_focus = new FocusState({
|
|
980
929
|
getAllowCopy: () => this.allowCopy,
|
|
@@ -996,26 +945,24 @@ export class TableContext {
|
|
|
996
945
|
this.tabBackward();
|
|
997
946
|
},
|
|
998
947
|
getDebug: () => this.debug,
|
|
999
|
-
//
|
|
1000
|
-
//
|
|
1001
|
-
//
|
|
1002
|
-
// at construction time.
|
|
948
|
+
// `getFocusDetailsFor` needs the parent `TableContext` to
|
|
949
|
+
// construct `TableFocusDetails` on cache miss. Pass via a thunk
|
|
950
|
+
// so the sub-context never closes over `this` at construction.
|
|
1003
951
|
getTableContextRef: () => this,
|
|
1004
952
|
});
|
|
1005
953
|
/**
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1008
|
-
* `TableBody.svelte` renders.
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
* the next paint.
|
|
954
|
+
* Row-virtualisation sub-context. Owns the visible-row window plus
|
|
955
|
+
* the top / bottom spacer-height derived chain that
|
|
956
|
+
* `TableBody.svelte` renders. Below the 100-row threshold every row
|
|
957
|
+
* is rendered directly; above it, overscan rows above and below the
|
|
958
|
+
* viewport stay rendered so a fast wheel flick does not surface a
|
|
959
|
+
* blank band.
|
|
1013
960
|
*
|
|
1014
|
-
* Dependencies are thunks
|
|
1015
|
-
* `paginationRowModel.rows`
|
|
1016
|
-
* observed height from the
|
|
1017
|
-
*
|
|
1018
|
-
*
|
|
961
|
+
* Dependencies are thunks: `getRows` reads
|
|
962
|
+
* `paginationRowModel.rows`, `getRowHeight` returns the max-side
|
|
963
|
+
* observed height from the row-height pool (currently a no-op
|
|
964
|
+
* pending re-introduction), and `getEstimatedRowHeight` returns the
|
|
965
|
+
* per-table-density estimate.
|
|
1019
966
|
*/
|
|
1020
967
|
/**
|
|
1021
968
|
* Rendered widths of header cells, keyed by columnId. TableHead
|
|
@@ -1043,12 +990,8 @@ export class TableContext {
|
|
|
1043
990
|
getEstimatedRowHeight: () => (this.isCompact ? 28 : 48),
|
|
1044
991
|
});
|
|
1045
992
|
/**
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
* optimisation and the `AbortController` short-circuit. Consumers
|
|
1049
|
-
* inside `src/lib` already point at `tableContext.sortedData`; the
|
|
1050
|
-
* delegation will be removed once Phase 6 v-next migrates every
|
|
1051
|
-
* reader to `tableContext._sorting.sortedData` directly.
|
|
993
|
+
* Delegates to `_sorting.sortedData`, which owns the comparator-hoist
|
|
994
|
+
* optimisation and the `AbortController` short-circuit.
|
|
1052
995
|
*/
|
|
1053
996
|
get sortedData() {
|
|
1054
997
|
return this._sorting.sortedData;
|
|
@@ -1233,26 +1176,23 @@ export class TableContext {
|
|
|
1233
1176
|
// #endregion
|
|
1234
1177
|
// #region public methods
|
|
1235
1178
|
/**
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
* `originalRowIndices` / `sortedRowModel` / `onHighlightAll` see
|
|
1241
|
-
* no behavioural change.
|
|
1179
|
+
* Forwards to `_selection.cachedKey(item)` (the key-extraction cache
|
|
1180
|
+
* lives there). Used by `getHighlightedRowData` /
|
|
1181
|
+
* `getFocusElementData` / `originalRowIndices` / `sortedRowModel` /
|
|
1182
|
+
* `onHighlightAll`.
|
|
1242
1183
|
*/
|
|
1243
1184
|
_cachedKey(item) {
|
|
1244
1185
|
return this._selection.cachedKey(item);
|
|
1245
1186
|
}
|
|
1246
|
-
/**
|
|
1247
|
-
* implementation lives on `_selection.selectionContains` (Phase 6.5). */
|
|
1187
|
+
/** Delegates to `_selection.selectionContains`. */
|
|
1248
1188
|
selectionContains = (item) => {
|
|
1249
1189
|
return this._selection.selectionContains(item);
|
|
1250
1190
|
};
|
|
1251
|
-
/**
|
|
1191
|
+
/** Delegates to `_selection.addInvalidValue`. */
|
|
1252
1192
|
addInvalidValue = (item) => {
|
|
1253
1193
|
return this._selection.addInvalidValue(item);
|
|
1254
1194
|
};
|
|
1255
|
-
/**
|
|
1195
|
+
/** Delegates to `_selection.removeInvalidValue`. */
|
|
1256
1196
|
removeInvalidValue = (item) => {
|
|
1257
1197
|
return this._selection.removeInvalidValue(item);
|
|
1258
1198
|
};
|
|
@@ -1267,39 +1207,39 @@ export class TableContext {
|
|
|
1267
1207
|
setOpenModalCell = (cell) => {
|
|
1268
1208
|
this.openModalCell = cell ? { row: cell.row, columnId: cell.columnId } : null;
|
|
1269
1209
|
};
|
|
1270
|
-
/**
|
|
1210
|
+
/** Delegates to `_focus`. */
|
|
1271
1211
|
toggleHighlightedRow = (item) => {
|
|
1272
1212
|
return this._selection.toggleHighlightedRow(item);
|
|
1273
1213
|
};
|
|
1274
|
-
/**
|
|
1214
|
+
/** Delegates to `_focus`. */
|
|
1275
1215
|
resetHighlightedRows = () => {
|
|
1276
1216
|
this._selection.resetHighlightedRows();
|
|
1277
1217
|
};
|
|
1278
|
-
/**
|
|
1218
|
+
/** Delegates to `_focus`. */
|
|
1279
1219
|
toggleSelected = (item) => {
|
|
1280
1220
|
return this._selection.toggleSelected(item);
|
|
1281
1221
|
};
|
|
1282
|
-
/**
|
|
1222
|
+
/** Delegates to `_focus`. */
|
|
1283
1223
|
setSelected = (item, selected) => {
|
|
1284
1224
|
return this._selection.setSelected(item, selected);
|
|
1285
1225
|
};
|
|
1286
|
-
/**
|
|
1226
|
+
/** Delegates to `_focus`. */
|
|
1287
1227
|
setSelectionMap = (set) => {
|
|
1288
1228
|
this._selection.setSelectionMap(set);
|
|
1289
1229
|
};
|
|
1290
|
-
/**
|
|
1230
|
+
/** Delegates to `_focus`. */
|
|
1291
1231
|
updateSelectedItems = async () => {
|
|
1292
1232
|
await this._selection.updateSelectedItems();
|
|
1293
1233
|
};
|
|
1294
|
-
/**
|
|
1234
|
+
/** Delegates to `_focus`. */
|
|
1295
1235
|
resetSelectedItems = () => {
|
|
1296
1236
|
this._selection.resetSelectedItems();
|
|
1297
1237
|
};
|
|
1298
|
-
/**
|
|
1238
|
+
/** Delegates to `_focus`. */
|
|
1299
1239
|
selectAllInCurrentPage = async () => {
|
|
1300
1240
|
await this._selection.selectAllInCurrentPage();
|
|
1301
1241
|
};
|
|
1302
|
-
/**
|
|
1242
|
+
/** Delegates to `_focus`. */
|
|
1303
1243
|
onHighlightAll = () => {
|
|
1304
1244
|
return this._selection.onHighlightAll();
|
|
1305
1245
|
};
|
|
@@ -1317,11 +1257,10 @@ export class TableContext {
|
|
|
1317
1257
|
});
|
|
1318
1258
|
};
|
|
1319
1259
|
/**
|
|
1320
|
-
*
|
|
1321
|
-
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1324
|
-
* arrow-key / Home / End / Ctrl+A / Ctrl+C path asynchronously.
|
|
1260
|
+
* Delegates to `_focus.handleTdKeydown`. Bound to the root
|
|
1261
|
+
* `<table>` container's `onkeydown` listener; routes Ctrl+F /
|
|
1262
|
+
* Escape / Tab synchronously and dispatches the arrow-key / Home /
|
|
1263
|
+
* End / Ctrl+A / Ctrl+C path asynchronously.
|
|
1325
1264
|
*/
|
|
1326
1265
|
handleTdKeydown = (e) => {
|
|
1327
1266
|
this._focus.handleTdKeydown(e);
|
|
@@ -1352,12 +1291,7 @@ export class TableContext {
|
|
|
1352
1291
|
setColumnPinning = (updater) => {
|
|
1353
1292
|
this._columnLayout.setColumnPinning(updater);
|
|
1354
1293
|
};
|
|
1355
|
-
/**
|
|
1356
|
-
* Delegating accessor preserved for backwards compatibility. The
|
|
1357
|
-
* actual `$state` slot lives on `_filtering`; this getter / setter
|
|
1358
|
-
* pair forwards reads and writes so existing consumers (notably
|
|
1359
|
-
* `generateTableOptions`) need no migration.
|
|
1360
|
-
*/
|
|
1294
|
+
/** Delegates to `_filtering.updateFilters`. */
|
|
1361
1295
|
get updateFilters() {
|
|
1362
1296
|
return this._filtering.updateFilters;
|
|
1363
1297
|
}
|
|
@@ -1534,173 +1468,99 @@ export class TableContext {
|
|
|
1534
1468
|
this.unfocus();
|
|
1535
1469
|
this.columnDefs = newDefs;
|
|
1536
1470
|
};
|
|
1537
|
-
/**
|
|
1538
|
-
copyHighlightedRowsToClipboard =
|
|
1539
|
-
|
|
1540
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1541
|
-
if (!navigator.clipboard) {
|
|
1542
|
-
alert('cannot copy in an insecure connection');
|
|
1543
|
-
return;
|
|
1544
|
-
}
|
|
1545
|
-
return this._performRowCopy(await this.getHighlightedRowData());
|
|
1471
|
+
/** Delegates to `_clipboard.copyHighlightedRowsToClipboard`. */
|
|
1472
|
+
copyHighlightedRowsToClipboard = () => {
|
|
1473
|
+
return this._clipboard.copyHighlightedRowsToClipboard();
|
|
1546
1474
|
};
|
|
1547
|
-
/**
|
|
1548
|
-
copyDataToClipboard =
|
|
1549
|
-
|
|
1550
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1551
|
-
if (!navigator.clipboard) {
|
|
1552
|
-
alert('cannot copy in an insecure connection');
|
|
1553
|
-
return;
|
|
1554
|
-
}
|
|
1555
|
-
return this._performRowCopy(await this.getFocusElementData());
|
|
1475
|
+
/** Delegates to `_clipboard.copyDataToClipboard`. */
|
|
1476
|
+
copyDataToClipboard = () => {
|
|
1477
|
+
return this._clipboard.copyDataToClipboard();
|
|
1556
1478
|
};
|
|
1557
|
-
|
|
1558
|
-
const focusedColumnIds = affectedColumns.map((it) => encapsulate(typeof it.header === 'string' ? it.header : it.id));
|
|
1559
|
-
const value = await (async () => {
|
|
1560
|
-
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
1561
|
-
const selectColumns = new Map();
|
|
1562
|
-
for (let i = affectedColumns.length - 1; i > -1; i--) {
|
|
1563
|
-
const columnDef = affectedColumns[i];
|
|
1564
|
-
if (columnDef instanceof SelectDef) {
|
|
1565
|
-
const item = items[i];
|
|
1566
|
-
const defOptions = indicesByItem.get(item);
|
|
1567
|
-
selectColumns.set(i, await (defOptions
|
|
1568
|
-
? (columnDef.getSpecificOptions?.(item, defOptions) ?? columnDef.getOptions())
|
|
1569
|
-
: columnDef.getOptions()));
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
const separator = this.commaSeparatedCopy ? ',' : '\t';
|
|
1573
|
-
const shouldCopyHeaders = this.copyWithHeaders &&
|
|
1574
|
-
(focusedElementData.length !== 1 || focusedElementData[0].length !== 1);
|
|
1575
|
-
// transform to TSV
|
|
1576
|
-
if (focusedElementData.length === 1 && focusedElementData[0].length === 1) {
|
|
1577
|
-
if (selectColumns.has(0)) {
|
|
1578
|
-
const columnOptions = selectColumns.get(0);
|
|
1579
|
-
const value = columnOptions?.find((it) => it.value === focusedElementData[0][0])?.label ??
|
|
1580
|
-
focusedElementData[0][0]?.toString() ??
|
|
1581
|
-
'';
|
|
1582
|
-
// Single-cell copy bypasses TSV/CSV wrapping but still lands
|
|
1583
|
-
// in a spreadsheet; neutralise formula-injection prefixes.
|
|
1584
|
-
return escapeForSpreadsheet(value);
|
|
1585
|
-
}
|
|
1586
|
-
else {
|
|
1587
|
-
const value = focusedElementData[0][0]?.toString().trim() ?? '';
|
|
1588
|
-
return escapeForSpreadsheet(value);
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
return `${shouldCopyHeaders ? `${focusedColumnIds.join(separator)}\n` : ''}${focusedElementData
|
|
1592
|
-
.map((it) => it
|
|
1593
|
-
.map((toCopy, i) => {
|
|
1594
|
-
if (toCopy instanceof Date) {
|
|
1595
|
-
return toCopy.toLocaleDateString();
|
|
1596
|
-
}
|
|
1597
|
-
if (selectColumns.has(i)) {
|
|
1598
|
-
const columnOptions = selectColumns.get(i);
|
|
1599
|
-
if (dev && !columnOptions) {
|
|
1600
|
-
console.warn(`could not find colum with index ${i}`);
|
|
1601
|
-
}
|
|
1602
|
-
const value = columnOptions?.find((it) => it.value === toCopy)?.label ??
|
|
1603
|
-
toCopy?.toString() ??
|
|
1604
|
-
'';
|
|
1605
|
-
return encapsulate(value);
|
|
1606
|
-
}
|
|
1607
|
-
else {
|
|
1608
|
-
const value = toCopy?.toString().trim() ?? '';
|
|
1609
|
-
return encapsulate(value);
|
|
1610
|
-
}
|
|
1611
|
-
})
|
|
1612
|
-
.join(separator))
|
|
1613
|
-
.join('\n')}`;
|
|
1614
|
-
})();
|
|
1615
|
-
navigator.clipboard.writeText(value).catch(devCatch);
|
|
1616
|
-
};
|
|
1617
|
-
/** Delegating accessor preserved for backwards compatibility. The
|
|
1618
|
-
* implementation lives on `_focus.startFocus` (Phase 6.6). */
|
|
1479
|
+
/** Delegates to `_focus.startFocus`. */
|
|
1619
1480
|
startFocus = (coords) => {
|
|
1620
1481
|
this._focus.startFocus(coords);
|
|
1621
1482
|
};
|
|
1622
|
-
/**
|
|
1623
|
-
* implementation lives on `_focus.moveFocus` (Phase 6.6). */
|
|
1483
|
+
/** Delegates to `_focus.moveFocus`. */
|
|
1624
1484
|
moveFocus = (coords, startEditing = false) => {
|
|
1625
1485
|
this._focus.moveFocus(coords, startEditing);
|
|
1626
1486
|
};
|
|
1627
|
-
/**
|
|
1487
|
+
/** Delegates to `_focus`. */
|
|
1628
1488
|
unfocus = () => {
|
|
1629
1489
|
this._focus.unfocus();
|
|
1630
1490
|
};
|
|
1631
|
-
/**
|
|
1491
|
+
/** Delegates to `_focus`. */
|
|
1632
1492
|
focusToTop = () => {
|
|
1633
1493
|
this._focus.focusToTop();
|
|
1634
1494
|
};
|
|
1635
|
-
/**
|
|
1495
|
+
/** Delegates to `_focus`. */
|
|
1636
1496
|
focusToBottom = () => {
|
|
1637
1497
|
this._focus.focusToBottom();
|
|
1638
1498
|
};
|
|
1639
|
-
/**
|
|
1499
|
+
/** Delegates to `_focus`. */
|
|
1640
1500
|
moveToBottom = () => {
|
|
1641
1501
|
this._focus.moveToBottom();
|
|
1642
1502
|
};
|
|
1643
|
-
/**
|
|
1503
|
+
/** Delegates to `_focus`. */
|
|
1644
1504
|
moveToTop = () => {
|
|
1645
1505
|
this._focus.moveToTop();
|
|
1646
1506
|
};
|
|
1647
|
-
/**
|
|
1507
|
+
/** Delegates to `_focus`. */
|
|
1648
1508
|
moveFocusUp = () => {
|
|
1649
1509
|
this._focus.moveFocusUp();
|
|
1650
1510
|
};
|
|
1651
|
-
/**
|
|
1511
|
+
/** Delegates to `_focus`. */
|
|
1652
1512
|
setFocusUp = () => {
|
|
1653
1513
|
this._focus.setFocusUp();
|
|
1654
1514
|
};
|
|
1655
|
-
/**
|
|
1515
|
+
/** Delegates to `_focus`. */
|
|
1656
1516
|
tabForward = () => {
|
|
1657
1517
|
this._focus.tabForward();
|
|
1658
1518
|
};
|
|
1659
|
-
/**
|
|
1519
|
+
/** Delegates to `_focus`. */
|
|
1660
1520
|
tabBackward = () => {
|
|
1661
1521
|
this._focus.tabBackward();
|
|
1662
1522
|
};
|
|
1663
|
-
/**
|
|
1523
|
+
/** Delegates to `_focus`. */
|
|
1664
1524
|
focusToStart = () => {
|
|
1665
1525
|
this._focus.focusToStart();
|
|
1666
1526
|
};
|
|
1667
|
-
/**
|
|
1527
|
+
/** Delegates to `_focus`. */
|
|
1668
1528
|
moveToStart = () => {
|
|
1669
1529
|
this._focus.moveToStart();
|
|
1670
1530
|
};
|
|
1671
|
-
/**
|
|
1531
|
+
/** Delegates to `_focus`. */
|
|
1672
1532
|
focusToEnd = () => {
|
|
1673
1533
|
this._focus.focusToEnd();
|
|
1674
1534
|
};
|
|
1675
|
-
/**
|
|
1535
|
+
/** Delegates to `_focus`. */
|
|
1676
1536
|
moveToEnd = () => {
|
|
1677
1537
|
this._focus.moveToEnd();
|
|
1678
1538
|
};
|
|
1679
|
-
/**
|
|
1539
|
+
/** Delegates to `_focus`. */
|
|
1680
1540
|
moveFocusDown = () => {
|
|
1681
1541
|
this._focus.moveFocusDown();
|
|
1682
1542
|
};
|
|
1683
|
-
/**
|
|
1543
|
+
/** Delegates to `_focus`. */
|
|
1684
1544
|
setFocusDown = () => {
|
|
1685
1545
|
this._focus.setFocusDown();
|
|
1686
1546
|
};
|
|
1687
|
-
/**
|
|
1547
|
+
/** Delegates to `_focus`. */
|
|
1688
1548
|
moveFocusLeft = () => {
|
|
1689
1549
|
this._focus.moveFocusLeft();
|
|
1690
1550
|
};
|
|
1691
|
-
/**
|
|
1551
|
+
/** Delegates to `_focus`. */
|
|
1692
1552
|
setFocusLeft = () => {
|
|
1693
1553
|
this._focus.setFocusLeft();
|
|
1694
1554
|
};
|
|
1695
|
-
/**
|
|
1555
|
+
/** Delegates to `_focus`. */
|
|
1696
1556
|
moveFocusRight = () => {
|
|
1697
1557
|
this._focus.moveFocusRight();
|
|
1698
1558
|
};
|
|
1699
|
-
/**
|
|
1559
|
+
/** Delegates to `_focus`. */
|
|
1700
1560
|
setFocusRight = () => {
|
|
1701
1561
|
this._focus.setFocusRight();
|
|
1702
1562
|
};
|
|
1703
|
-
/**
|
|
1563
|
+
/** Delegates to `_focus`. */
|
|
1704
1564
|
endFocus = (coords) => {
|
|
1705
1565
|
this._focus.endFocus(coords);
|
|
1706
1566
|
};
|
|
@@ -1752,17 +1612,15 @@ export class TableContext {
|
|
|
1752
1612
|
// }
|
|
1753
1613
|
// };
|
|
1754
1614
|
/**
|
|
1755
|
-
*
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1758
|
-
*
|
|
1759
|
-
* `_preferences.setSelectedPreset` (Phase 6.4).
|
|
1615
|
+
* Applies the preset to the live column layout, forwards the
|
|
1616
|
+
* preset's `sortingState` to the data-repository updater, and
|
|
1617
|
+
* persists the selected name. Delegates to
|
|
1618
|
+
* `_preferences.setSelectedPreset`.
|
|
1760
1619
|
*
|
|
1761
|
-
* The
|
|
1762
|
-
*
|
|
1763
|
-
*
|
|
1764
|
-
* `
|
|
1765
|
-
* warning is reinstated below so the surface is byte-identical.
|
|
1620
|
+
* The "no sorting state found" debug warning is emitted here (not
|
|
1621
|
+
* inside the sub-context) so the public surface stays byte-identical
|
|
1622
|
+
* - `_preferences.applySortingState` already no-ops when
|
|
1623
|
+
* `paginationRepo.updateSorting` is absent.
|
|
1766
1624
|
*/
|
|
1767
1625
|
setSelectedPreset = (preset) => {
|
|
1768
1626
|
if (!this.paginationRepo?.updateSorting) {
|
|
@@ -1771,19 +1629,17 @@ export class TableContext {
|
|
|
1771
1629
|
this._preferences.setSelectedPreset(preset);
|
|
1772
1630
|
};
|
|
1773
1631
|
/**
|
|
1774
|
-
*
|
|
1775
|
-
* replaces a saved preset for the current column layout and
|
|
1632
|
+
* Adds or replaces a saved preset for the current column layout and
|
|
1776
1633
|
* persists the full preset list to localStorage. Delegates to
|
|
1777
|
-
* `_preferences.saveColumnPreset
|
|
1634
|
+
* `_preferences.saveColumnPreset`.
|
|
1778
1635
|
*/
|
|
1779
1636
|
saveColumnPreset = (name) => {
|
|
1780
1637
|
this._preferences.saveColumnPreset(name);
|
|
1781
1638
|
};
|
|
1782
1639
|
/**
|
|
1783
|
-
* This listener should be added
|
|
1640
|
+
* Delegates to `_focus.setFocusEnd`. This listener should be added
|
|
1641
|
+
* and removed based on `isMousingDown`.
|
|
1784
1642
|
*/
|
|
1785
|
-
/** Delegating accessor preserved for backwards compatibility. The
|
|
1786
|
-
* implementation lives on `_focus.setFocusEnd` (Phase 6.6). */
|
|
1787
1643
|
setFocusEnd = (coords) => {
|
|
1788
1644
|
this._focus.setFocusEnd(coords);
|
|
1789
1645
|
};
|
|
@@ -1888,18 +1744,12 @@ export class TableContext {
|
|
|
1888
1744
|
.map(makeRow));
|
|
1889
1745
|
return row;
|
|
1890
1746
|
}
|
|
1891
|
-
columnDefReturnsTextValue = (it) => {
|
|
1892
|
-
return ('index' in it &&
|
|
1893
|
-
this.columnVisibility[it.id] !== false &&
|
|
1894
|
-
!uncopyableColumns.has(it.columnType));
|
|
1895
|
-
};
|
|
1896
1747
|
/**
|
|
1897
|
-
*
|
|
1898
|
-
*
|
|
1899
|
-
*
|
|
1900
|
-
*
|
|
1901
|
-
*
|
|
1902
|
-
* persistence side of the boundary moved.
|
|
1748
|
+
* Build the user-controlled settings blob from the current `$state`
|
|
1749
|
+
* slots and delegate the `localStorage.setItem` call to
|
|
1750
|
+
* `_preferences.persistSettings`. The settings fields themselves
|
|
1751
|
+
* live on `TableContext` because each drives reactive UI; only the
|
|
1752
|
+
* persistence boundary lives in the sub-context.
|
|
1903
1753
|
*/
|
|
1904
1754
|
_updateLocalStorageSettings() {
|
|
1905
1755
|
const settingsObject = {
|
|
@@ -1913,11 +1763,9 @@ export class TableContext {
|
|
|
1913
1763
|
this._preferences.persistSettings(settingsObject);
|
|
1914
1764
|
}
|
|
1915
1765
|
/**
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
1918
|
-
*
|
|
1919
|
-
* preserved on `TableContext` to keep the existing read sites in
|
|
1920
|
-
* `tabForward` / `focusToStart` / `moveFocusLeft` / etc. untouched.
|
|
1766
|
+
* Delegates to `_columnLayout.visualColumns`. The underscore prefix
|
|
1767
|
+
* is preserved so the existing read sites in `tabForward` /
|
|
1768
|
+
* `focusToStart` / `moveFocusLeft` / etc. stay untouched.
|
|
1921
1769
|
*/
|
|
1922
1770
|
get _visualColumns() {
|
|
1923
1771
|
return this._columnLayout.visualColumns;
|
|
@@ -1929,166 +1777,16 @@ export class TableContext {
|
|
|
1929
1777
|
return this._columnLayout.columnVisualIndex(id);
|
|
1930
1778
|
}
|
|
1931
1779
|
/**
|
|
1932
|
-
*
|
|
1933
|
-
*
|
|
1934
|
-
* (Phase 6.6); the visual-index lookup itself is owned by
|
|
1935
|
-
* `_columnLayout.columnVisualIndex` (Phase 6.3).
|
|
1780
|
+
* Delegates to `_focus.focusStartVisualColumn`; the visual-index
|
|
1781
|
+
* lookup is owned by `_columnLayout.columnVisualIndex`.
|
|
1936
1782
|
*/
|
|
1937
1783
|
get focusStartVisualColumn() {
|
|
1938
1784
|
return this._focus.focusStartVisualColumn;
|
|
1939
1785
|
}
|
|
1940
|
-
/**
|
|
1941
|
-
* Delegating getter preserved for backwards compatibility. The
|
|
1942
|
-
* implementation lives on `_focus.focusEndVisualColumn`
|
|
1943
|
-
* (Phase 6.6).
|
|
1944
|
-
*/
|
|
1786
|
+
/** Delegates to `_focus.focusEndVisualColumn`. */
|
|
1945
1787
|
get focusEndVisualColumn() {
|
|
1946
1788
|
return this._focus.focusEndVisualColumn;
|
|
1947
1789
|
}
|
|
1948
|
-
async getHighlightedRowData() {
|
|
1949
|
-
const affectedColumns = this.columnDefs.filter(this.columnDefReturnsTextValue);
|
|
1950
|
-
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
1951
|
-
const indices = new Map();
|
|
1952
|
-
const selectedRows = [...this.highlightedItems.values()];
|
|
1953
|
-
const sortedData = this.sortedData;
|
|
1954
|
-
for (const item of selectedRows) {
|
|
1955
|
-
const rowIndex = sortedData.indexOf(item);
|
|
1956
|
-
if (rowIndex == -1) {
|
|
1957
|
-
console.warn(`row index for highlighted row data not found`);
|
|
1958
|
-
continue;
|
|
1959
|
-
}
|
|
1960
|
-
indices.set(item, rowIndex);
|
|
1961
|
-
}
|
|
1962
|
-
selectedRows.sort((left, right) => {
|
|
1963
|
-
return (indices.get(left) ?? -1) - (indices.get(right) ?? -1);
|
|
1964
|
-
});
|
|
1965
|
-
// 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)
|
|
1966
|
-
const selectedCells = [];
|
|
1967
|
-
const rowLength = selectedRows.length;
|
|
1968
|
-
for (let rowIndex = 0; rowIndex < rowLength; rowIndex++) {
|
|
1969
|
-
const item = selectedRows[rowIndex];
|
|
1970
|
-
const rawKey = this._cachedKey(item);
|
|
1971
|
-
const key = rawKey instanceof Promise ? await rawKey : rawKey;
|
|
1972
|
-
selectedCells[rowIndex] = [];
|
|
1973
|
-
const targetRow = selectedCells[rowIndex];
|
|
1974
|
-
const colLength = affectedColumns.length;
|
|
1975
|
-
for (let colIndex = 0; colIndex < colLength; colIndex++) {
|
|
1976
|
-
const columnDef = affectedColumns[colIndex];
|
|
1977
|
-
if (columnDef instanceof RowSelectionDef) {
|
|
1978
|
-
targetRow.push(this.selectedItems.has(key) ? 'true' : 'false');
|
|
1979
|
-
continue;
|
|
1980
|
-
}
|
|
1981
|
-
if (uncopyableColumns.has(columnDef.columnType)) {
|
|
1982
|
-
continue;
|
|
1983
|
-
}
|
|
1984
|
-
const x = (await columnDef.getDisplayValue?.(item, sortedData.lastIndexOf(item))) ||
|
|
1985
|
-
('accessorFn' in columnDef &&
|
|
1986
|
-
(await columnDef.accessorFn?.(item, sortedData.indexOf(item))));
|
|
1987
|
-
if (x && typeof x === 'string') {
|
|
1988
|
-
targetRow.push(x);
|
|
1989
|
-
continue;
|
|
1990
|
-
}
|
|
1991
|
-
if (x && Array.isArray(x) && typeof x[0] === 'string') {
|
|
1992
|
-
targetRow.push(x.join(', '));
|
|
1993
|
-
continue;
|
|
1994
|
-
}
|
|
1995
|
-
const toCopy = columnDef.id && columnDef.id in item ? item[columnDef.id] : null;
|
|
1996
|
-
const y = toCopy && typeof toCopy === 'object' && toCopy instanceof Date
|
|
1997
|
-
? toCopy.toLocaleDateString()
|
|
1998
|
-
: (toCopy?.toString() ?? '');
|
|
1999
|
-
targetRow.push(y);
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
return {
|
|
2003
|
-
items: selectedRows,
|
|
2004
|
-
indicesByItem: indices,
|
|
2005
|
-
focusedElementData: selectedCells,
|
|
2006
|
-
affectedColumns,
|
|
2007
|
-
};
|
|
2008
|
-
}
|
|
2009
|
-
async getFocusElementData() {
|
|
2010
|
-
if (this.focusStart && this.focusEnd) {
|
|
2011
|
-
const { row: startRowIndexId } = this.focusStart;
|
|
2012
|
-
const { row: endRowIndexId } = this.focusEnd;
|
|
2013
|
-
// const model = this._currentPageData;
|
|
2014
|
-
const model = this.paginationRowModel;
|
|
2015
|
-
const startRowIndex = model.rows.findIndex((row) => row.visibleIndex === startRowIndexId);
|
|
2016
|
-
const endRowIndex = model.rows.findIndex((row) => row.visibleIndex === endRowIndexId);
|
|
2017
|
-
if (!this.currentPageData.length || startRowIndex == -1 || endRowIndex == -1) {
|
|
2018
|
-
throw new Error(`copy was missing one of the two indices. First: ${startRowIndex}, second: ${endRowIndex}`);
|
|
2019
|
-
}
|
|
2020
|
-
const minRowIndex = Math.min(startRowIndex, endRowIndex);
|
|
2021
|
-
const maxRowIndex = Math.max(startRowIndex, endRowIndex);
|
|
2022
|
-
const startVisualIndex = this.columnVisualIndex(this.focusStart.id);
|
|
2023
|
-
const endVisualIndex = this.columnVisualIndex(this.focusEnd.id);
|
|
2024
|
-
const minVisualIndex = Math.min(startVisualIndex, endVisualIndex);
|
|
2025
|
-
const maxVisualIndex = Math.max(startVisualIndex, endVisualIndex);
|
|
2026
|
-
const affectedColumns = this._visualColumns
|
|
2027
|
-
.slice(minVisualIndex, maxVisualIndex + 1)
|
|
2028
|
-
.filter((it) => this.columnDefReturnsTextValue(it));
|
|
2029
|
-
const selectedRows = [];
|
|
2030
|
-
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
2031
|
-
const indices = new Map();
|
|
2032
|
-
for (let i = minRowIndex; i <= maxRowIndex; i++) {
|
|
2033
|
-
const row = model.rows[i];
|
|
2034
|
-
const item = row.original;
|
|
2035
|
-
const itemIndex = row.originalIndex;
|
|
2036
|
-
selectedRows.push(item);
|
|
2037
|
-
indices.set(item, itemIndex);
|
|
2038
|
-
}
|
|
2039
|
-
// 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)
|
|
2040
|
-
const selectedCells = [];
|
|
2041
|
-
const rowLength = selectedRows.length;
|
|
2042
|
-
const sortedData = this.sortedData;
|
|
2043
|
-
for (let rowIndex = 0; rowIndex < rowLength; rowIndex++) {
|
|
2044
|
-
const item = selectedRows[rowIndex];
|
|
2045
|
-
const rawKey = this._cachedKey(item);
|
|
2046
|
-
const key = rawKey instanceof Promise ? await rawKey : rawKey;
|
|
2047
|
-
selectedCells[rowIndex] = [];
|
|
2048
|
-
const targetRow = selectedCells[rowIndex];
|
|
2049
|
-
const colLength = affectedColumns.length;
|
|
2050
|
-
for (let colIndex = 0; colIndex < colLength; colIndex++) {
|
|
2051
|
-
const columnDef = affectedColumns[colIndex];
|
|
2052
|
-
if (columnDef instanceof RowSelectionDef) {
|
|
2053
|
-
targetRow.push(this.selectedItems.has(key) ? 'true' : 'false');
|
|
2054
|
-
continue;
|
|
2055
|
-
}
|
|
2056
|
-
if (uncopyableColumns.has(columnDef.columnType)) {
|
|
2057
|
-
continue;
|
|
2058
|
-
}
|
|
2059
|
-
const x = (await columnDef.getDisplayValue?.(item, sortedData.lastIndexOf(item))) ||
|
|
2060
|
-
('accessorFn' in columnDef &&
|
|
2061
|
-
(await columnDef.accessorFn?.(item, sortedData.indexOf(item))));
|
|
2062
|
-
if (x && typeof x === 'string') {
|
|
2063
|
-
targetRow.push(x);
|
|
2064
|
-
continue;
|
|
2065
|
-
}
|
|
2066
|
-
if (x && Array.isArray(x) && typeof x[0] === 'string') {
|
|
2067
|
-
targetRow.push(x.join(', '));
|
|
2068
|
-
continue;
|
|
2069
|
-
}
|
|
2070
|
-
const toCopy = columnDef.id && columnDef.id in item ? item[columnDef.id] : null;
|
|
2071
|
-
const y = toCopy && typeof toCopy === 'object' && toCopy instanceof Date
|
|
2072
|
-
? toCopy.toLocaleDateString()
|
|
2073
|
-
: (toCopy?.toString() ?? '');
|
|
2074
|
-
targetRow.push(y);
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
return {
|
|
2078
|
-
items: selectedRows,
|
|
2079
|
-
indicesByItem: indices,
|
|
2080
|
-
focusedElementData: selectedCells,
|
|
2081
|
-
affectedColumns,
|
|
2082
|
-
};
|
|
2083
|
-
}
|
|
2084
|
-
return {
|
|
2085
|
-
items: [],
|
|
2086
|
-
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
2087
|
-
indicesByItem: new Map(),
|
|
2088
|
-
focusedElementData: [],
|
|
2089
|
-
affectedColumns: [],
|
|
2090
|
-
};
|
|
2091
|
-
}
|
|
2092
1790
|
updateDefsBasedOnPinning = () => {
|
|
2093
1791
|
return this._columnLayout.updateDefsBasedOnPinning();
|
|
2094
1792
|
};
|
|
@@ -2105,17 +1803,28 @@ export class TableContext {
|
|
|
2105
1803
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
2106
1804
|
async setupDefaultColumnDefs() {
|
|
2107
1805
|
this.assertNoDuplicateIds();
|
|
1806
|
+
// Snapshot the locally-available filter functions once per pass so
|
|
1807
|
+
// `resolveDefaultFilter` can index into them by name.
|
|
1808
|
+
const localFilters = {
|
|
1809
|
+
stringFilter: this.stringFilter,
|
|
1810
|
+
numberFilter: this.numberFilter,
|
|
1811
|
+
selectFilter: this.selectFilter,
|
|
1812
|
+
boolFilter: this.boolFilter,
|
|
1813
|
+
dateFilter: this.dateFilter,
|
|
1814
|
+
};
|
|
2108
1815
|
const adjustedDefsPromises = this.defaultColumnDefs.defs.map((def) => {
|
|
2109
|
-
|
|
1816
|
+
const entry = def.kind != null ? COLUMN_KIND_REGISTRY[def.kind] : undefined;
|
|
1817
|
+
// Accessor columns get a header-width minSize floor so the
|
|
1818
|
+
// header text never wraps under its declared width. Falls
|
|
1819
|
+
// back to 120px when the header is a Snippet rather than a
|
|
1820
|
+
// plain string (cannot canvas-measure).
|
|
1821
|
+
if (entry?.category === 'accessor') {
|
|
2110
1822
|
if (!def.allowFiltering) {
|
|
2111
1823
|
if (def.debug) {
|
|
2112
1824
|
console.log(`${def.id}: does not allow filtering`, def);
|
|
2113
1825
|
}
|
|
2114
1826
|
return def;
|
|
2115
1827
|
}
|
|
2116
|
-
if (def.debug) {
|
|
2117
|
-
console.log(`${def.id}: is an accessor def`, def);
|
|
2118
|
-
}
|
|
2119
1828
|
if (!('minSize' in def) || !def.minSize) {
|
|
2120
1829
|
if (typeof def.header === 'string') {
|
|
2121
1830
|
const minWidth = this.measureHeaderWidth(def);
|
|
@@ -2126,103 +1835,26 @@ export class TableContext {
|
|
|
2126
1835
|
def.minSize = 120;
|
|
2127
1836
|
}
|
|
2128
1837
|
}
|
|
2129
|
-
// code smell...
|
|
2130
|
-
if (def instanceof TextInputDef) {
|
|
2131
|
-
def.filterFn = this.stringFilter;
|
|
2132
|
-
if (def.debug) {
|
|
2133
|
-
console.log(`${def.id}: given a string filter`, def);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
else if (def instanceof NumberInputDef) {
|
|
2137
|
-
def.filterFn = this.numberFilter;
|
|
2138
|
-
if (def.debug) {
|
|
2139
|
-
console.log(`${def.id}: given a number filter`, def);
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
else if (def instanceof SelectDef) {
|
|
2143
|
-
def.filterFn = this.selectFilter;
|
|
2144
|
-
if (def.debug) {
|
|
2145
|
-
console.log(`${def.id}: given a select filter`, def);
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
else if (def instanceof CheckboxDef) {
|
|
2149
|
-
def.filterFn = this.boolFilter;
|
|
2150
|
-
if (def.debug) {
|
|
2151
|
-
console.log(`${def.id}: given a bool filter`, def);
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
else if (def instanceof DateInputDef) {
|
|
2155
|
-
def.filterFn = this.dateFilter;
|
|
2156
|
-
if (def.debug) {
|
|
2157
|
-
console.log(`${def.id}: given a date filter`, def);
|
|
2158
|
-
}
|
|
2159
|
-
}
|
|
2160
|
-
else if (def.debug) {
|
|
2161
|
-
console.log(`${def.id}: was not a text,number,select,checkbox,or date accessor, and was not given a filter`, def);
|
|
2162
|
-
}
|
|
2163
1838
|
}
|
|
2164
|
-
|
|
2165
|
-
//
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
console.log(`${def.id}: given a string filter`, def);
|
|
2178
|
-
}
|
|
2179
|
-
break;
|
|
2180
|
-
}
|
|
2181
|
-
case 'Bool': {
|
|
2182
|
-
def.filterFn = this.boolFilter;
|
|
2183
|
-
if (def.debug) {
|
|
2184
|
-
console.log(`${def.id}: given a bool filter`, def);
|
|
2185
|
-
}
|
|
2186
|
-
break;
|
|
2187
|
-
}
|
|
2188
|
-
case 'Date': {
|
|
2189
|
-
def.filterFn = this.dateFilter;
|
|
2190
|
-
if (def.debug) {
|
|
2191
|
-
console.log(`${def.id}: given a date filter`, def);
|
|
2192
|
-
}
|
|
2193
|
-
break;
|
|
2194
|
-
}
|
|
2195
|
-
case 'Number': {
|
|
2196
|
-
def.filterFn = this.numberFilter;
|
|
2197
|
-
if (def.debug) {
|
|
2198
|
-
console.log(`${def.id}: given a number filter`, def);
|
|
2199
|
-
}
|
|
2200
|
-
break;
|
|
2201
|
-
}
|
|
2202
|
-
case 'Select': {
|
|
2203
|
-
def.filterFn = this.selectFilter;
|
|
2204
|
-
if (def.debug) {
|
|
2205
|
-
console.log(`${def.id}: given a select filter`, def);
|
|
2206
|
-
}
|
|
2207
|
-
break;
|
|
1839
|
+
// Wire the default filter function for kinds the registry knows
|
|
1840
|
+
// about. Accessor kinds replace any pre-existing filterFn;
|
|
1841
|
+
// display kinds (Display / Bubble / Progress) only fill in when
|
|
1842
|
+
// nothing was set. Structural kinds (rowSelection, actions,
|
|
1843
|
+
// expand, validity, filterOnly) skip entirely.
|
|
1844
|
+
if (def.allowFiltering) {
|
|
1845
|
+
const isAccessor = entry?.category === 'accessor';
|
|
1846
|
+
if (isAccessor || !def.filterFn) {
|
|
1847
|
+
const resolved = resolveDefaultFilter(def, localFilters);
|
|
1848
|
+
if (resolved !== undefined) {
|
|
1849
|
+
def.filterFn = resolved;
|
|
1850
|
+
if (def.debug) {
|
|
1851
|
+
console.log(`${def.id}: assigned default ${def.kind ?? '<unknown>'} filter`, def);
|
|
2208
1852
|
}
|
|
2209
1853
|
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
def.filterFn = this.stringFilter;
|
|
2213
|
-
if (def.debug) {
|
|
2214
|
-
console.log(`${def.id}: is a bubble def. given a string filter`, def);
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
else if (def instanceof ProgressBarDef) {
|
|
2218
|
-
def.filterFn = this.numberFilter;
|
|
2219
|
-
if (def.debug) {
|
|
2220
|
-
console.log(`${def.id}: is a progress def. given a number filter`, def);
|
|
1854
|
+
else if (def.debug && entry !== undefined && entry.category !== 'structural') {
|
|
1855
|
+
console.log(`${def.id}: kind has no default filter and none assigned`, def);
|
|
2221
1856
|
}
|
|
2222
1857
|
}
|
|
2223
|
-
else if (def.debug) {
|
|
2224
|
-
console.log(`${def.id}: is not a display, bubble, or progressbar def, and was not given a filter`, def);
|
|
2225
|
-
}
|
|
2226
1858
|
}
|
|
2227
1859
|
else if (def.debug) {
|
|
2228
1860
|
console.log(`${def.id}: no filtering matched`, def);
|
|
@@ -2239,16 +1871,15 @@ export class TableContext {
|
|
|
2239
1871
|
return adjustedDefs;
|
|
2240
1872
|
}
|
|
2241
1873
|
/**
|
|
2242
|
-
*
|
|
2243
|
-
* `_preferences.loadSavedSettings`
|
|
2244
|
-
*
|
|
2245
|
-
* pre-extraction behaviour:
|
|
1874
|
+
* Read the persisted per-table user-settings blob through
|
|
1875
|
+
* `_preferences.loadSavedSettings` and apply each field to the live
|
|
1876
|
+
* `$state` slot. Field defaults:
|
|
2246
1877
|
*
|
|
2247
1878
|
* - missing slot: `singleClickEditing` defaults to `true`; every
|
|
2248
1879
|
* other field keeps its constructor default.
|
|
2249
|
-
* - present slot:
|
|
1880
|
+
* - present slot: a field is applied only if it would deviate from
|
|
2250
1881
|
* the constructor default (the "only alter when the user
|
|
2251
|
-
* explicitly disabled"
|
|
1882
|
+
* explicitly disabled it" semantic).
|
|
2252
1883
|
*/
|
|
2253
1884
|
_getUserDefaults() {
|
|
2254
1885
|
const saved = this._preferences.loadSavedSettings();
|
|
@@ -2365,51 +1996,6 @@ export function isSearchable(def) {
|
|
|
2365
1996
|
function hasPagination(repository) {
|
|
2366
1997
|
return 'setPage' in repository;
|
|
2367
1998
|
}
|
|
2368
|
-
/**
|
|
2369
|
-
* Neutralises CSV / TSV formula-injection prefixes recognised by Excel,
|
|
2370
|
-
* LibreOffice Calc, Google Sheets, and Apple Numbers.
|
|
2371
|
-
*
|
|
2372
|
-
* When a clipboard payload reaches a spreadsheet, any cell whose first
|
|
2373
|
-
* character is one of `=`, `+`, `-`, `@`, `\t`, `\r` is treated as a
|
|
2374
|
-
* formula and evaluated in the user's context. Untrusted row data
|
|
2375
|
-
* containing `=cmd|'/c calc'!A1` (or DDE / web-query equivalents) is the
|
|
2376
|
-
* canonical attack vector. Prefixing such a value with a single quote
|
|
2377
|
-
* (`'`) makes the spreadsheet interpret the cell as a literal string
|
|
2378
|
-
* instead.
|
|
2379
|
-
*
|
|
2380
|
-
* Trade-off: the leading apostrophe is invisible in the rendered cell of
|
|
2381
|
-
* every major spreadsheet, but the underlying cell value differs from the
|
|
2382
|
-
* source when read back by another formula referencing the cell. This is
|
|
2383
|
-
* the accepted industry mitigation (OWASP CSV Injection cheat sheet).
|
|
2384
|
-
*
|
|
2385
|
-
* Private helper - keep this colocated with `encapsulate` so every
|
|
2386
|
-
* clipboard-bound string flows through both functions before being
|
|
2387
|
-
* written to the OS clipboard.
|
|
2388
|
-
*/
|
|
2389
|
-
function escapeForSpreadsheet(value) {
|
|
2390
|
-
if (value.length === 0) {
|
|
2391
|
-
return value;
|
|
2392
|
-
}
|
|
2393
|
-
const first = value.charCodeAt(0);
|
|
2394
|
-
// '=' 61, '+' 43, '-' 45, '@' 64, '\t' 9, '\r' 13
|
|
2395
|
-
if (first === 61 || first === 43 || first === 45 || first === 64 || first === 9 || first === 13) {
|
|
2396
|
-
return `'${value}`;
|
|
2397
|
-
}
|
|
2398
|
-
return value;
|
|
2399
|
-
}
|
|
2400
|
-
function encapsulate(value) {
|
|
2401
|
-
const safe = escapeForSpreadsheet(value);
|
|
2402
|
-
return `"${safe.replace(/[\n]/gm, ' ').replace(/["]/g, '""')}"`;
|
|
2403
|
-
}
|
|
2404
|
-
/**
|
|
2405
|
-
* Internal exports for tests. Not part of the public API; do not import
|
|
2406
|
-
* from consumer code. Allows the clipboard formula-escape regression test
|
|
2407
|
-
* to call the module-private helpers directly.
|
|
2408
|
-
*/
|
|
2409
|
-
export const _internal = {
|
|
2410
|
-
escapeForSpreadsheet,
|
|
2411
|
-
encapsulate,
|
|
2412
|
-
};
|
|
2413
1999
|
function generateTableOptions(contextObj) {
|
|
2414
2000
|
const _pagination = $derived.by(() => {
|
|
2415
2001
|
void contextObj.paginationRepo?.paginationState.pageSize;
|