@perspective-dev/viewer-datagrid 4.1.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/cdn/perspective-viewer-datagrid.js +5 -4
  2. package/dist/cdn/perspective-viewer-datagrid.js.map +4 -4
  3. package/dist/css/perspective-viewer-datagrid.css +1 -1
  4. package/dist/esm/custom_elements/datagrid.d.ts +1 -0
  5. package/dist/esm/data_listener/format_tree_header.d.ts +1 -0
  6. package/dist/esm/event_handlers/click/edit_click.d.ts +1 -1
  7. package/dist/esm/event_handlers/row_select_click.d.ts +1 -1
  8. package/dist/esm/model/create.d.ts +1 -1
  9. package/dist/esm/perspective-viewer-datagrid.js +3 -3
  10. package/dist/esm/perspective-viewer-datagrid.js.map +3 -3
  11. package/dist/esm/style_handlers/body.d.ts +1 -1
  12. package/dist/esm/style_handlers/column_header.d.ts +1 -1
  13. package/dist/esm/style_handlers/consolidated.d.ts +2 -5
  14. package/dist/esm/style_handlers/table_cell/boolean.d.ts +1 -5
  15. package/dist/esm/style_handlers/table_cell/cell_flash.d.ts +2 -2
  16. package/dist/esm/style_handlers/table_cell/datetime.d.ts +1 -5
  17. package/dist/esm/style_handlers/table_cell/row_header.d.ts +2 -2
  18. package/dist/esm/style_handlers/types.d.ts +2 -5
  19. package/dist/esm/types.d.ts +4 -9
  20. package/package.json +3 -3
  21. package/src/less/regular_table.less +39 -22
  22. package/src/ts/color_utils.ts +0 -1
  23. package/src/ts/custom_elements/datagrid.ts +5 -0
  24. package/src/ts/data_listener/format_tree_header.ts +16 -0
  25. package/src/ts/data_listener/index.ts +24 -4
  26. package/src/ts/event_handlers/click/edit_click.ts +13 -10
  27. package/src/ts/event_handlers/dispatch_click.ts +2 -4
  28. package/src/ts/event_handlers/expand_collapse.ts +4 -3
  29. package/src/ts/event_handlers/focus.ts +1 -1
  30. package/src/ts/event_handlers/header_click.ts +1 -1
  31. package/src/ts/event_handlers/keydown/edit_keydown.ts +2 -2
  32. package/src/ts/event_handlers/row_select_click.ts +24 -19
  33. package/src/ts/event_handlers/select_region.ts +23 -11
  34. package/src/ts/event_handlers/sort.ts +11 -8
  35. package/src/ts/get_cell_config.ts +1 -0
  36. package/src/ts/model/create.ts +19 -22
  37. package/src/ts/plugin/draw.ts +1 -0
  38. package/src/ts/style_handlers/body.ts +21 -21
  39. package/src/ts/style_handlers/column_header.ts +21 -9
  40. package/src/ts/style_handlers/consolidated.ts +8 -13
  41. package/src/ts/style_handlers/focus.ts +4 -10
  42. package/src/ts/style_handlers/group_header.ts +6 -3
  43. package/src/ts/style_handlers/table_cell/boolean.ts +2 -5
  44. package/src/ts/style_handlers/table_cell/cell_flash.ts +2 -2
  45. package/src/ts/style_handlers/table_cell/datetime.ts +2 -5
  46. package/src/ts/style_handlers/table_cell/row_header.ts +8 -7
  47. package/src/ts/style_handlers/types.ts +6 -6
  48. package/src/ts/types.ts +18 -8
@@ -1,5 +1,5 @@
1
1
  import { RegularTableElement } from "regular-table";
2
- import type { DatagridModel, PerspectiveViewerElement, ColumnsConfig } from "../types.js";
2
+ import { type DatagridModel, type PerspectiveViewerElement, type ColumnsConfig } from "../types.js";
3
3
  import { CollectedCell, LocalSelectedPositionMap, LocalSelectedRowsMap } from "./types.js";
