@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
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { ColumnDef } from '../Columns/Definitions/ColumnDef.svelte.js';
|
|
2
|
+
import type { CellCoordinates } from '../Coordinates/CellCoordinates.js';
|
|
3
|
+
import type { VisualColumnIndex } from '../Coordinates/ColumnIndices.js';
|
|
4
|
+
import type { Primitive } from './TableInitOptions.js';
|
|
5
|
+
/**
|
|
6
|
+
* Shape of the parent context's read surface that `ClipboardState` needs.
|
|
7
|
+
* Every entry is a thunk so the sub-context never holds a parent reference
|
|
8
|
+
* and the reactive graph keeps its `$derived` shape.
|
|
9
|
+
*/
|
|
10
|
+
export interface ClipboardStateDeps<T extends object, RowIdType extends Primitive> {
|
|
11
|
+
getColumnDefs: () => ReadonlyArray<ColumnDef<T>>;
|
|
12
|
+
/** Same shape as `VisibilityState`; the deps interface keeps the
|
|
13
|
+
* structural form so the sub-context doesn't depend on the type alias. */
|
|
14
|
+
getColumnVisibility: () => Record<string, boolean | undefined>;
|
|
15
|
+
getHighlightedItems: () => ReadonlyMap<RowIdType, T>;
|
|
16
|
+
getSelectedItems: () => ReadonlyMap<RowIdType, T>;
|
|
17
|
+
getSortedData: () => ReadonlyArray<T>;
|
|
18
|
+
getCurrentPageData: () => ReadonlyArray<T>;
|
|
19
|
+
getPaginationRowModel: () => {
|
|
20
|
+
rows: ReadonlyArray<{
|
|
21
|
+
visibleIndex: number;
|
|
22
|
+
original: T;
|
|
23
|
+
originalIndex: number;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
getVisualColumns: () => ReadonlyArray<ColumnDef<T>>;
|
|
27
|
+
getFocusStart: () => CellCoordinates | null | undefined;
|
|
28
|
+
getFocusEnd: () => CellCoordinates | null | undefined;
|
|
29
|
+
cachedKey: (item: T) => RowIdType | Promise<RowIdType>;
|
|
30
|
+
columnVisualIndex: (id: string) => VisualColumnIndex;
|
|
31
|
+
/** Master gate from `TableInitOptions.allowCopy`. */
|
|
32
|
+
getAllowCopy: () => boolean;
|
|
33
|
+
/** Called by the persistence setters after a successful write so the
|
|
34
|
+
* parent flushes the user-settings blob to localStorage. */
|
|
35
|
+
persistSettings: () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sub-context owning the copy-to-clipboard machinery: the two user-tunable
|
|
39
|
+
* preference flags (`copyWithHeaders`, `commaSeparatedCopy`), the
|
|
40
|
+
* `Promise`-returning serialisers for the highlighted-rows and focus-range
|
|
41
|
+
* payloads, and the `_performRowCopy` writer that funnels everything through
|
|
42
|
+
* `escapeForSpreadsheet` / `encapsulate` before reaching `navigator.clipboard`.
|
|
43
|
+
*
|
|
44
|
+
* Why a sub-context (rather than methods on `TableContext`):
|
|
45
|
+
*
|
|
46
|
+
* - All the load-bearing rules live in one file — header gating,
|
|
47
|
+
* separator selection, formula-injection neutralisation, select-option
|
|
48
|
+
* label resolution. The grouping matches the user mental model.
|
|
49
|
+
* - `TableContext.svelte.ts` is the long-standing god-object; pulling
|
|
50
|
+
* clipboard out shrinks the parent by ~250 lines.
|
|
51
|
+
* - The two preference flags persist via the parent's existing
|
|
52
|
+
* `TableSettings` payload, so they live here behind the same
|
|
53
|
+
* `persistSettings` thunk the other prefs already use.
|
|
54
|
+
*/
|
|
55
|
+
export declare class ClipboardState<T extends object, RowIdType extends Primitive> {
|
|
56
|
+
private readonly _deps;
|
|
57
|
+
/** Whether copy-to-clipboard prepends a TSV / CSV header row. */
|
|
58
|
+
private _copyWithHeaders;
|
|
59
|
+
/** When true the separator is comma (CSV); otherwise tab (TSV). */
|
|
60
|
+
private _commaSeparatedCopy;
|
|
61
|
+
constructor(deps: ClipboardStateDeps<T, RowIdType>);
|
|
62
|
+
get copyWithHeaders(): boolean;
|
|
63
|
+
set copyWithHeaders(v: boolean);
|
|
64
|
+
get commaSeparatedCopy(): boolean;
|
|
65
|
+
set commaSeparatedCopy(v: boolean);
|
|
66
|
+
/** Toggles whether copy-to-clipboard prepends a header row and persists. */
|
|
67
|
+
readonly setCopyWithHeaders: (value: boolean) => void;
|
|
68
|
+
/** Toggles CSV vs TSV copy-to-clipboard separator and persists. */
|
|
69
|
+
readonly setCommaSeparatedCopy: (value: boolean) => void;
|
|
70
|
+
/** Copies the highlighted rows to the OS clipboard as TSV / CSV. */
|
|
71
|
+
readonly copyHighlightedRowsToClipboard: () => Promise<void>;
|
|
72
|
+
/** Copies the currently focused cell range to the OS clipboard. */
|
|
73
|
+
readonly copyDataToClipboard: () => Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Predicate determining whether a column contributes a text value to
|
|
76
|
+
* the clipboard payload. Hidden columns and structural / custom kinds
|
|
77
|
+
* are excluded; row-selection survives because it's serialised below.
|
|
78
|
+
*/
|
|
79
|
+
private columnDefReturnsTextValue;
|
|
80
|
+
private getHighlightedRowData;
|
|
81
|
+
private getFocusElementData;
|
|
82
|
+
/**
|
|
83
|
+
* Walk `rows` × `columns` and produce the inner 2D string buffer used
|
|
84
|
+
* by `_performRowCopy`. Factored out so the highlighted-rows and
|
|
85
|
+
* focus-range serialisers share their cell-reading logic verbatim
|
|
86
|
+
* (the two paths diverged historically only in how they picked which
|
|
87
|
+
* rows / which columns to include).
|
|
88
|
+
*/
|
|
89
|
+
private _readCellsFromRows;
|
|
90
|
+
/**
|
|
91
|
+
* Final serialisation step. Resolves `SelectDef` option labels for any
|
|
92
|
+
* affected select columns, picks the configured separator, encapsulates
|
|
93
|
+
* each cell, and writes the final string to the OS clipboard. Single-cell
|
|
94
|
+
* copies bypass TSV wrapping but still pass through
|
|
95
|
+
* `escapeForSpreadsheet` so a pasted formula payload can't execute.
|
|
96
|
+
*/
|
|
97
|
+
private _performRowCopy;
|
|
98
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { dev } from '$app/environment';
|
|
2
|
+
import { devCatch } from '../../../../Helpers/Helpers.svelte.js';
|
|
3
|
+
import { encapsulate, escapeForSpreadsheet } from '../../clipboardEscape.js';
|
|
4
|
+
import { ColumnType } from '../Columns/ColumnType.js';
|
|
5
|
+
import { SelectDef } from '../Columns/Definitions/Accessors/SelectDef.svelte.js';
|
|
6
|
+
import { RowSelectionDef } from '../Columns/Definitions/RowSelection/RowSelectionDef.svelte.js';
|
|
7
|
+
/**
|
|
8
|
+
* Column kinds whose cell value isn't a meaningful text payload and so
|
|
9
|
+
* should be skipped when serialising a row to the clipboard. Row-selection
|
|
10
|
+
* is handled explicitly (it serialises as "true" / "false") and is therefore
|
|
11
|
+
* NOT in this set.
|
|
12
|
+
*/
|
|
13
|
+
const uncopyableColumns = new Set([
|
|
14
|
+
ColumnType.Expand,
|
|
15
|
+
ColumnType.Actions,
|
|
16
|
+
ColumnType.FilterOnly,
|
|
17
|
+
ColumnType.Custom,
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Sub-context owning the copy-to-clipboard machinery: the two user-tunable
|
|
21
|
+
* preference flags (`copyWithHeaders`, `commaSeparatedCopy`), the
|
|
22
|
+
* `Promise`-returning serialisers for the highlighted-rows and focus-range
|
|
23
|
+
* payloads, and the `_performRowCopy` writer that funnels everything through
|
|
24
|
+
* `escapeForSpreadsheet` / `encapsulate` before reaching `navigator.clipboard`.
|
|
25
|
+
*
|
|
26
|
+
* Why a sub-context (rather than methods on `TableContext`):
|
|
27
|
+
*
|
|
28
|
+
* - All the load-bearing rules live in one file — header gating,
|
|
29
|
+
* separator selection, formula-injection neutralisation, select-option
|
|
30
|
+
* label resolution. The grouping matches the user mental model.
|
|
31
|
+
* - `TableContext.svelte.ts` is the long-standing god-object; pulling
|
|
32
|
+
* clipboard out shrinks the parent by ~250 lines.
|
|
33
|
+
* - The two preference flags persist via the parent's existing
|
|
34
|
+
* `TableSettings` payload, so they live here behind the same
|
|
35
|
+
* `persistSettings` thunk the other prefs already use.
|
|
36
|
+
*/
|
|
37
|
+
export class ClipboardState {
|
|
38
|
+
_deps;
|
|
39
|
+
/** Whether copy-to-clipboard prepends a TSV / CSV header row. */
|
|
40
|
+
_copyWithHeaders = $state(true);
|
|
41
|
+
/** When true the separator is comma (CSV); otherwise tab (TSV). */
|
|
42
|
+
_commaSeparatedCopy = $state(false);
|
|
43
|
+
constructor(deps) {
|
|
44
|
+
this._deps = deps;
|
|
45
|
+
}
|
|
46
|
+
// -------- preference flags -----------------------------------------
|
|
47
|
+
get copyWithHeaders() {
|
|
48
|
+
return this._copyWithHeaders;
|
|
49
|
+
}
|
|
50
|
+
set copyWithHeaders(v) {
|
|
51
|
+
this._copyWithHeaders = v;
|
|
52
|
+
}
|
|
53
|
+
get commaSeparatedCopy() {
|
|
54
|
+
return this._commaSeparatedCopy;
|
|
55
|
+
}
|
|
56
|
+
set commaSeparatedCopy(v) {
|
|
57
|
+
this._commaSeparatedCopy = v;
|
|
58
|
+
}
|
|
59
|
+
/** Toggles whether copy-to-clipboard prepends a header row and persists. */
|
|
60
|
+
setCopyWithHeaders = (value) => {
|
|
61
|
+
if (this._deps.getAllowCopy()) {
|
|
62
|
+
this._copyWithHeaders = value;
|
|
63
|
+
this._deps.persistSettings();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
/** Toggles CSV vs TSV copy-to-clipboard separator and persists. */
|
|
67
|
+
setCommaSeparatedCopy = (value) => {
|
|
68
|
+
if (this._deps.getAllowCopy()) {
|
|
69
|
+
this._commaSeparatedCopy = value;
|
|
70
|
+
this._deps.persistSettings();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
// -------- public clipboard writers ---------------------------------
|
|
74
|
+
/** Copies the highlighted rows to the OS clipboard as TSV / CSV. */
|
|
75
|
+
copyHighlightedRowsToClipboard = async () => {
|
|
76
|
+
// `navigator.clipboard` is undefined in non-HTTPS contexts. The lint
|
|
77
|
+
// rule below is a false-positive in that environment.
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
79
|
+
if (!navigator.clipboard) {
|
|
80
|
+
alert('cannot copy in an insecure connection');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
return this._performRowCopy(await this.getHighlightedRowData());
|
|
84
|
+
};
|
|
85
|
+
/** Copies the currently focused cell range to the OS clipboard. */
|
|
86
|
+
copyDataToClipboard = async () => {
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
88
|
+
if (!navigator.clipboard) {
|
|
89
|
+
alert('cannot copy in an insecure connection');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
return this._performRowCopy(await this.getFocusElementData());
|
|
93
|
+
};
|
|
94
|
+
// -------- internals ------------------------------------------------
|
|
95
|
+
/**
|
|
96
|
+
* Predicate determining whether a column contributes a text value to
|
|
97
|
+
* the clipboard payload. Hidden columns and structural / custom kinds
|
|
98
|
+
* are excluded; row-selection survives because it's serialised below.
|
|
99
|
+
*/
|
|
100
|
+
columnDefReturnsTextValue = (it) => {
|
|
101
|
+
return ('index' in it &&
|
|
102
|
+
this._deps.getColumnVisibility()[it.id] !== false &&
|
|
103
|
+
!uncopyableColumns.has(it.columnType));
|
|
104
|
+
};
|
|
105
|
+
async getHighlightedRowData() {
|
|
106
|
+
const affectedColumns = this._deps
|
|
107
|
+
.getColumnDefs()
|
|
108
|
+
.filter((d) => this.columnDefReturnsTextValue(d));
|
|
109
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
110
|
+
const indices = new Map();
|
|
111
|
+
const selectedRows = [...this._deps.getHighlightedItems().values()];
|
|
112
|
+
const sortedData = this._deps.getSortedData();
|
|
113
|
+
for (const item of selectedRows) {
|
|
114
|
+
const rowIndex = sortedData.indexOf(item);
|
|
115
|
+
if (rowIndex === -1) {
|
|
116
|
+
if (dev) {
|
|
117
|
+
console.warn('row index for highlighted row data not found');
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
indices.set(item, rowIndex);
|
|
122
|
+
}
|
|
123
|
+
selectedRows.sort((left, right) => (indices.get(left) ?? -1) - (indices.get(right) ?? -1));
|
|
124
|
+
const selectedCells = await this._readCellsFromRows(selectedRows, affectedColumns, sortedData);
|
|
125
|
+
return {
|
|
126
|
+
items: selectedRows,
|
|
127
|
+
indicesByItem: indices,
|
|
128
|
+
focusedElementData: selectedCells,
|
|
129
|
+
affectedColumns,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
async getFocusElementData() {
|
|
133
|
+
const focusStart = this._deps.getFocusStart();
|
|
134
|
+
const focusEnd = this._deps.getFocusEnd();
|
|
135
|
+
if (!focusStart || !focusEnd) {
|
|
136
|
+
return {
|
|
137
|
+
items: [],
|
|
138
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
139
|
+
indicesByItem: new Map(),
|
|
140
|
+
focusedElementData: [],
|
|
141
|
+
affectedColumns: [],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const { row: startRowIndexId } = focusStart;
|
|
145
|
+
const { row: endRowIndexId } = focusEnd;
|
|
146
|
+
const model = this._deps.getPaginationRowModel();
|
|
147
|
+
const startRowIndex = model.rows.findIndex((row) => row.visibleIndex === startRowIndexId);
|
|
148
|
+
const endRowIndex = model.rows.findIndex((row) => row.visibleIndex === endRowIndexId);
|
|
149
|
+
if (!this._deps.getCurrentPageData().length || startRowIndex === -1 || endRowIndex === -1) {
|
|
150
|
+
throw new Error(`copy was missing one of the two indices. First: ${startRowIndex.toString()}, second: ${endRowIndex.toString()}`);
|
|
151
|
+
}
|
|
152
|
+
const minRowIndex = Math.min(startRowIndex, endRowIndex);
|
|
153
|
+
const maxRowIndex = Math.max(startRowIndex, endRowIndex);
|
|
154
|
+
const startVisualIndex = this._deps.columnVisualIndex(focusStart.id);
|
|
155
|
+
const endVisualIndex = this._deps.columnVisualIndex(focusEnd.id);
|
|
156
|
+
const minVisualIndex = Math.min(startVisualIndex, endVisualIndex);
|
|
157
|
+
const maxVisualIndex = Math.max(startVisualIndex, endVisualIndex);
|
|
158
|
+
const affectedColumns = this._deps
|
|
159
|
+
.getVisualColumns()
|
|
160
|
+
.slice(minVisualIndex, maxVisualIndex + 1)
|
|
161
|
+
.filter((it) => this.columnDefReturnsTextValue(it));
|
|
162
|
+
const selectedRows = [];
|
|
163
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
164
|
+
const indices = new Map();
|
|
165
|
+
for (let i = minRowIndex; i <= maxRowIndex; i++) {
|
|
166
|
+
const row = model.rows[i];
|
|
167
|
+
selectedRows.push(row.original);
|
|
168
|
+
indices.set(row.original, row.originalIndex);
|
|
169
|
+
}
|
|
170
|
+
const sortedData = this._deps.getSortedData();
|
|
171
|
+
const selectedCells = await this._readCellsFromRows(selectedRows, affectedColumns, sortedData);
|
|
172
|
+
return {
|
|
173
|
+
items: selectedRows,
|
|
174
|
+
indicesByItem: indices,
|
|
175
|
+
focusedElementData: selectedCells,
|
|
176
|
+
affectedColumns,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Walk `rows` × `columns` and produce the inner 2D string buffer used
|
|
181
|
+
* by `_performRowCopy`. Factored out so the highlighted-rows and
|
|
182
|
+
* focus-range serialisers share their cell-reading logic verbatim
|
|
183
|
+
* (the two paths diverged historically only in how they picked which
|
|
184
|
+
* rows / which columns to include).
|
|
185
|
+
*/
|
|
186
|
+
async _readCellsFromRows(rows, columns, sortedData) {
|
|
187
|
+
const cells = [];
|
|
188
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
189
|
+
const item = rows[rowIndex];
|
|
190
|
+
const rawKey = this._deps.cachedKey(item);
|
|
191
|
+
const key = rawKey instanceof Promise ? await rawKey : rawKey;
|
|
192
|
+
cells[rowIndex] = [];
|
|
193
|
+
const targetRow = cells[rowIndex];
|
|
194
|
+
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
|
|
195
|
+
const columnDef = columns[colIndex];
|
|
196
|
+
if (columnDef instanceof RowSelectionDef) {
|
|
197
|
+
targetRow.push(this._deps.getSelectedItems().has(key) ? 'true' : 'false');
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (uncopyableColumns.has(columnDef.columnType)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const x = (await columnDef.getDisplayValue?.(item, sortedData.lastIndexOf(item))) ||
|
|
204
|
+
('accessorFn' in columnDef &&
|
|
205
|
+
(await columnDef.accessorFn?.(item, sortedData.indexOf(item))));
|
|
206
|
+
if (x && typeof x === 'string') {
|
|
207
|
+
targetRow.push(x);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (x && Array.isArray(x) && typeof x[0] === 'string') {
|
|
211
|
+
targetRow.push(x.join(', '));
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const toCopy = columnDef.id && columnDef.id in item
|
|
215
|
+
? item[columnDef.id]
|
|
216
|
+
: null;
|
|
217
|
+
const y = toCopy && typeof toCopy === 'object' && toCopy instanceof Date
|
|
218
|
+
? toCopy.toLocaleDateString()
|
|
219
|
+
: (toCopy?.toString() ?? '');
|
|
220
|
+
targetRow.push(y);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return cells;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Final serialisation step. Resolves `SelectDef` option labels for any
|
|
227
|
+
* affected select columns, picks the configured separator, encapsulates
|
|
228
|
+
* each cell, and writes the final string to the OS clipboard. Single-cell
|
|
229
|
+
* copies bypass TSV wrapping but still pass through
|
|
230
|
+
* `escapeForSpreadsheet` so a pasted formula payload can't execute.
|
|
231
|
+
*/
|
|
232
|
+
_performRowCopy = async ({ items, indicesByItem, focusedElementData, affectedColumns, }) => {
|
|
233
|
+
const focusedColumnIds = affectedColumns.map((it) => encapsulate(typeof it.header === 'string' ? it.header : it.id));
|
|
234
|
+
const value = await (async () => {
|
|
235
|
+
// Resolve per-row option sets for SelectDef columns; iterates
|
|
236
|
+
// in reverse so the last value wins when a row maps to
|
|
237
|
+
// multiple SelectOption sources via `getSpecificOptions`.
|
|
238
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
239
|
+
const selectColumns = new Map();
|
|
240
|
+
for (let i = affectedColumns.length - 1; i > -1; i--) {
|
|
241
|
+
const columnDef = affectedColumns[i];
|
|
242
|
+
if (columnDef instanceof SelectDef) {
|
|
243
|
+
const item = items[i];
|
|
244
|
+
const defOptions = indicesByItem.get(item);
|
|
245
|
+
selectColumns.set(i, await (defOptions
|
|
246
|
+
? (columnDef.getSpecificOptions?.(item, defOptions) ?? columnDef.getOptions())
|
|
247
|
+
: columnDef.getOptions()));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const separator = this._commaSeparatedCopy ? ',' : '\t';
|
|
251
|
+
const shouldCopyHeaders = this._copyWithHeaders &&
|
|
252
|
+
(focusedElementData.length !== 1 || focusedElementData[0].length !== 1);
|
|
253
|
+
if (focusedElementData.length === 1 && focusedElementData[0].length === 1) {
|
|
254
|
+
// Single-cell copy: skip TSV/CSV wrapping but still escape
|
|
255
|
+
// formula-injection prefixes ('=', '+', '-', '@', '\t', '\r').
|
|
256
|
+
if (selectColumns.has(0)) {
|
|
257
|
+
const columnOptions = selectColumns.get(0);
|
|
258
|
+
const v = columnOptions?.find((it) => it.value === focusedElementData[0][0])?.label ??
|
|
259
|
+
focusedElementData[0][0]?.toString() ??
|
|
260
|
+
'';
|
|
261
|
+
return escapeForSpreadsheet(v);
|
|
262
|
+
}
|
|
263
|
+
const v = focusedElementData[0][0]?.toString().trim() ?? '';
|
|
264
|
+
return escapeForSpreadsheet(v);
|
|
265
|
+
}
|
|
266
|
+
return `${shouldCopyHeaders ? `${focusedColumnIds.join(separator)}\n` : ''}${focusedElementData
|
|
267
|
+
.map((it) => it
|
|
268
|
+
.map((toCopy, i) => {
|
|
269
|
+
if (toCopy instanceof Date) {
|
|
270
|
+
return toCopy.toLocaleDateString();
|
|
271
|
+
}
|
|
272
|
+
if (selectColumns.has(i)) {
|
|
273
|
+
const columnOptions = selectColumns.get(i);
|
|
274
|
+
if (dev && !columnOptions) {
|
|
275
|
+
console.warn(`could not find column with index ${i.toString()}`);
|
|
276
|
+
}
|
|
277
|
+
const v = columnOptions?.find((it) => it.value === toCopy)?.label ??
|
|
278
|
+
toCopy?.toString() ??
|
|
279
|
+
'';
|
|
280
|
+
return encapsulate(v);
|
|
281
|
+
}
|
|
282
|
+
const v = toCopy?.toString().trim() ?? '';
|
|
283
|
+
return encapsulate(v);
|
|
284
|
+
})
|
|
285
|
+
.join(separator))
|
|
286
|
+
.join('\n')}`;
|
|
287
|
+
})();
|
|
288
|
+
navigator.clipboard.writeText(value).catch(devCatch);
|
|
289
|
+
};
|
|
290
|
+
}
|
|
@@ -17,36 +17,18 @@ export interface ColumnLayoutStateDeps {
|
|
|
17
17
|
getDebug: () => boolean;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
* column-layout concern previously held directly on `TableContext`:
|
|
20
|
+
* Sub-context owning column-layout state:
|
|
22
21
|
*
|
|
23
|
-
* - `columnDefs` (
|
|
24
|
-
* - `columnDefsById` (`$derived` id->def lookup
|
|
22
|
+
* - `columnDefs` (ordered column definitions);
|
|
23
|
+
* - `columnDefsById` (`$derived` id->def lookup);
|
|
25
24
|
* - `columnPinning` / `columnSizing` / `columnVisibility` (the three
|
|
26
|
-
* per-column maps
|
|
27
|
-
* - `_visualColumns` and `_visualColumnIndexById` (
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* - `
|
|
32
|
-
* - `setColumnPinning(updater)` (delegating writer that respects the
|
|
25
|
+
* per-column maps mutated through public setters);
|
|
26
|
+
* - `_visualColumns` and `_visualColumnIndexById` (cached visual order
|
|
27
|
+
* plus the paired `Map<id, VisualColumnIndex>` so
|
|
28
|
+
* `columnVisualIndex` is O(1));
|
|
29
|
+
* - `columnVisualIndex(id)` (public lookup);
|
|
30
|
+
* - `setColumnPinning(updater)` (writer that respects the
|
|
33
31
|
* `allowColumnReordering` master gate).
|
|
34
|
-
*
|
|
35
|
-
* `TableContext` retains delegating getters / setters / methods for
|
|
36
|
-
* every legacy surface (`columnDefs`, `columnPinning`, `columnSizing`,
|
|
37
|
-
* `columnVisibility`, `columnDefsById`, `columnVisualIndex`,
|
|
38
|
-
* `_visualColumns`, `setColumnPinning`, etc.) so existing consumers
|
|
39
|
-
* need no migration. Future consumers can read `tableContext._columnLayout`
|
|
40
|
-
* directly once the migration is complete (see
|
|
41
|
-
* `src/stories/Concepts/TableContext-decomposition.mdx`).
|
|
42
|
-
*
|
|
43
|
-
* The `focusStartVisualColumn` / `focusEndVisualColumn` getters straddle
|
|
44
|
-
* column-layout and focus; the column-layout-side calculation
|
|
45
|
-
* (`columnVisualIndex` lookup) lives here, but the focus-side state
|
|
46
|
-
* (`focusStart`, `focusEnd`) stays on `TableContext` until the Phase 6.6
|
|
47
|
-
* `FocusState` extraction. The parent's `focusStartVisualColumn` getter
|
|
48
|
-
* therefore reads `this.focusStart?.id` and calls
|
|
49
|
-
* `this._columnLayout.columnVisualIndex(...)`.
|
|
50
32
|
*/
|
|
51
33
|
export declare class ColumnLayoutState<T extends object> {
|
|
52
34
|
private readonly _deps;
|
|
@@ -114,17 +96,10 @@ export declare class ColumnLayoutState<T extends object> {
|
|
|
114
96
|
* pinned-right, preserving memory order within each section.
|
|
115
97
|
* Excludes columns whose visibility is explicitly `false`.
|
|
116
98
|
*
|
|
117
|
-
* Cached as a `$derived`
|
|
118
|
-
* `columnVisibility`, or `columnPinning` change)
|
|
119
|
-
*
|
|
120
|
-
* O(
|
|
121
|
-
* paired `_visualColumnIndexById` below for the O(1) reverse-lookup
|
|
122
|
-
* map.
|
|
123
|
-
*
|
|
124
|
-
* Made `public` (with the underscore prefix preserved) so the
|
|
125
|
-
* parent `TableContext` can delegate its legacy `_visualColumns`
|
|
126
|
-
* field. Future consumers should read
|
|
127
|
-
* `tableContext._columnLayout.visualColumns` directly.
|
|
99
|
+
* Cached as a `$derived` (rebuilds only when `columnDefs`,
|
|
100
|
+
* `columnVisibility`, or `columnPinning` change) to avoid the
|
|
101
|
+
* O(columns) filter cost on every focus-arrow keystroke; see
|
|
102
|
+
* `_visualColumnIndexById` for the O(1) reverse-lookup map.
|
|
128
103
|
*/
|
|
129
104
|
readonly visualColumns: Array<ColumnDef<T>>;
|
|
130
105
|
/**
|
|
@@ -142,10 +117,9 @@ export declare class ColumnLayoutState<T extends object> {
|
|
|
142
117
|
*/
|
|
143
118
|
columnVisualIndex(id: string): VisualColumnIndex;
|
|
144
119
|
/**
|
|
145
|
-
*
|
|
120
|
+
* Apply an updater to the column-pinning state (left / right
|
|
146
121
|
* pins). No-op when column reordering is disabled at the table
|
|
147
|
-
* level.
|
|
148
|
-
* `TableContext.setColumnPinning` writer verbatim.
|
|
122
|
+
* level.
|
|
149
123
|
*/
|
|
150
124
|
readonly setColumnPinning: (updater: (state: ColumnPinningState) => ColumnPinningState) => void;
|
|
151
125
|
/**
|
|
@@ -163,11 +137,9 @@ export declare class ColumnLayoutState<T extends object> {
|
|
|
163
137
|
*/
|
|
164
138
|
readonly updateDefsBasedOnPinning: () => Array<ColumnDef<T>>;
|
|
165
139
|
/**
|
|
166
|
-
* Re-
|
|
140
|
+
* Re-publish the column-pinning map so its left / right entries
|
|
167
141
|
* are keyed by the current `columnDefs` ordering. Used by the
|
|
168
|
-
* parent's drag-drop and `moveColumnTo` flows after a reorder
|
|
169
|
-
* operation; preserves the pre-extraction
|
|
170
|
-
* `TableContext._setNewPinningState` contract verbatim.
|
|
142
|
+
* parent's drag-drop and `moveColumnTo` flows after a reorder.
|
|
171
143
|
*/
|
|
172
144
|
readonly setNewPinningState: () => void;
|
|
173
145
|
}
|
|
@@ -1,34 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* column-layout concern previously held directly on `TableContext`:
|
|
2
|
+
* Sub-context owning column-layout state:
|
|
4
3
|
*
|
|
5
|
-
* - `columnDefs` (
|
|
6
|
-
* - `columnDefsById` (`$derived` id->def lookup
|
|
4
|
+
* - `columnDefs` (ordered column definitions);
|
|
5
|
+
* - `columnDefsById` (`$derived` id->def lookup);
|
|
7
6
|
* - `columnPinning` / `columnSizing` / `columnVisibility` (the three
|
|
8
|
-
* per-column maps
|
|
9
|
-
* - `_visualColumns` and `_visualColumnIndexById` (
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - `
|
|
14
|
-
* - `setColumnPinning(updater)` (delegating writer that respects the
|
|
7
|
+
* per-column maps mutated through public setters);
|
|
8
|
+
* - `_visualColumns` and `_visualColumnIndexById` (cached visual order
|
|
9
|
+
* plus the paired `Map<id, VisualColumnIndex>` so
|
|
10
|
+
* `columnVisualIndex` is O(1));
|
|
11
|
+
* - `columnVisualIndex(id)` (public lookup);
|
|
12
|
+
* - `setColumnPinning(updater)` (writer that respects the
|
|
15
13
|
* `allowColumnReordering` master gate).
|
|
16
|
-
*
|
|
17
|
-
* `TableContext` retains delegating getters / setters / methods for
|
|
18
|
-
* every legacy surface (`columnDefs`, `columnPinning`, `columnSizing`,
|
|
19
|
-
* `columnVisibility`, `columnDefsById`, `columnVisualIndex`,
|
|
20
|
-
* `_visualColumns`, `setColumnPinning`, etc.) so existing consumers
|
|
21
|
-
* need no migration. Future consumers can read `tableContext._columnLayout`
|
|
22
|
-
* directly once the migration is complete (see
|
|
23
|
-
* `src/stories/Concepts/TableContext-decomposition.mdx`).
|
|
24
|
-
*
|
|
25
|
-
* The `focusStartVisualColumn` / `focusEndVisualColumn` getters straddle
|
|
26
|
-
* column-layout and focus; the column-layout-side calculation
|
|
27
|
-
* (`columnVisualIndex` lookup) lives here, but the focus-side state
|
|
28
|
-
* (`focusStart`, `focusEnd`) stays on `TableContext` until the Phase 6.6
|
|
29
|
-
* `FocusState` extraction. The parent's `focusStartVisualColumn` getter
|
|
30
|
-
* therefore reads `this.focusStart?.id` and calls
|
|
31
|
-
* `this._columnLayout.columnVisualIndex(...)`.
|
|
32
14
|
*/
|
|
33
15
|
export class ColumnLayoutState {
|
|
34
16
|
_deps;
|
|
@@ -116,17 +98,10 @@ export class ColumnLayoutState {
|
|
|
116
98
|
* pinned-right, preserving memory order within each section.
|
|
117
99
|
* Excludes columns whose visibility is explicitly `false`.
|
|
118
100
|
*
|
|
119
|
-
* Cached as a `$derived`
|
|
120
|
-
* `columnVisibility`, or `columnPinning` change)
|
|
121
|
-
*
|
|
122
|
-
* O(
|
|
123
|
-
* paired `_visualColumnIndexById` below for the O(1) reverse-lookup
|
|
124
|
-
* map.
|
|
125
|
-
*
|
|
126
|
-
* Made `public` (with the underscore prefix preserved) so the
|
|
127
|
-
* parent `TableContext` can delegate its legacy `_visualColumns`
|
|
128
|
-
* field. Future consumers should read
|
|
129
|
-
* `tableContext._columnLayout.visualColumns` directly.
|
|
101
|
+
* Cached as a `$derived` (rebuilds only when `columnDefs`,
|
|
102
|
+
* `columnVisibility`, or `columnPinning` change) to avoid the
|
|
103
|
+
* O(columns) filter cost on every focus-arrow keystroke; see
|
|
104
|
+
* `_visualColumnIndexById` for the O(1) reverse-lookup map.
|
|
130
105
|
*/
|
|
131
106
|
visualColumns = $derived.by(() => {
|
|
132
107
|
const visibility = this._columnVisibility;
|
|
@@ -164,10 +139,9 @@ export class ColumnLayoutState {
|
|
|
164
139
|
return this.visualColumnIndexById.get(id) ?? -1;
|
|
165
140
|
}
|
|
166
141
|
/**
|
|
167
|
-
*
|
|
142
|
+
* Apply an updater to the column-pinning state (left / right
|
|
168
143
|
* pins). No-op when column reordering is disabled at the table
|
|
169
|
-
* level.
|
|
170
|
-
* `TableContext.setColumnPinning` writer verbatim.
|
|
144
|
+
* level.
|
|
171
145
|
*/
|
|
172
146
|
setColumnPinning = (updater) => {
|
|
173
147
|
if (!this._deps.getAllowColumnReordering()) {
|
|
@@ -216,11 +190,9 @@ export class ColumnLayoutState {
|
|
|
216
190
|
return allDefs;
|
|
217
191
|
};
|
|
218
192
|
/**
|
|
219
|
-
* Re-
|
|
193
|
+
* Re-publish the column-pinning map so its left / right entries
|
|
220
194
|
* are keyed by the current `columnDefs` ordering. Used by the
|
|
221
|
-
* parent's drag-drop and `moveColumnTo` flows after a reorder
|
|
222
|
-
* operation; preserves the pre-extraction
|
|
223
|
-
* `TableContext._setNewPinningState` contract verbatim.
|
|
195
|
+
* parent's drag-drop and `moveColumnTo` flows after a reorder.
|
|
224
196
|
*/
|
|
225
197
|
setNewPinningState = () => {
|
|
226
198
|
this._columnPinning = {
|
|
@@ -40,19 +40,10 @@ export interface FilteringStateDeps<T extends object> {
|
|
|
40
40
|
getDebug: () => boolean;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* slot, and the `updateFilters` `OnChangeFn` slot.
|
|
48
|
-
*
|
|
49
|
-
* `TableContext` retains delegating getters / setters for every legacy
|
|
50
|
-
* surface (`filteredIndices`, `filteredData`, `showQuickFiltering`,
|
|
51
|
-
* `showSelectedOnly`, `remoteFilters`, `dateFilter`, `numberFilter`,
|
|
52
|
-
* `selectFilter`, `boolFilter`, `stringFilter`, `updateFilters`); future
|
|
53
|
-
* consumers can read `tableContext._filtering` directly once the
|
|
54
|
-
* migration completes (see
|
|
55
|
-
* `src/stories/Concepts/TableContext-decomposition.mdx`).
|
|
43
|
+
* Sub-context owning filtering-related state: relayed per-type
|
|
44
|
+
* `FilterFn` derived values, the `filteredData` `$derived` chain, the
|
|
45
|
+
* user-facing toggle flags (`showQuickFiltering`, `showSelectedOnly`),
|
|
46
|
+
* the remote-filter slot, and the `updateFilters` `OnChangeFn` slot.
|
|
56
47
|
*/
|
|
57
48
|
export declare class FilteringState<T extends object> {
|
|
58
49
|
private readonly _deps;
|
|
@@ -87,10 +78,9 @@ export declare class FilteringState<T extends object> {
|
|
|
87
78
|
setFilteredIndices(indices: ReadonlyArray<number>): void;
|
|
88
79
|
/**
|
|
89
80
|
* Whether the quick-filter row is currently visible. The setter
|
|
90
|
-
* enforces the `allowQuickFiltering` gate
|
|
91
|
-
*
|
|
92
|
-
* a
|
|
93
|
-
* `TableContext.showQuickFiltering` setter verbatim.
|
|
81
|
+
* enforces the `allowQuickFiltering` master gate: when quick
|
|
82
|
+
* filtering is disabled at the table level, the setter is a no-op
|
|
83
|
+
* (with a debug log).
|
|
94
84
|
*/
|
|
95
85
|
get showQuickFiltering(): boolean;
|
|
96
86
|
set showQuickFiltering(v: boolean);
|
|
@@ -158,9 +148,8 @@ export declare class FilteringState<T extends object> {
|
|
|
158
148
|
*
|
|
159
149
|
* Reactivity note: `selectedItems` is intentionally NOT touched
|
|
160
150
|
* outside the `showSelectedOnly` branches. Reading it unconditionally
|
|
161
|
-
* would invalidate `filteredData`
|
|
162
|
-
*
|
|
163
|
-
* during Phase-5 Group 2).
|
|
151
|
+
* would invalidate `filteredData` -> `sortedData` ->
|
|
152
|
+
* `currentPageData` -> the entire row model on every single toggle.
|
|
164
153
|
*/
|
|
165
154
|
readonly filteredData: T[];
|
|
166
155
|
}
|