@perspective-dev/viewer-datagrid 4.4.0 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cdn/perspective-viewer-datagrid.js +4 -22
  2. package/dist/cdn/perspective-viewer-datagrid.js.map +4 -4
  3. package/dist/css/perspective-viewer-datagrid-toolbar.css +1 -1
  4. package/dist/css/perspective-viewer-datagrid.css +1 -1
  5. package/dist/esm/color_utils.d.ts +22 -0
  6. package/dist/esm/custom_elements/datagrid.d.ts +5 -5
  7. package/dist/esm/data_listener/format_cell.d.ts +1 -1
  8. package/dist/esm/data_listener/formatter_cache.d.ts +1 -1
  9. package/dist/esm/data_listener/index.d.ts +3 -2
  10. package/dist/esm/event_handlers/click/edit_click.d.ts +3 -2
  11. package/dist/esm/event_handlers/click.d.ts +4 -6
  12. package/dist/esm/event_handlers/dispatch_click.d.ts +3 -2
  13. package/dist/esm/event_handlers/expand_collapse.d.ts +1 -1
  14. package/dist/esm/event_handlers/focus.d.ts +4 -5
  15. package/dist/esm/event_handlers/header_click.d.ts +5 -3
  16. package/dist/esm/event_handlers/keydown/edit_keydown.d.ts +3 -4
  17. package/dist/esm/event_handlers/select_region.d.ts +3 -1
  18. package/dist/esm/event_handlers/sort.d.ts +8 -7
  19. package/dist/esm/model/create.d.ts +1 -1
  20. package/dist/esm/perspective-viewer-datagrid.js +3 -3
  21. package/dist/esm/perspective-viewer-datagrid.js.map +4 -4
  22. package/dist/esm/plugin/activate.d.ts +1 -1
  23. package/dist/esm/plugin/column_style_controls.d.ts +1 -1
  24. package/dist/esm/style_handlers/body.d.ts +3 -3
  25. package/dist/esm/style_handlers/column_header.d.ts +4 -3
  26. package/dist/esm/style_handlers/consolidated.d.ts +3 -47
  27. package/dist/esm/style_handlers/editable.d.ts +3 -2
  28. package/dist/esm/style_handlers/focus.d.ts +4 -4
  29. package/dist/esm/style_handlers/group_header.d.ts +1 -1
  30. package/dist/esm/style_handlers/table_cell/boolean.d.ts +1 -1
  31. package/dist/esm/style_handlers/table_cell/cell_flash.d.ts +1 -1
  32. package/dist/esm/style_handlers/table_cell/datetime.d.ts +1 -1
  33. package/dist/esm/style_handlers/table_cell/numeric.d.ts +1 -1
  34. package/dist/esm/style_handlers/table_cell/row_header.d.ts +1 -1
  35. package/dist/esm/style_handlers/table_cell/string.d.ts +1 -1
  36. package/dist/esm/style_handlers/types.d.ts +0 -4
  37. package/dist/esm/types.d.ts +10 -17
  38. package/package.json +2 -4
  39. package/src/css/regular_table.css +87 -31
  40. package/src/css/row-hover.css +20 -7
  41. package/src/css/toolbar.css +11 -0
  42. package/src/ts/color_utils.ts +144 -16
  43. package/src/ts/custom_elements/datagrid.ts +11 -12
  44. package/src/ts/custom_elements/toolbar.ts +4 -5
  45. package/src/ts/data_listener/format_cell.ts +28 -9
  46. package/src/ts/data_listener/formatter_cache.ts +1 -1
  47. package/src/ts/data_listener/index.ts +4 -8
  48. package/src/ts/event_handlers/click/edit_click.ts +7 -6
  49. package/src/ts/event_handlers/click.ts +39 -68
  50. package/src/ts/event_handlers/dispatch_click.ts +24 -25
  51. package/src/ts/event_handlers/expand_collapse.ts +7 -7
  52. package/src/ts/event_handlers/focus.ts +38 -35
  53. package/src/ts/event_handlers/header_click.ts +101 -62
  54. package/src/ts/event_handlers/keydown/edit_keydown.ts +49 -52
  55. package/src/ts/event_handlers/select_region.ts +144 -133
  56. package/src/ts/event_handlers/sort.ts +16 -24
  57. package/src/ts/model/column_overrides.ts +13 -4
  58. package/src/ts/model/create.ts +51 -55
  59. package/src/ts/model/toolbar.ts +23 -7
  60. package/src/ts/plugin/activate.ts +120 -92
  61. package/src/ts/plugin/column_style_controls.ts +1 -1
  62. package/src/ts/plugin/save.ts +1 -0
  63. package/src/ts/style_handlers/body.ts +44 -51
  64. package/src/ts/style_handlers/column_header.ts +16 -19
  65. package/src/ts/style_handlers/consolidated.ts +22 -123
  66. package/src/ts/style_handlers/editable.ts +10 -8
  67. package/src/ts/style_handlers/focus.ts +5 -5
  68. package/src/ts/style_handlers/group_header.ts +3 -2
  69. package/src/ts/style_handlers/table_cell/boolean.ts +3 -3
  70. package/src/ts/style_handlers/table_cell/cell_flash.ts +11 -11
  71. package/src/ts/style_handlers/table_cell/datetime.ts +3 -3
  72. package/src/ts/style_handlers/table_cell/numeric.ts +24 -25
  73. package/src/ts/style_handlers/table_cell/row_header.ts +2 -2
  74. package/src/ts/style_handlers/table_cell/string.ts +20 -18
  75. package/src/ts/style_handlers/types.ts +0 -10
  76. package/src/ts/types.ts +28 -20
  77. package/dist/esm/event_handlers/deselect_all.d.ts +0 -5
  78. package/dist/esm/event_handlers/row_select_click.d.ts +0 -4
  79. package/src/ts/event_handlers/deselect_all.ts +0 -28
  80. package/src/ts/event_handlers/row_select_click.ts +0 -92