4
4
  /**
5
5
  * Apply styles to all body cells in a single pass.
@@ -1,5 +1,5 @@
1
1
  import { RegularTableElement } from "regular-table";
2
- import type { DatagridModel, PerspectiveViewerElement } from "../types.js";
2
+ import { type DatagridModel, type PerspectiveViewerElement } from "../types.js";
3
3
  import { CollectedHeaderRow } from "./types.js";
4
4
  /**
5
5
  * Apply selected column styling in response to column settings toggle events.
@@ -1,12 +1,9 @@
1
1
  import { RegularTableElement } from "regular-table";
2
- import { CellMetadata } from "regular-table/dist/esm/types.js";
3
2
  import type { DatagridModel, PerspectiveViewerElement, ColumnsConfig, DatagridPluginElement, SelectedPosition } from "../types.js";
4
- interface CellMetaExtended extends CellMetadata {
5
- _is_hidden_by_aggregate_depth?: boolean;
6
- }
3
+ import { CellMetadata } from "regular-table/dist/esm/types.js";
7
4
  interface CollectedCell {
8
5
  element: HTMLElement;
9
- metadata: CellMetaExtended;
6
+ metadata: CellMetadata;
10
7
  isHeader: boolean;
11
8
  }
12
9
  interface CollectedHeaderRow {
@@ -1,7 +1,3 @@
1
1
  import { CellMetadata } from "regular-table/dist/esm/types.js";
2
2
  import type { DatagridModel, ColumnConfig } from "../../types.js";
3
- interface CellMetaWithFlags extends CellMetadata {
4
- _is_hidden_by_aggregate_depth?: boolean;
5
- }
6
- export declare function cell_style_boolean(this: DatagridModel, _plugin: ColumnConfig | undefined, td: HTMLElement, metadata: CellMetaWithFlags): void;
7
- export {};
3
+ export declare function cell_style_boolean(this: DatagridModel, _plugin: ColumnConfig | undefined, td: HTMLElement, metadata: CellMetadata): void;
@@ -1,3 +1,3 @@
1
- import { CellMetadata } from "regular-table/dist/esm/types.js";
1
+ import { CellMetadataBody } from "regular-table/dist/esm/types.js";
2
2
  import type { DatagridModel, ColorRecord } from "../../types.js";
3
- export declare function style_cell_flash(this: DatagridModel, metadata: CellMetadata, td: HTMLElement, [, , , , , pos_s, pos_e]: ColorRecord, [, , , , , neg_s, neg_e]: ColorRecord, is_settings_open: boolean): void;
3
+ export declare function style_cell_flash(this: DatagridModel, metadata: CellMetadataBody, td: HTMLElement, [, , , , , pos_s, pos_e]: ColorRecord, [, , , , , neg_s, neg_e]: ColorRecord, is_settings_open: boolean): void;
@@ -1,7 +1,3 @@
1
1
  import { CellMetadata } from "regular-table/dist/esm/types.js";
2
2
  import type { DatagridModel, ColumnConfig } from "../../types.js";
3
- interface CellMetaWithFlags extends CellMetadata {
4
- _is_hidden_by_aggregate_depth?: boolean;
5
- }
6
- export declare function cell_style_datetime(this: DatagridModel, plugin: ColumnConfig, td: HTMLElement, metadata: CellMetaWithFlags): void;
7
- export {};
3
+ export declare function cell_style_datetime(this: DatagridModel, plugin: ColumnConfig, td: HTMLElement, metadata: CellMetadata): void;
@@ -1,4 +1,4 @@
1
- import { CellMetadata } from "regular-table/dist/esm/types.js";
1
+ import { CellMetadataRowHeader } from "regular-table/dist/esm/types.js";
2
2
  import type { DatagridModel } from "../../types.js";
3
3
  import { RegularTableElement } from "regular-table";
4
- export declare function cell_style_row_header(this: DatagridModel, regularTable: RegularTableElement, td: HTMLElement, metadata: CellMetadata): void;
4
+ export declare function cell_style_row_header(this: DatagridModel, regularTable: RegularTableElement, td: HTMLElement, metadata: CellMetadataRowHeader): void;
@@ -1,12 +1,9 @@
1
1
  import { RegularTableElement } from "regular-table";
2
- import { CellMetadata } from "regular-table/dist/esm/types.js";
2
+ import { CellMetadata, CellMetadataBody, CellMetadataRowHeader } from "regular-table/dist/esm/types.js";
3
3
  import type { SelectedPosition } from "../types.js";
4
- export interface CellMetaExtended extends CellMetadata {
5
- _is_hidden_by_aggregate_depth?: boolean;
6
- }
7
4
  export interface CollectedCell {
8
5
  element: HTMLElement;
9
- metadata: CellMetaExtended;
6
+ metadata: CellMetadataRowHeader | CellMetadataBody;
10
7
  isHeader: boolean;
11
8
  }
12
9
  export interface CollectedHeaderRow {
@@ -1,8 +1,8 @@
1
- import type { View, Table, ViewConfig, ColumnType, SortDir, ViewWindow } from "@perspective-dev/client";
1
+ import type { View, Table, ViewConfig, ColumnType, SortDir, ViewWindow, ViewConfigUpdate } from "@perspective-dev/client";
2
2
  import { RegularTableElement } from "regular-table";
3
3
  import { CellMetadata, DataResponse } from "regular-table/dist/esm/types";
4
4
  export type { RegularTableElement as RegularTable };
5
- export type { CellMetadata as CellMeta };
5
+ export declare function get_psp_type(model: DatagridModel, metadata: CellMetadata): ColumnType;
6
6
  export type EditMode = "READ_ONLY" | "EDIT" | "SELECT_COLUMN" | "SELECT_ROW" | "SELECT_REGION";
7
7
  export type ColorRecord = [
8
8
  string,
@@ -158,19 +158,14 @@ export type FormatterCache = Map<string, FormatterCacheEntry>;
158
158
  export interface CellConfigResult {
159
159
  row: Record<string, unknown>;
160
160
  column_names: string[];
161
- config: Partial<ViewConfig>;
161
+ config: ViewConfigUpdate;
162
162
  }
163
163
  export interface PerspectiveClickDetail {
164
164
  row: Record<string, unknown>;
165
165
  column_names: string[];
166
166
  config: Partial<ViewConfig>;
167
167
  }
168
- export interface PerspectiveSelectDetail {
169
- selected: boolean;
170
- row: Record<string, unknown>;
171
- column_names?: string[];
172
- config: Partial<ViewConfig>;
173
- }
168
+ export { PerspectiveSelectDetail } from "@perspective-dev/viewer";
174
169
  export interface HandledMouseEvent extends MouseEvent {
175
170
  handled?: boolean;
176
171
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perspective-dev/viewer-datagrid",
3
- "version": "4.1.1",
3
+ "version": "4.3.0",
4
4
  "description": "Perspective datagrid plugin based on `regular-table`",
5
5
  "unpkg": "dist/cdn/perspective-viewer-datagrid.js",
6
6
  "jsdelivr": "dist/cdn/perspective-viewer-datagrid.js",
@@ -32,10 +32,10 @@
32
32
  "@perspective-dev/client": "",
33
33
  "@perspective-dev/viewer": "",
34
34
  "chroma-js": ">=3 <4",
35
- "regular-table": "=0.8.0"
35
+ "regular-table": "=0.8.3"
36
36
  },
37
37
  "devDependencies": {
38
- "@prospective.co/procss": "0.1.17",
38
+ "@prospective.co/procss": "0.1.18",
39
39
  "@perspective-dev/esbuild-plugin": "",
40
40
  "@perspective-dev/test": "",
41
41
  "@types/chroma-js": "^3.1.2",
@@ -128,10 +128,20 @@ perspective-viewer {
128
128
  border-color: var(--selected-row--background-color, #ea7319) !important;
129
129
  }
130
130
 
131
+ regular-table.flat-group-rollup-mode.vertical-row-headers
132
+ th.psp-tree-label:not(:last-of-type) {
133
+ writing-mode: vertical-lr;
134
+ }
135
+
131
136
  .psp-row-selected.psp-tree-label:not(:hover):before {
132
137
  color: white;
133
138
  }
134
139
 
140
+ regular-table:not(.flat-group-rollup-mode)
141
+ .psp-row-selected.psp-tree-label:not(:hover):before {
142
+ color: white;
143
+ }
144
+
135
145
  .psp-row-subselected,
136
146
  :hover .psp-row-subselected,
137
147
  :hover th.psp-tree-leaf.psp-row-subselected,
@@ -254,29 +264,36 @@ tbody th:empty {
254
264
  max-width: 20px;
255
265
  pointer-events: none;
256
266
  }
257
- .psp-tree-label {
258
- max-width: 0px;
259
- min-width: 0px;
260
- }
261
- .psp-tree-label:before {
262
- color: var(--icon--color);
263
- font-family: var(--button--font-family, inherit);
264
- padding-right: 11px;
265
- }
266
- .psp-tree-label-expand:before {
267
- content: var(--tree-label-expand--content, "+");
268
- }
269
- .psp-tree-label-collapse:before {
270
- content: var(--tree-label-collapse--content, "-");
271
- }
272
- .psp-tree-label-expand,
273
- .psp-tree-label-collapse {
274
- cursor: pointer;
275
- }
276
267
 
277
- .psp-tree-label:hover:before {
278
- color: var(--active--color);
279
- text-shadow: 0px 0px 5px var(--active--color);
268
+ regular-table:not(.flat-group-rollup-mode) {
269
+ .psp-tree-label {
270
+ max-width: 0px;
271
+ min-width: 0px;
272
+ }
273
+
274
+ .psp-tree-label:before {
275
+ color: var(--icon--color);
276
+ font-family: var(--button--font-family, inherit);
277
+ padding-right: 11px;
278
+ }
279
+
280
+ .psp-tree-label-expand:before {
281
+ content: var(--tree-label-expand--content, "+");
282
+ }
283
+
284
+ .psp-tree-label-collapse:before {
285
+ content: var(--tree-label-collapse--content, "-");
286
+ }
287
+
288
+ .psp-tree-label-expand,
289
+ .psp-tree-label-collapse {
290
+ cursor: pointer;
291
+ }
292
+
293
+ .psp-tree-label:hover:before {
294
+ color: var(--active--color);
295
+ text-shadow: 0px 0px 5px var(--active--color);
296
+ }
280
297
  }
281
298
 
282
299
  .psp-tree-leaf {
@@ -57,7 +57,6 @@ export function make_color_record(color: string): ColorRecord {
57
57
  const chroma_neg = chroma(color);
58
58
  const _neg_grad = make_gradient(chroma_neg);
59
59
  const rgb = chroma_neg.rgb();
60
-
61
60
  return [
62
61
  color,
63
62
  rgb[0],
@@ -133,6 +133,10 @@ export class HTMLPerspectiveViewerDatagridPluginElement
133
133
  return ["Columns"];
134
134
  }
135
135
 
136
+ get group_rollups(): string[] {
137
+ return ["rollup", "flat", "total"];
138
+ }
139
+
136
140
  /**
137
141
  * Give the Datagrid a higher priority so it is loaded
138
142
  * over the default charts by default.
@@ -179,6 +183,7 @@ export class HTMLPerspectiveViewerDatagridPluginElement
179
183
  viewport?.start_row !== null
180
184
  ? viewport.end_row - viewport.start_row
181
185
  : await view.num_rows();
186
+
182
187
  let out = "";
183
188
  for (let ridx = 0; ridx < nrows; ridx++) {
184
189
  for (const col_name of cols) {
@@ -52,6 +52,22 @@ export function* format_tree_header_row_path(
52
52
  }
53
53
  }
54
54
 
55
+ export function* format_flat_header_row_path(
56
+ this: DatagridModel,
57
+ paths: unknown[][] = [],
58
+ row_headers: string[],
59
+ regularTable: RegularTable,
60
+ ): Generator<RowHeaderCell[]> {
61
+ const plugins: ColumnsConfig =
62
+ (regularTable as any)[PRIVATE_PLUGIN_SYMBOL] || {};
63
+
64
+ for (let path of paths) {
65
+ yield path.map((part, i) =>
66
+ format_cell.call(this, row_headers[i], part, plugins, true),
67
+ ) as RowHeaderCell[];
68
+ }
69
+ }
70
+
55
71
  /**
56
72
  * Format a single cell of the `group_by` tree header.
57
73
  */