@@ -13,16 +13,24 @@
13
13
  import { RegularTableElement } from "regular-table";
14
14
  import type {
15
15
  DatagridPluginElement,
16
- PerspectiveViewerElement,
16
+ EditMode,
17
17
  SelectionArea,
18
18
  } from "../types.js";
19
- import { ViewWindow } from "@perspective-dev/client";
19
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
20
+ import type { ViewWindow } from "@perspective-dev/client";
21
+ import type { CellMetadataBody } from "regular-table/dist/esm/types.js";
20
22
 
21
23
  const MOUSE_SELECTED_AREA_CLASS = "mouse-selected-area";
22
24
 
25
+ export type OnSelectCallback = (
26
+ area: SelectionArea,
27
+ isDeselect: boolean,
28
+ ) => void;
29
+
23
30
  interface AddAreaMouseSelectionOptions {
24
31
  className?: string;
25
32
  selected?: SelectionArea[];
33
+ onSelect?: OnSelectCallback;
26
34
  }
27
35
 
28
36
  export const addAreaMouseSelection = (
@@ -31,6 +39,7 @@ export const addAreaMouseSelection = (
31
39
  {
32
40
  className = MOUSE_SELECTED_AREA_CLASS,
33
41
  selected = [],
42
+ onSelect,
34
43
  }: AddAreaMouseSelectionOptions = {},
35
44
  ): RegularTableElement => {
36
45
  datagrid.model!._selection_state = {
@@ -50,7 +59,7 @@ export const addAreaMouseSelection = (
50
59
 
51
60
  table.addEventListener(
52
61
  "mouseup",
53
- getMouseupListener(datagrid, table, className),
62
+ getMouseupListener(datagrid, table, className, onSelect),
54
63
  );
55
64
 
56
65
  table.addStyleListener(() =>
@@ -60,6 +69,10 @@ export const addAreaMouseSelection = (
60
69
  return table;
61
70
  };
62
71
 
72
+ function isSingleClickMode(mode: EditMode): boolean {
73
+ return mode === "SELECT_ROW_TREE";
74
+ }
75
+
63
76
  const getMousedownListener =
64
77
  (
65
78
  datagrid: DatagridPluginElement,
@@ -70,10 +83,9 @@ const getMousedownListener =
70
83
  const mouseEvent = event as MouseEvent;
71
84
  if (
72
85
  mouseEvent.button === 0 &&
73
- (datagrid.model!._edit_mode === "SELECT_REGION" ||
74
- datagrid.model!._edit_mode === "SELECT_ROW" ||
75
- datagrid.model!._edit_mode === "SELECT_COLUMN")
86
+ isSelectionMode(datagrid.model!._edit_mode)
76
87
  ) {
88
+ if (isSingleClickMode(datagrid.model!._edit_mode)) return;
77
89
  datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES = {};
78
90
  const meta = table.getMeta(mouseEvent.target as HTMLElement);
79
91
  if (
@@ -122,11 +134,8 @@ const getMouseoverListener =
122
134
  ) =>
123
135
  (event: Event): void => {
124
136
  const mouseEvent = event as MouseEvent;
125
- if (
126
- datagrid.model!._edit_mode === "SELECT_REGION" ||
127
- datagrid.model!._edit_mode === "SELECT_ROW" ||
128
- datagrid.model!._edit_mode === "SELECT_COLUMN"
129
- ) {
137
+ const mode = datagrid.model!._edit_mode;
138
+ if (isSelectionMode(mode) && !isSingleClickMode(mode)) {
130
139
  if (
131
140
  datagrid.model!._selection_state
132
141
  .CURRENT_MOUSEDOWN_COORDINATES &&
@@ -183,17 +192,63 @@ const getMouseupListener =
183
192
  datagrid: DatagridPluginElement,
184
193
  table: RegularTableElement,
185
194
  className: string,
195
+ onSelect?: OnSelectCallback,
186
196
  ) =>
187
197
  (event: Event): void => {
188
198
  const mouseEvent = event as MouseEvent;
189
- if (
190
- datagrid.model!._edit_mode === "SELECT_REGION" ||
191
- datagrid.model!._edit_mode === "SELECT_ROW" ||
192
- datagrid.model!._edit_mode === "SELECT_COLUMN"
193
- ) {
199
+ const mode = datagrid.model!._edit_mode;
200
+ if (isSelectionMode(mode)) {
194
201
  const meta = table.getMeta(mouseEvent.target as HTMLElement);
195
202
  if (!meta) return;
196
203
 
204
+ // For single-click modes (SELECT_ROW_TREE), handle toggle
205
+ if (isSingleClickMode(mode)) {
206
+ if (
207
+ (meta.type === "body" || meta.type === "row_header") &&
208
+ meta.y !== undefined &&
209
+ meta.y >= 0
210
+ ) {
211
+ const existing =
212
+ datagrid.model!._selection_state.selected_areas;
213
+ const isSameRow =
214
+ existing.length > 0 && existing[0].y0 === meta.y;
215
+
216
+ if (isSameRow) {
217
+ // Deselect
218
+ datagrid.model!._selection_state.selected_areas = [];
219
+ datagrid.model!._selection_state.dirty = true;
220
+ applyMouseAreaSelections(
221
+ datagrid,
222
+ table,
223
+ className,
224
+ [],
225
+ );
226
+ onSelect?.(existing[0], true);
227
+ } else {
228
+ // Select new row
229
+ const area: SelectionArea = {
230
+ x0: 0,
231
+ x1: 0,
232
+ y0: meta.y,
233
+ y1: meta.y,
234
+ };
235
+ datagrid.model!._selection_state.selected_areas = [
236
+ area,
237
+ ];
238
+ datagrid.model!._selection_state.dirty = true;
239
+ applyMouseAreaSelections(datagrid, table, className);
240
+ onSelect?.(area, false);
241
+ }
242
+ }
243
+
244
+ datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES =
245
+ {};
246
+ datagrid.model!._selection_state.potential_selection =
247
+ undefined;
248
+ return;
249
+ }
250
+
251
+ // Drag-based modes (SELECT_ROW, SELECT_COLUMN, SELECT_REGION)
197
252
  if (
198
253
  (datagrid.model!._selection_state.old_selected_areas?.length ??
199
254
  0) > 0
@@ -260,80 +315,103 @@ const getMouseupListener =
260
315
  }
261
316
  };
262
317
 
318
+ function modeIncludesColumns(mode: EditMode): boolean {
319
+ return mode === "SELECT_COLUMN" || mode === "SELECT_REGION";
320
+ }
321
+
322
+ function modeIncludesRows(mode: EditMode): boolean {
323
+ return (
324
+ mode === "SELECT_ROW" ||
325
+ mode === "SELECT_REGION" ||
326
+ mode === "SELECT_ROW_TREE"
327
+ );
328
+ }
329
+
263
330
  function set_psp_selection(
264
- viewer: PerspectiveViewerElement,
331
+ viewer: HTMLPerspectiveViewerElement,
265
332
  datagrid: DatagridPluginElement,
266
333
  { x0, x1, y0, y1 }: SelectionArea,
267
334
  ): void {
268
335
  const viewport: ViewWindow = {};
269
336
  const mode = datagrid.model!._edit_mode;
270
- if (
271
- x0 !== undefined &&
272
- ["SELECT_COLUMN", "SELECT_REGION"].indexOf(mode) > -1
273
- ) {
337
+ if (x0 !== undefined && modeIncludesColumns(mode)) {
274
338
  viewport.start_col = x0;
275
339
  }
276
340
 
277
- if (
278
- x1 !== undefined &&
279
- ["SELECT_COLUMN", "SELECT_REGION"].indexOf(mode) > -1
280
- ) {
341
+ if (x1 !== undefined && modeIncludesColumns(mode)) {
281
342
  viewport.end_col = x1 + 1;
282
343
  }
283
344
 
284
- if (
285
- y0 !== undefined &&
286
- ["SELECT_ROW", "SELECT_REGION"].indexOf(mode) > -1
287
- ) {
345
+ if (y0 !== undefined && modeIncludesRows(mode)) {
288
346
  viewport.start_row = y0;
289
347
  }
290
348
 
291
- if (
292
- y1 !== undefined &&
293
- ["SELECT_ROW", "SELECT_REGION"].indexOf(mode) > -1
294
- ) {
349
+ if (y1 !== undefined && modeIncludesRows(mode)) {
295
350
  viewport.end_row = y1 + 1;
296
351
  }
297
352
 
298
353
  viewer.setSelection(viewport);
299
354
  }
300
355
 
356
+ type CellPredicate = (meta: CellMetadataBody, area: SelectionArea) => boolean;
357
+
358
+ const SELECTION_PREDICATES: Record<string, CellPredicate> = {
359
+ SELECT_REGION: (m, a) =>
360
+ a.x0 <= m.x && m.x <= a.x1 && a.y0 <= m.y && m.y <= a.y1,
361
+ SELECT_ROW: (m, a) => a.y0 <= m.y && m.y <= a.y1,
362
+ SELECT_ROW_TREE: (m, a) => a.y0 <= m.y && m.y <= a.y1,
363
+ SELECT_COLUMN: (m, a) => a.x0 <= m.x && m.x <= a.x1,
364
+ };
365
+
366
+ function isSelectionMode(mode: EditMode): boolean {
367
+ return (
368
+ mode === "SELECT_REGION" ||
369
+ mode === "SELECT_ROW" ||
370
+ mode === "SELECT_COLUMN" ||
371
+ mode === "SELECT_ROW_TREE"
372
+ );
373
+ }
374
+
301
375
  export const applyMouseAreaSelections = (
302
376
  datagrid: DatagridPluginElement,
303
377
  table: RegularTableElement,
304
378
  className: string,
305
379
  selected?: SelectionArea[],
306
380
  ): void => {
307
- if (
308
- datagrid.model!._edit_mode === "SELECT_REGION" ||
309
- datagrid.model!._edit_mode === "SELECT_ROW" ||
310
- datagrid.model!._edit_mode === "SELECT_COLUMN"
311
- ) {
381
+ const mode = datagrid.model!._edit_mode;
382
+ if (isSelectionMode(mode)) {
312
383
  selected = datagrid.model!._selection_state.selected_areas.slice(0);
313
384
  if (datagrid.model!._selection_state.potential_selection) {
314
385
  selected.push(datagrid.model!._selection_state.potential_selection);
315
386
  }
316
387
 
317
- const tds = table.querySelectorAll("tbody td");
318
-
319
388
  if (selected.length > 0) {
320
389
  set_psp_selection(
321
- datagrid.parentElement as any,
390
+ datagrid.parentElement as HTMLPerspectiveViewerElement,
322
391
  datagrid,
323
392
  selected[0],
324
393
  );
325
- applyMouseAreaSelection(datagrid, table, selected, className);
394
+
395
+ // SELECT_ROW_TREE styling is handled entirely by the
396
+ // identity-based system in body.ts, which styles both td
397
+ // and th uniformly in a single draw pass.
398
+ if (!isSingleClickMode(mode)) {
399
+ applyMouseAreaSelection(datagrid, table, selected, className);
400
+ }
326
401
  } else {
327
- (datagrid.parentElement as any).setSelection();
402
+ (
403
+ datagrid.parentElement as HTMLPerspectiveViewerElement
404
+ ).setSelection();
405
+ const tds = table.querySelectorAll("tbody td");
328
406
  for (const td of tds) {
329
407
  td.classList.remove(className);
330
408
  }
331
409
  }
332
410
  } else if (datagrid.model!._selection_state.dirty) {
333
411
  datagrid.model!._selection_state.dirty = false;
334
- const tds = table.querySelectorAll("tbody td");
335
- for (const td of tds) {
336
- td.classList.remove(className);
412
+ const cells = table.querySelectorAll("tbody td, tbody th");
413
+ for (const cell of cells) {
414
+ cell.classList.remove(className);
337
415
  }
338
416
  }
339
417
  };
@@ -344,96 +422,29 @@ const applyMouseAreaSelection = (
344
422
  selected: SelectionArea[],
345
423
  className: string,
346
424
  ): void => {
347
- if (datagrid.model!._edit_mode === "SELECT_REGION" && selected.length > 0) {
348
- const tds = table.querySelectorAll("tbody td");
349
-
350
- for (const td of tds) {
351
- const meta = table.getMeta(td as HTMLElement);
352
- if (!meta || meta.type !== "body") continue;
353
- let rendered = false;
354
- for (const { x0, x1, y0, y1 } of selected) {
355
- if (
356
- x0 !== undefined &&
357
- y0 !== undefined &&
358
- x1 !== undefined &&
359
- y1 !== undefined
360
- ) {
361
- if (
362
- x0 <= meta.x &&
363
- meta.x <= x1 &&
364
- y0 <= meta.y &&
365
- meta.y <= y1
366
- ) {
367
- rendered = true;
368
- datagrid.model!._selection_state.dirty = true;
369
- td.classList.add(className);
370
- }
371
- }
372
- }
373
-
374
- if (!rendered) {
375
- td.classList.remove(className);
376
- }
377
- }
378
- } else if (
379
- datagrid.model!._edit_mode === "SELECT_ROW" &&
380
- selected.length > 0
381
- ) {
382
- const tds = table.querySelectorAll("tbody td");
383
-
384
- for (const td of tds) {
385
- const meta = table.getMeta(td as HTMLElement);
386
- if (!meta) continue;
387
- let rendered = false;
388
- for (const { x0, x1, y0, y1 } of selected) {
389
- if (
390
- x0 !== undefined &&
391
- y0 !== undefined &&
392
- x1 !== undefined &&
393
- y1 !== undefined &&
394
- meta?.type === "body"
395
- ) {
396
- if (y0 <= meta.y && meta.y <= y1) {
397
- datagrid.model!._selection_state.dirty = true;
398
- rendered = true;
399
- td.classList.add(className);
400
- }
401
- }
402
- }
403
-
404
- if (!rendered) {
405
- td.classList.remove(className);
425
+ const predicate = SELECTION_PREDICATES[datagrid.model!._edit_mode];
426
+ if (!predicate || selected.length === 0) return;
427
+ const tds = table.querySelectorAll("tbody td");
428
+ for (const td of tds) {
429
+ const meta = table.getMeta(td as HTMLElement);
430
+ if (!meta || meta.type !== "body") continue;
431
+ let rendered = false;
432
+ for (const area of selected) {
433
+ if (
434
+ area.x0 !== undefined &&
435
+ area.y0 !== undefined &&
436
+ area.x1 !== undefined &&
437
+ area.y1 !== undefined &&
438
+ predicate(meta, area)
439
+ ) {
440
+ rendered = true;
441
+ datagrid.model!._selection_state.dirty = true;
442
+ td.classList.add(className);
406
443
  }
407
444
  }
408
- } else if (
409
- datagrid.model!._edit_mode === "SELECT_COLUMN" &&
410
- selected.length > 0
411
- ) {
412
- const tds = table.querySelectorAll("tbody td");
413
-
414
- for (const td of tds) {
415
- const meta = table.getMeta(td as HTMLElement);
416
- if (!meta) continue;
417
- let rendered = false;
418
- for (const { x0, x1, y0, y1 } of selected) {
419
- if (
420
- x0 !== undefined &&
421
- y0 !== undefined &&
422
- x1 !== undefined &&
423
- y1 !== undefined &&
424
- meta?.type === "body"
425
- ) {
426
- if (x0 <= meta.x && meta.x <= x1) {
427
- datagrid.model!._selection_state.dirty = true;
428
- rendered = true;
429
- td.classList.add(className);
430
- }
431
- }
432
- }
433
445
 
434
- if (!rendered) {
435
- td.classList.remove(className);
436
- }
446
+ if (!rendered) {
447
+ td.classList.remove(className);
437
448
  }
438
449
  }
439
450
  };
@@ -10,14 +10,10 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import { RegularTableElement } from "regular-table";
14
- import type {
15
- DatagridModel,
16
- PerspectiveViewerElement,
17
- SortRotationOrder,
18
- SortTerm,
19
- } from "../types.js";
20
- import { SortDir } from "@perspective-dev/client";
13
+ import type { RegularTableElement } from "regular-table";
14
+ import type { DatagridModel, SortRotationOrder, SortTerm } from "../types.js";
15
+ import type { SortDir } from "@perspective-dev/client";
16
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
21
17
 
22
18
  const ROW_SORT_ORDER: SortRotationOrder = {
23
19
  desc: "asc",
@@ -31,22 +27,18 @@ const ROW_COL_SORT_ORDER: SortRotationOrder = {
31
27
  asc: undefined,
32
28
  "desc abs": "asc abs",
33
29
  "asc abs": undefined,
34
- // "col desc": "col asc",
35
- // "col asc": undefined,
36
- // "col desc abs": "col asc abs",
37
- // "col asc abs": undefined,
38
30
  };
39
31
 
40
32
  export async function sortHandler(
41
- this: DatagridModel,
33
+ model: DatagridModel,
42
34
  regularTable: RegularTableElement,
43
- viewer: PerspectiveViewerElement,
35
+ viewer: HTMLPerspectiveViewerElement,
44
36
  event: MouseEvent,
45
37
  target: HTMLElement,
46
38
  ): Promise<void> {
47
39
  const meta = regularTable.getMeta(target);
48
40
  if (!meta?.column_header) return;
49
- const column_name = meta.column_header[this._config.split_by.length];
41
+ const column_name = meta.column_header[model._config.split_by.length];
50
42
  const sort_method =
51
43
  event.ctrlKey ||
52
44
  (event as MouseEvent & { metaKey?: boolean }).metaKey ||
@@ -55,22 +47,22 @@ export async function sortHandler(
55
47
  : override_sort;
56
48
 
57
49
  const abs = event.shiftKey;
58
- const sort = sort_method.call(this, `${column_name}`, abs);
50
+ const sort = sort_method(model, `${column_name}`, abs);
59
51
  await viewer.restore({ sort });
60
52
  }
61
53
 
62
54
  export function append_sort(
63
- this: DatagridModel,
55
+ model: DatagridModel,
64
56
  column_name: string,
65
57
  abs: boolean,
66
58
  ): SortTerm[] {
67
59
  const sort: SortTerm[] = [];
68
60
  let found = false;
69
- for (const sort_term of this._config.sort) {
61
+ for (const sort_term of model._config.sort) {
70
62
  const [_column_name, _sort_dir] = sort_term;
71
63
  if (_column_name === column_name) {
72
64
  found = true;
73
- const term = create_sort.call(this, column_name, _sort_dir, abs);
65
+ const term = create_sort(model, column_name, _sort_dir, abs);
74
66
  if (term) {
75
67
  sort.push(term);
76
68
  }
@@ -87,13 +79,13 @@ export function append_sort(
87
79
  }
88
80
 
89
81
  export function override_sort(
90
- this: DatagridModel,
82
+ model: DatagridModel,
91
83
  column_name: string,
92
84
  abs: boolean,
93
85
  ): SortTerm[] {
94
- for (const [_column_name, _sort_dir] of this._config.sort) {
86
+ for (const [_column_name, _sort_dir] of model._config.sort) {
95
87
  if (_column_name === column_name) {
96
- const sort = create_sort.call(this, column_name, _sort_dir, abs);
88
+ const sort = create_sort(model, column_name, _sort_dir, abs);
97
89
  return sort ? [sort] : [];
98
90
  }
99
91
  }
@@ -102,12 +94,12 @@ export function override_sort(
102
94
  }
103
95
 
104
96
  export function create_sort(
105
- this: DatagridModel,
97
+ model: DatagridModel,
106
98
  column_name: string,
107
99
  sort_dir: SortDir | undefined,
108
100
  _abs: boolean,
109
101
  ): SortTerm | undefined {
110
- const is_col_sortable = this._config.split_by.length > 0;
102
+ const is_col_sortable = model._config.split_by.length > 0;
111
103
  const order = is_col_sortable ? ROW_COL_SORT_ORDER : ROW_SORT_ORDER;
112
104
  const inc_sort_dir: SortDir | undefined = sort_dir
113
105
  ? order[sort_dir]
@@ -46,7 +46,10 @@ export function restore_column_size_overrides(
46
46
  this._cached_column_sizes = old_sizes;
47
47
  }
48
48
 
49
- const overrides: Record<number, number | undefined> = {};
49
+ const regular_table = this.regular_table as RegularTableWithOverrides;
50
+ const overrides: Record<number, number | undefined> = {
51
+ ...regular_table.saveColumnSizes(),
52
+ };
50
53
  const { group_by } = this.model!._config;
51
54
  const tree_header_offset = group_by?.length > 0 ? group_by.length + 1 : 0;
52
55
 
@@ -57,15 +60,21 @@ export function restore_column_size_overrides(
57
60
  | undefined;
58
61
  } else {
59
62
  const index = this.model!._column_paths.indexOf(key);
63
+ // Skip keys that don't resolve to a known column — e.g. on the
64
+ // first draw after `activate`, `_column_paths` has not yet been
65
+ // populated by the data listener, so we leave any existing
66
+ // `regular-table` widths untouched rather than clobbering them
67
+ // with garbage indices.
68
+ if (index === -1) {
69
+ continue;
70
+ }
60
71
  overrides[index + tree_header_offset] = old_sizes[key] as
61
72
  | number
62
73
  | undefined;
63
74
  }
64
75
  }
65
76
 
66
- (this.regular_table as RegularTableWithOverrides).restoreColumnSizes(
67
- overrides,
68
- );
77
+ regular_table.restoreColumnSizes(overrides);
69
78
  }
70
79
 
71
80
  /**