@@ -13,6 +13,7 @@
13
13
  import { PRIVATE_PLUGIN_SYMBOL } from "../types.js";
14
14
  import { format_cell } from "./format_cell.js";
15
15
  import {
16
+ format_flat_header_row_path,
16
17
  format_tree_header,
17
18
  format_tree_header_row_path,
18
19
  } from "./format_tree_header.js";
@@ -23,7 +24,7 @@ import type {
23
24
  Schema,
24
25
  } from "../types.js";
25
26
  import type { CellScalar, DataResponse } from "regular-table/dist/esm/types.js";
26
- import { ViewWindow } from "@perspective-dev/client";
27
+ import { ViewConfig, ViewWindow } from "@perspective-dev/client";
27
28
 
28
29
  interface ColumnData {
29
30
  __ROW_PATH__?: unknown[][];
@@ -191,8 +192,10 @@ export function createDataListener(
191
192
  column_paths.push(path);
192
193
  }
193
194
 
195
+ const is_dim_call = x1 - x0 > 0 && y1 - y0 > 0;
196
+
194
197
  // Only update the last state if this is not a "phantom" call.
195
- if (x1 - x0 > 0 && y1 - y0 > 0) {
198
+ if (is_dim_call) {
196
199
  this.last_column_paths = last_column_paths;
197
200
  this.last_meta = last_meta;
198
201
  this.last_ids = last_ids;
@@ -207,9 +210,12 @@ export function createDataListener(
207
210
  }
208
211
 
209
212
  const is_row_path = columns.__ROW_PATH__ !== undefined;
213
+ const is_flat = this._config.group_rollup_mode === "flat";
210
214
  const row_headers = Array.from(
211
215
  (is_row_path
212
- ? format_tree_header_row_path
216
+ ? is_flat
217
+ ? format_flat_header_row_path
218
+ : format_tree_header_row_path
213
219
  : format_tree_header
214
220
  ).call(
215
221
  this,
@@ -219,7 +225,9 @@ export function createDataListener(
219
225
  ),
220
226
  ) as (string | HTMLElement)[][];
221
227
 
222
- const num_row_headers = row_headers[0]?.length;
228
+ const num_row_headers = !is_dim_call
229
+ ? row_header_depth(this._config)
230
+ : row_headers[0]?.length;
223
231
 
224
232
  const result: DataResponse = {
225
233
  num_column_headers:
@@ -240,3 +248,15 @@ export function createDataListener(
240
248
  return result;
241
249
  };
242
250
  }
251
+
252
+ function row_header_depth(config: ViewConfig) {
253
+ if (config.group_rollup_mode === "flat") {
254
+ return config.group_by.length;
255
+ } else if (config.group_rollup_mode === "total") {
256
+ return 0;
257
+ } else if (config.group_by.length === 0) {
258
+ return 0;
259
+ } else {
260
+ return config.group_by.length + 1;
261
+ }
262
+ }
@@ -10,10 +10,12 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import type {
14
- RegularTable,
15
- DatagridModel,
16
- PerspectiveViewerElement,
13
+ import { CellMetadataBody } from "regular-table/dist/esm/types.js";
14
+ import {
15
+ type RegularTable,
16
+ type DatagridModel,
17
+ type PerspectiveViewerElement,
18
+ get_psp_type,
17
19
  } from "../../types.js";
18
20
 
19
21
  export function write_cell(
@@ -21,13 +23,13 @@ export function write_cell(
21
23
  model: DatagridModel,
22
24
  active_cell: HTMLElement,
23
25
  ): boolean {
24
- const meta = table.getMeta(active_cell);
26
+ const meta = table.getMeta(active_cell) as CellMetadataBody;
25
27
  if (!meta) {
26
28
  return false;
27
29
  }
28
- const type = model._schema[model._column_paths[meta.x]];
30
+ const type = model._schema[model._column_paths[meta.x!]];
29
31
  let text: string | number | boolean | null = active_cell.textContent || "";
30
- const id = model._ids[meta.y - meta.y0][0];
32
+ const id = model._ids[meta.y! - meta.y0][0];
31
33
  if (type === "float" || type === "integer") {
32
34
  const parsed = parseFloat(text.replace(/,/g, ""));
33
35
  if (isNaN(parsed)) {
@@ -59,13 +61,14 @@ export function clickListener(
59
61
  _viewer: PerspectiveViewerElement,
60
62
  event: MouseEvent,
61
63
  ): void {
62
- const meta = table.getMeta(event.target as Element);
63
- if (typeof meta?.x !== "undefined") {
64
+ const meta = table.getMeta(event.target as HTMLElement);
65
+ if (meta?.type === "body" || meta?.type === "column_header") {
64
66
  const is_editable2 = this._is_editable[meta.x];
65
- const is_bool = this.get_psp_type(meta) === "boolean";
67
+ const is_bool = get_psp_type(this, meta) === "boolean";
66
68
  const is_null = (event.target as Element).classList.contains(
67
69
  "psp-null",
68
70
  );
71
+
69
72
  if (is_editable2 && is_bool && !is_null) {
70
73
  write_cell(table, this, event.target as HTMLElement);
71
74
  }
@@ -24,12 +24,10 @@ export async function dispatch_click_listener(
24
24
  viewer: PerspectiveViewerElement,
25
25
  event: MouseEvent,
26
26
  ): Promise<void> {
27
- const meta = table.getMeta(event.target as Element);
28
- if (!meta) return;
27
+ const meta = table.getMeta(event.target as HTMLElement);
28
+ if (!meta || meta.type !== "body") return;
29
29
  const { x, y } = meta;
30
-
31
30
  const { row, column_names, config } = await getCellConfig(this, y, x);
32
-
33
31
  viewer.dispatchEvent(
34
32
  new CustomEvent<PerspectiveClickDetail>("perspective-click", {
35
33
  bubbles: true,
@@ -17,12 +17,12 @@ export async function expandCollapseHandler(
17
17
  regularTable: RegularTable,
18
18
  event: MouseEvent,
19
19
  ): Promise<void> {
20
- const meta = regularTable.getMeta(event.target as Element);
21
- if (!meta?.row_header) return;
22
-
20
+ const meta = regularTable.getMeta(event.target as HTMLElement);
21
+ if (!meta || meta.type !== "row_header") return;
23
22
  const is_collapse = (event.target as Element).classList.contains(
24
23
  "psp-tree-label-collapse",
25
24
  );
25
+
26
26
  if (event.shiftKey && is_collapse) {
27
27
  this._view.set_depth(
28
28
  (meta.row_header as unknown[]).filter((x) => x !== undefined)
@@ -38,6 +38,7 @@ export async function expandCollapseHandler(
38
38
  } else {
39
39
  this._view.expand(meta.y);
40
40
  }
41
+
41
42
  this._num_rows = await this._view.num_rows();
42
43
  this._num_columns = await this._view.num_columns();
43
44
  regularTable.draw();
@@ -52,7 +52,7 @@ export function focusinListener(
52
52
  ): void {
53
53
  const target = event.target as HTMLElement;
54
54
  const meta = table.getMeta(target);
55
- if (meta) {
55
+ if (meta?.type === "body") {
56
56
  const new_state: SelectedPosition = {
57
57
  x: meta.x,
58
58
  y: meta.y,
@@ -50,7 +50,7 @@ export async function mousedown_listener(
50
50
  if (target.classList.contains("psp-menu-enabled")) {
51
51
  const meta = regularTable.getMeta(target);
52
52
  const column_name = meta?.column_header?.[this._config.split_by.length];
53
- await viewer.toggleColumnSettings(column_name);
53
+ await viewer.toggleColumnSettings(`${column_name}`);
54
54
  } else if (target.classList.contains("psp-sort-enabled")) {
55
55
  sortHandler.call(this, regularTable, viewer, event, target);
56
56
  }
@@ -76,7 +76,7 @@ const moveSelection = lock(async function (
76
76
  dy: number,
77
77
  ): Promise<void> {
78
78
  const meta = table.getMeta(active_cell);
79
- if (!meta) return;
79
+ if (!meta || meta.type !== "body") return;
80
80
  const num_columns = this._column_paths.length;
81
81
  const num_rows = this._num_rows;
82
82
  const selected_position = selected_position_map.get(table);
@@ -118,7 +118,7 @@ function isLastCell(
118
118
  target: HTMLElement,
119
119
  ): boolean {
120
120
  const meta = table.getMeta(target);
121
- return meta !== undefined && meta.y === model._num_rows - 1;
121
+ return meta?.type === "body" && meta.y === model._num_rows - 1;
122
122
  }
123
123
 
124
124
  export function keydownListener(
@@ -11,11 +11,11 @@
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
13
  import getCellConfig from "../get_cell_config.js";
14
- import type {
15
- RegularTable,
16
- DatagridModel,
17
- PerspectiveViewerElement,
18
- HandledMouseEvent,
14
+ import {
15
+ type RegularTable,
16
+ type DatagridModel,
17
+ type PerspectiveViewerElement,
18
+ type HandledMouseEvent,
19
19
  PerspectiveSelectDetail,
20
20
  } from "../types.js";
21
21
 
@@ -28,21 +28,22 @@ export async function selectionListener(
28
28
  selected_rows_map: SelectedRowsMap,
29
29
  event: HandledMouseEvent,
30
30
  ): Promise<void> {
31
- const meta = regularTable.getMeta(event.target as Element);
31
+ const meta = regularTable.getMeta(event.target as HTMLElement);
32
32
  if (!viewer.hasAttribute("selectable")) return;
33
33
  if (event.handled) return;
34
34
  if (event.shiftKey) return;
35
35
  if (event.button !== 0) {
36
36
  return;
37
37
  }
38
+
38
39
  event.stopImmediatePropagation();
39
40
 
40
41
  if (!meta) {
41
42
  return;
42
43
  }
43
44
 
44
- const id = this._ids?.[meta.y - meta.y0];
45
- if (meta && meta.y >= 0) {
45
+ if ((meta.type === "body" || meta.type === "row_header") && meta.y >= 0) {
46
+ const id = this._ids?.[meta.y - meta.y0];
46
47
  const selected = selected_rows_map.get(regularTable);
47
48
  const key_match =
48
49
  !!selected &&
@@ -51,27 +52,31 @@ export async function selectionListener(
51
52
  const is_deselect =
52
53
  !!selected && id.length === selected.length && key_match;
53
54
 
54
- let detail: PerspectiveSelectDetail = {
55
- selected: !is_deselect,
56
- row: {},
57
- config: { filter: [] },
58
- };
59
55
  const { row, column_names, config } = await getCellConfig(
60
56
  this,
61
57
  meta.y,
62
- meta.x,
58
+ meta.type === "body" ? meta.x : 0,
63
59
  );
64
60
 
61
+ let detail: PerspectiveSelectDetail;
65
62
  if (is_deselect) {
66
63
  selected_rows_map.delete(regularTable);
67
- detail = {
68
- ...detail,
64
+ detail = new PerspectiveSelectDetail(
65
+ false,
69
66
  row,
70
- config: { filter: structuredClone(this._config.filter) },
71
- };
67
+ [],
68
+ [],
69
+ [{ filter: structuredClone(this._config.filter) }],
70
+ );
72
71
  } else {
73
72
  selected_rows_map.set(regularTable, id);
74
- detail = { ...detail, row, column_names, config };
73
+ detail = new PerspectiveSelectDetail(
74
+ true,
75
+ row,
76
+ column_names,
77
+ [],
78
+ [config],
79
+ );
75
80
  }
76
81
 
77
82
  await regularTable.draw({ preserve_width: true });
@@ -75,8 +75,12 @@ const getMousedownListener =
75
75
  datagrid.model!._edit_mode === "SELECT_COLUMN")
76
76
  ) {
77
77
  datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES = {};
78
- const meta = table.getMeta(mouseEvent.target as Element);
79
- if (meta && meta.x !== undefined && meta.y !== undefined) {
78
+ const meta = table.getMeta(mouseEvent.target as HTMLElement);
79
+ if (
80
+ meta?.type === "body" &&
81
+ meta.x !== undefined &&
82
+ meta.y !== undefined
83
+ ) {
80
84
  datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES =
81
85
  {
82
86
  x: meta.x,
@@ -129,8 +133,12 @@ const getMouseoverListener =
129
133
  datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES
130
134
  .x !== undefined
131
135
  ) {
132
- const meta = table.getMeta(mouseEvent.target as Element);
133
- if (meta && meta.x !== undefined && meta.y !== undefined) {
136
+ const meta = table.getMeta(mouseEvent.target as HTMLElement);
137
+ if (
138
+ meta?.type === "body" &&
139
+ meta.x !== undefined &&
140
+ meta.y !== undefined
141
+ ) {
134
142
  const potentialSelection: SelectionArea = {
135
143
  x0: Math.min(
136
144
  meta.x,
@@ -183,7 +191,7 @@ const getMouseupListener =
183
191
  datagrid.model!._edit_mode === "SELECT_ROW" ||
184
192
  datagrid.model!._edit_mode === "SELECT_COLUMN"
185
193
  ) {
186
- const meta = table.getMeta(mouseEvent.target as Element);
194
+ const meta = table.getMeta(mouseEvent.target as HTMLElement);
187
195
  if (!meta) return;
188
196
 
189
197
  if (
@@ -195,6 +203,7 @@ const getMouseupListener =
195
203
  if (
196
204
  selected.x0 === selected.x1 &&
197
205
  selected.y0 === selected.y1 &&
206
+ meta?.type === "body" &&
198
207
  selected.x0 === meta.x &&
199
208
  selected.y0 === meta.y
200
209
  ) {
@@ -216,6 +225,7 @@ const getMouseupListener =
216
225
  .CURRENT_MOUSEDOWN_COORDINATES &&
217
226
  datagrid.model!._selection_state.CURRENT_MOUSEDOWN_COORDINATES
218
227
  .x !== undefined &&
228
+ meta?.type === "body" &&
219
229
  meta.x !== undefined &&
220
230
  meta.y !== undefined
221
231
  ) {
@@ -338,8 +348,8 @@ const applyMouseAreaSelection = (
338
348
  const tds = table.querySelectorAll("tbody td");
339
349
 
340
350
  for (const td of tds) {
341
- const meta = table.getMeta(td);
342
- if (!meta) continue;
351
+ const meta = table.getMeta(td as HTMLElement);
352
+ if (!meta || meta.type !== "body") continue;
343
353
  let rendered = false;
344
354
  for (const { x0, x1, y0, y1 } of selected) {
345
355
  if (
@@ -372,7 +382,7 @@ const applyMouseAreaSelection = (
372
382
  const tds = table.querySelectorAll("tbody td");
373
383
 
374
384
  for (const td of tds) {
375
- const meta = table.getMeta(td);
385
+ const meta = table.getMeta(td as HTMLElement);
376
386
  if (!meta) continue;
377
387
  let rendered = false;
378
388
  for (const { x0, x1, y0, y1 } of selected) {
@@ -380,7 +390,8 @@ const applyMouseAreaSelection = (
380
390
  x0 !== undefined &&
381
391
  y0 !== undefined &&
382
392
  x1 !== undefined &&
383
- y1 !== undefined
393
+ y1 !== undefined &&
394
+ meta?.type === "body"
384
395
  ) {
385
396
  if (y0 <= meta.y && meta.y <= y1) {
386
397
  datagrid.model!._selection_state.dirty = true;
@@ -401,7 +412,7 @@ const applyMouseAreaSelection = (
401
412
  const tds = table.querySelectorAll("tbody td");
402
413
 
403
414
  for (const td of tds) {
404
- const meta = table.getMeta(td);
415
+ const meta = table.getMeta(td as HTMLElement);
405
416
  if (!meta) continue;
406
417
  let rendered = false;
407
418
  for (const { x0, x1, y0, y1 } of selected) {
@@ -409,7 +420,8 @@ const applyMouseAreaSelection = (
409
420
  x0 !== undefined &&
410
421
  y0 !== undefined &&
411
422
  x1 !== undefined &&
412
- y1 !== undefined
423
+ y1 !== undefined &&
424
+ meta?.type === "body"
413
425
  ) {
414
426
  if (x0 <= meta.x && meta.x <= x1) {
415
427
  datagrid.model!._selection_state.dirty = true;