@perspective-dev/viewer-datagrid 4.4.0 → 4.5.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 (87) 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 +16 -21
  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/model/meta_columns.d.ts +1 -0
  21. package/dist/esm/perspective-viewer-datagrid.js +3 -3
  22. package/dist/esm/perspective-viewer-datagrid.js.map +4 -4
  23. package/dist/esm/plugin/activate.d.ts +1 -1
  24. package/dist/esm/plugin/column_config_schema.d.ts +31 -0
  25. package/dist/esm/style_handlers/body.d.ts +3 -3
  26. package/dist/esm/style_handlers/column_header.d.ts +4 -3
  27. package/dist/esm/style_handlers/consolidated.d.ts +3 -47
  28. package/dist/esm/style_handlers/editable.d.ts +3 -2
  29. package/dist/esm/style_handlers/focus.d.ts +4 -4
  30. package/dist/esm/style_handlers/group_header.d.ts +1 -1
  31. package/dist/esm/style_handlers/table_cell/boolean.d.ts +1 -1
  32. package/dist/esm/style_handlers/table_cell/cell_flash.d.ts +1 -1
  33. package/dist/esm/style_handlers/table_cell/datetime.d.ts +1 -1
  34. package/dist/esm/style_handlers/table_cell/numeric.d.ts +1 -1
  35. package/dist/esm/style_handlers/table_cell/row_header.d.ts +1 -1
  36. package/dist/esm/style_handlers/table_cell/string.d.ts +1 -1
  37. package/dist/esm/style_handlers/types.d.ts +0 -4
  38. package/dist/esm/types.d.ts +10 -17
  39. package/package.json +2 -4
  40. package/src/css/regular_table.css +87 -31
  41. package/src/css/row-hover.css +20 -7
  42. package/src/css/toolbar.css +11 -0
  43. package/src/ts/color_utils.ts +181 -16
  44. package/src/ts/custom_elements/datagrid.ts +70 -56
  45. package/src/ts/custom_elements/toolbar.ts +4 -5
  46. package/src/ts/data_listener/format_cell.ts +28 -9
  47. package/src/ts/data_listener/format_tree_header.ts +2 -2
  48. package/src/ts/data_listener/formatter_cache.ts +9 -96
  49. package/src/ts/data_listener/index.ts +13 -11
  50. package/src/ts/event_handlers/click/edit_click.ts +10 -6
  51. package/src/ts/event_handlers/click.ts +39 -68
  52. package/src/ts/event_handlers/dispatch_click.ts +27 -25
  53. package/src/ts/event_handlers/expand_collapse.ts +11 -8
  54. package/src/ts/event_handlers/focus.ts +38 -35
  55. package/src/ts/event_handlers/header_click.ts +107 -62
  56. package/src/ts/event_handlers/keydown/edit_keydown.ts +60 -54
  57. package/src/ts/event_handlers/select_region.ts +153 -131
  58. package/src/ts/event_handlers/sort.ts +20 -25
  59. package/src/ts/get_cell_config.ts +10 -3
  60. package/src/ts/model/column_overrides.ts +16 -9
  61. package/src/ts/model/create.ts +68 -55
  62. package/src/ts/{event_handlers/deselect_all.ts → model/meta_columns.ts} +33 -14
  63. package/src/ts/model/toolbar.ts +33 -8
  64. package/src/ts/plugin/activate.ts +122 -92
  65. package/src/ts/plugin/column_config_schema.ts +187 -0
  66. package/src/ts/plugin/draw.ts +1 -0
  67. package/src/ts/plugin/restore.ts +6 -2
  68. package/src/ts/plugin/save.ts +2 -5
  69. package/src/ts/style_handlers/body.ts +48 -51
  70. package/src/ts/style_handlers/column_header.ts +22 -21
  71. package/src/ts/style_handlers/consolidated.ts +23 -123
  72. package/src/ts/style_handlers/editable.ts +16 -10
  73. package/src/ts/style_handlers/focus.ts +7 -5
  74. package/src/ts/style_handlers/group_header.ts +13 -6
  75. package/src/ts/style_handlers/table_cell/boolean.ts +3 -3
  76. package/src/ts/style_handlers/table_cell/cell_flash.ts +11 -11
  77. package/src/ts/style_handlers/table_cell/datetime.ts +3 -3
  78. package/src/ts/style_handlers/table_cell/numeric.ts +24 -25
  79. package/src/ts/style_handlers/table_cell/row_header.ts +2 -2
  80. package/src/ts/style_handlers/table_cell/string.ts +20 -18
  81. package/src/ts/style_handlers/types.ts +0 -10
  82. package/src/ts/types.ts +28 -20
  83. package/dist/esm/event_handlers/deselect_all.d.ts +0 -5
  84. package/dist/esm/event_handlers/row_select_click.d.ts +0 -4
  85. package/dist/esm/plugin/column_style_controls.d.ts +0 -28
  86. package/src/ts/event_handlers/row_select_click.ts +0 -92
  87. package/src/ts/plugin/column_style_controls.ts +0 -76
@@ -14,9 +14,7 @@ import { RegularTableElement } from "regular-table";
14
14
 
15
15
  import {
16
16
  type DatagridModel,
17
- type PerspectiveViewerElement,
18
17
  type ColumnsConfig,
19
- type DatagridPluginElement,
20
18
  get_psp_type,
21
19
  } from "../types.js";
22
20
 
@@ -25,39 +23,31 @@ import { cell_style_string } from "./table_cell/string.js";
25
23
  import { cell_style_datetime } from "./table_cell/datetime.js";
26
24
  import { cell_style_boolean } from "./table_cell/boolean.js";
27
25
  import { cell_style_row_header } from "./table_cell/row_header.js";
28
- import {
29
- CollectedCell,
30
- LocalSelectedPositionMap,
31
- LocalSelectedRowsMap,
32
- } from "./types.js";
26
+ import { CollectedCell } from "./types.js";
33
27
 
34
28
  /**
35
29
  * Apply styles to all body cells in a single pass.
36
30
  */
37
31
  export function applyBodyCellStyles(
38
- this: DatagridModel,
32
+ model: DatagridModel,
39
33
  cells: CollectedCell[],
40
34
  plugins: ColumnsConfig,
41
35
  isSettingsOpen: boolean,
42
36
  isSelectable: boolean,
43
37
  isEditable: boolean,
44
38
  regularTable: RegularTableElement,
45
- selectedRowsMap: LocalSelectedRowsMap,
46
- selectedPositionMap: LocalSelectedPositionMap,
47
- viewer: PerspectiveViewerElement,
48
39
  ): void {
49
- const hasSelected = selectedRowsMap.has(regularTable);
50
- const selected = selectedRowsMap.get(regularTable);
40
+ const selectedId = isSelectable ? model._tree_selection_id : undefined;
51
41
 
52
42
  regularTable.classList.toggle(
53
43
  "flat-group-rollup-mode",
54
- this._config.group_rollup_mode === "flat",
44
+ model._config.group_rollup_mode === "flat",
55
45
  );
56
46
 
57
47
  for (const { element: td, metadata, isHeader } of cells) {
58
48
  const column_name =
59
- metadata.column_header?.[this._config.split_by.length];
60
- const type = get_psp_type(this, metadata);
49
+ metadata.column_header?.[model._config.split_by.length];
50
+ const type = get_psp_type(model, metadata);
61
51
  const plugin = column_name
62
52
  ? plugins[column_name.toString()]
63
53
  : undefined;
@@ -66,13 +56,13 @@ export function applyBodyCellStyles(
66
56
  // Calculate aggregate depth visibility
67
57
  // @ts-ignore
68
58
  metadata._is_hidden_by_aggregate_depth =
69
- this._config.group_rollup_mode === "rollup" &&
59
+ model._config.group_rollup_mode === "rollup" &&
70
60
  ((x?: number) =>
71
61
  x === 0 || x === undefined
72
62
  ? false
73
63
  : x - 1 <
74
64
  Math.min(
75
- this._config.group_by.length,
65
+ model._config.group_by.length,
76
66
  plugin?.aggregate_depth || 0,
77
67
  ))(
78
68
  (metadata.row_header as unknown[] | undefined)?.filter(
@@ -82,19 +72,19 @@ export function applyBodyCellStyles(
82
72
 
83
73
  // Apply type-specific cell styling
84
74
  if (is_numeric) {
85
- cell_style_numeric.call(
86
- this,
75
+ cell_style_numeric(
76
+ model,
87
77
  plugin as any,
88
78
  td,
89
79
  metadata as any,
90
80
  isSettingsOpen,
91
81
  );
92
82
  } else if (type === "boolean") {
93
- cell_style_boolean.call(this, plugin, td, metadata as any);
83
+ cell_style_boolean(model, plugin, td, metadata as any);
94
84
  } else if (type === "string") {
95
- cell_style_string.call(this, plugin as any, td, metadata as any);
85
+ cell_style_string(model, plugin as any, td, metadata as any);
96
86
  } else if (type === "date" || type === "datetime") {
97
- cell_style_datetime.call(this, plugin as any, td, metadata);
87
+ cell_style_datetime(model, plugin as any, td, metadata);
98
88
  } else {
99
89
  td.style.backgroundColor = "";
100
90
  td.style.color = "";
@@ -109,10 +99,10 @@ export function applyBodyCellStyles(
109
99
  td.classList.toggle("psp-null", metadata.value === null);
110
100
  td.classList.toggle("psp-align-right", !isHeader && is_numeric);
111
101
  td.classList.toggle("psp-align-left", isHeader || !is_numeric);
112
- if (this._column_settings_selected_column) {
102
+ if (model._column_settings_selected_column) {
113
103
  td.classList.toggle(
114
104
  "psp-menu-open",
115
- column_name === this._column_settings_selected_column,
105
+ column_name === model._column_settings_selected_column,
116
106
  );
117
107
  } else {
118
108
  td.classList.toggle("psp-menu-open", false);
@@ -123,9 +113,14 @@ export function applyBodyCellStyles(
123
113
  plugin?.number_fg_mode === "bar" && is_numeric,
124
114
  );
125
115
 
116
+ td.classList.toggle(
117
+ "psp-color-mode-label-bar",
118
+ plugin?.number_fg_mode === "label-bar" && is_numeric,
119
+ );
120
+
126
121
  // Apply row header styling
127
122
  if (isHeader) {
128
- cell_style_row_header.call(this, regularTable, td, metadata as any);
123
+ cell_style_row_header(model, regularTable, td, metadata as any);
129
124
  }
130
125
 
131
126
  // Set data attributes
@@ -152,55 +147,56 @@ export function applyBodyCellStyles(
152
147
  delete td.dataset.x;
153
148
  }
154
149
 
155
- // Apply selection styling (if selectable)
150
+ // Apply tree selection styling (SELECT_ROW_TREE).
151
+ // psp-select-region-inactive is exclusively a tree-selection class,
152
+ // so always clean it up. psp-select-region is shared with the
153
+ // coordinate-based selection modes, so only touch it when in
154
+ // SELECT_ROW_TREE mode (isSelectable).
155
+ td.classList.toggle("psp-select-region-inactive", false);
156
156
  if (isSelectable) {
157
- if (!hasSelected) {
158
- td.classList.toggle("psp-row-selected", false);
159
- td.classList.toggle("psp-row-subselected", false);
157
+ if (!selectedId) {
158
+ td.classList.toggle("psp-select-region", false);
160
159
  } else {
161
- const id = this._ids[(metadata.y ?? 0) - (metadata.y0 ?? 0)];
162
- const key_match = (selected as unknown[]).reduce<boolean>(
160
+ const id = model._ids[(metadata.y ?? 0) - (metadata.y0 ?? 0)];
161
+ const key_match = selectedId.reduce<boolean>(
163
162
  (agg, x, i) => agg && x === id[i],
164
163
  true,
165
164
  );
166
165
 
167
- const selectedArr = selected as unknown[];
166
+ const isExact = id.length === selectedId.length && key_match;
167
+ const isSub = id.length !== selectedId.length && key_match;
168
+
168
169
  if (isHeader) {
169
170
  if (
170
171
  metadata.type === "row_header" &&
171
172
  metadata.row_header_x !== undefined &&
172
173
  !!id[metadata.row_header_x]
173
174
  ) {
174
- td.classList.toggle("psp-row-selected", false);
175
- td.classList.toggle("psp-row-subselected", false);
175
+ td.classList.toggle("psp-select-region", false);
176
176
  } else {
177
+ td.classList.toggle("psp-select-region", isExact);
177
178
  td.classList.toggle(
178
- "psp-row-selected",
179
- id.length === selectedArr.length && key_match,
180
- );
181
- td.classList.toggle(
182
- "psp-row-subselected",
183
- id.length !== selectedArr.length && key_match,
179
+ "psp-select-region-inactive",
180
+ isSub,
184
181
  );
185
182
  }
186
183
  } else {
187
- td.classList.toggle(
188
- "psp-row-selected",
189
- id.length === selectedArr.length && key_match,
190
- );
191
- td.classList.toggle(
192
- "psp-row-subselected",
193
- id.length !== selectedArr.length && key_match,
194
- );
184
+ td.classList.toggle("psp-select-region", isExact);
185
+ td.classList.toggle("psp-select-region-inactive", isSub);
195
186
  }
196
187
  }
188
+ // } else if (
189
+ // model._edit_mode === "READ_ONLY" ||
190
+ // model._edit_mode === "EDIT"
191
+ // ) {
192
+ // td.classList.toggle("psp-select-region", false);
197
193
  }
198
194
 
199
195
  // Apply editable styling (if editable)
200
196
  if (!isHeader && metadata.type === "body") {
201
- if (isEditable && this._is_editable[metadata.x]) {
197
+ if (isEditable && model._is_editable[metadata.x]) {
202
198
  const col_name =
203
- metadata.column_header?.[this._config.split_by.length];
199
+ metadata.column_header?.[model._config.split_by.length];
204
200
  const col_name_str = col_name?.toString();
205
201
  if (
206
202
  col_name_str &&
@@ -219,6 +215,7 @@ export function applyBodyCellStyles(
219
215
  if (isEditable !== td.hasAttribute("contenteditable")) {
220
216
  td.toggleAttribute("contenteditable", isEditable);
221
217
  }
218
+
222
219
  td.classList.toggle("boolean-editable", false);
223
220
  }
224
221
  } else {
@@ -11,12 +11,9 @@
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
13
  import { RegularTableElement } from "regular-table";
14
- import {
15
- get_psp_type,
16
- type DatagridModel,
17
- type PerspectiveViewerElement,
18
- } from "../types.js";
14
+ import { get_psp_type, type DatagridModel } from "../types.js";
19
15
  import { CollectedHeaderRow } from "./types.js";
16
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
20
17
 
21
18
  /**
22
19
  * Apply selected column styling in response to column settings toggle events.
@@ -24,9 +21,9 @@ import { CollectedHeaderRow } from "./types.js";
24
21
  * the column settings panel.
25
22
  */
26
23
  export function style_selected_column(
27
- this: DatagridModel,
24
+ model: DatagridModel,
28
25
  regularTable: RegularTableElement,
29
- viewer: PerspectiveViewerElement,
26
+ viewer: HTMLPerspectiveViewerElement,
30
27
  selectedColumn: string | undefined,
31
28
  ): void {
32
29
  const group_header_trs = Array.from(
@@ -72,10 +69,13 @@ export function style_selected_column(
72
69
  const open = title.textContent === selectedColumn;
73
70
  title.classList.toggle("psp-menu-open", open);
74
71
  editBtn.classList.toggle("psp-menu-open", open);
75
- if (this._config.columns.length > 1) {
72
+ if (model._config.columns.length > 1) {
76
73
  for (const r of regularTable.querySelectorAll("td")) {
77
74
  const meta = regularTable.getMeta(r);
78
- if (!meta?.column_header) continue;
75
+ if (!meta?.column_header) {
76
+ continue;
77
+ }
78
+
79
79
  const isOpen =
80
80
  meta.column_header[
81
81
  meta.column_header.length - 2
@@ -92,34 +92,35 @@ export function style_selected_column(
92
92
  * Style a single column header row.
93
93
  */
94
94
  export function styleColumnHeaderRow(
95
- this: DatagridModel,
95
+ model: DatagridModel,
96
96
  headerRow: CollectedHeaderRow,
97
97
  regularTable: RegularTableElement,
98
98
  is_menu_row: boolean,
99
99
  ): void {
100
100
  const header_depth =
101
- this._config.group_by.length -
102
- (this._config.group_rollup_mode === "flat" ? 1 : 0);
101
+ model._config.group_by.length -
102
+ (model._config.group_rollup_mode === "flat" ? 1 : 0);
103
103
 
104
- const selectedColumn = this._column_settings_selected_column;
104
+ const selectedColumn = model._column_settings_selected_column;
105
105
  for (const { element: td, metadata } of headerRow.cells) {
106
106
  if (
107
107
  !metadata ||
108
108
  metadata.type === "body" ||
109
109
  metadata.type === "row_header"
110
- )
110
+ ) {
111
111
  continue;
112
+ }
112
113
 
113
114
  const column_name =
114
- metadata.column_header?.[this._config.split_by.length];
115
+ metadata.column_header?.[model._config.split_by.length];
115
116
 
116
- const sort = this._config.sort.find((x) => x[0] === column_name);
117
+ const sort = model._config.sort.find((x) => x[0] === column_name);
117
118
  const is_corner = typeof metadata.x === "undefined";
118
119
  const needs_border =
119
120
  (metadata.type === "corner" &&
120
121
  metadata.row_header_x === header_depth) ||
121
122
  (!is_corner &&
122
- (metadata.x + 1) % this._config.columns.length === 0);
123
+ (metadata.x + 1) % model._config.columns.length === 0);
123
124
 
124
125
  td.classList.toggle("psp-header-border", needs_border);
125
126
  td.classList.toggle("psp-header-group", false);
@@ -159,7 +160,7 @@ export function styleColumnHeaderRow(
159
160
  !is_menu_row && !!sort && sort[1] === "col desc abs",
160
161
  );
161
162
 
162
- const type = get_psp_type(this, metadata);
163
+ const type = get_psp_type(model, metadata);
163
164
  const is_numeric = type === "integer" || type === "float";
164
165
  const is_string = type === "string";
165
166
  const is_date = type === "date";
@@ -171,13 +172,13 @@ export function styleColumnHeaderRow(
171
172
  "psp-menu-enabled",
172
173
  (is_string || is_numeric || is_date || is_datetime) &&
173
174
  !is_corner &&
174
- metadata.column_header_y === this._config.split_by.length + 1,
175
+ metadata.column_header_y === model._config.split_by.length + 1,
175
176
  );
176
177
  td.classList.toggle(
177
178
  "psp-sort-enabled",
178
179
  (is_string || is_numeric || is_date || is_datetime) &&
179
180
  !is_corner &&
180
- metadata.column_header_y === this._config.split_by.length,
181
+ metadata.column_header_y === model._config.split_by.length,
181
182
  );
182
183
  td.classList.toggle(
183
184
  "psp-is-width-override",
@@ -185,7 +186,7 @@ export function styleColumnHeaderRow(
185
186
  );
186
187
 
187
188
  // Apply menu-open for selected column
188
- if (this._config.columns.length > 1 && selectedColumn) {
189
+ if (model._config.columns.length > 1 && selectedColumn) {
189
190
  const isOpen =
190
191
  metadata.column_header?.[metadata.column_header.length - 2] ===
191
192
  selectedColumn;
@@ -14,69 +14,19 @@ import { RegularTableElement } from "regular-table";
14
14
  import { PRIVATE_PLUGIN_SYMBOL } from "../model/index.js";
15
15
  import type {
16
16
  DatagridModel,
17
- PerspectiveViewerElement,
18
17
  ColumnsConfig,
19
18
  DatagridPluginElement,
20
- SelectedPosition,
19
+ SelectedPositionMap,
21
20
  } from "../types.js";
21
+ import { isEditableMode } from "../types.js";
22
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
22
23
 
23
24
  import { applyFocusStyle } from "./focus.js";
24
- import { styleColumnHeaderRow } from "./column_header.js";
25
25
  import { applyColumnHeaderStyles } from "./editable.js";
26
26
  import { applyGroupHeaderStyles } from "./group_header.js";
27
27
  import { applyBodyCellStyles } from "./body.js";
28
28
  import { CellMetadata } from "regular-table/dist/esm/types.js";
29
-
30
- interface CollectedCell {
31
- element: HTMLElement;
32
- metadata: CellMetadata;
33
- isHeader: boolean;
34
- }
35
-
36
- interface CollectedHeaderRow {
37
- row: HTMLTableRowElement;
38
- cells: Array<{
39
- element: HTMLTableCellElement;
40
- metadata: CellMetadata | undefined;
41
- }>;
42
- }
43
-
44
- /**
45
- * Context object passed through consolidated styling
46
- */
47
- export interface StyleContext {
48
- model: DatagridModel;
49
- regularTable: RegularTableElement;
50
- viewer: PerspectiveViewerElement;
51
- datagrid: DatagridPluginElement;
52
- plugins: ColumnsConfig;
53
- isSettingsOpen: boolean;
54
- isSelectable: boolean;
55
- isEditable: boolean;
56
- selectedRowsMap: Map<RegularTableElement, unknown[]>;
57
- selectedPositionMap: Map<RegularTableElement, SelectedPosition>;
58
- }
59
-
60
- // Local types for selection maps - match the actual runtime usage
61
- // (activate.ts uses `as any` casts when passing these)
62
- type LocalSelectedRowsMap = WeakMap<RegularTableElement, unknown[]>;
63
- type LocalSelectedPositionMap = WeakMap<RegularTableElement, SelectedPosition>;
64
-
65
- function isEditableMode(
66
- model: DatagridModel,
67
- viewer: PerspectiveViewerElement,
68
- allowed: boolean = false,
69
- ): boolean {
70
- const has_pivots =
71
- model._config.group_by.length === 0 &&
72
- model._config.split_by.length === 0;
73
- const selectable = viewer.hasAttribute("selectable");
74
- const plugin = viewer.children[0] as
75
- | (DatagridPluginElement & { dataset: DOMStringMap })
76
- | undefined;
77
- const editable = allowed || plugin?.dataset?.editMode === "EDIT";
78
- return has_pivots && !selectable && editable;
79
- }
29
+ import { CollectedCell, CollectedHeaderRow } from "./types.js";
80
30
 
81
31
  /**
82
32
  * Consolidated style listener that handles all cell styling in a single pass.
@@ -86,24 +36,18 @@ function isEditableMode(
86
36
  */
87
37
  export function createConsolidatedStyleListener(
88
38
  datagrid: DatagridPluginElement,
89
- selectedRowsMap: LocalSelectedRowsMap,
90
- selectedPositionMap: LocalSelectedPositionMap,
91
- ): (
92
- this: DatagridModel,
39
+ model: DatagridModel,
93
40
  regularTable: RegularTableElement,
94
- viewer: PerspectiveViewerElement,
95
- ) => void {
96
- return function consolidatedStyleListener(
97
- this: DatagridModel,
98
- regularTable: RegularTableElement,
99
- viewer: PerspectiveViewerElement,
100
- ): void {
41
+ viewer: HTMLPerspectiveViewerElement,
42
+ selectedPositionMap: SelectedPositionMap,
43
+ ): () => void {
44
+ return function consolidatedStyleListener(): void {
101
45
  const plugins: ColumnsConfig =
102
46
  (regularTable as any)[PRIVATE_PLUGIN_SYMBOL] || {};
103
47
  const isSettingsOpen = viewer.hasAttribute("settings");
104
- const isSelectable = viewer.hasAttribute("selectable");
105
- const isEditable = isEditableMode(this, viewer);
106
- const isEditableAllowed = isEditableMode(this, viewer, true);
48
+ const isSelectable = model._edit_mode === "SELECT_ROW_TREE";
49
+ const isEditable = isEditableMode(model, viewer);
50
+ const isEditableAllowed = isEditableMode(model, viewer, true);
107
51
 
108
52
  // Toggle edit mode class on datagrid
109
53
  datagrid.classList.toggle("edit-mode-allowed", isEditableAllowed);
@@ -117,7 +61,11 @@ export function createConsolidatedStyleListener(
117
61
  cell as HTMLElement,
118
62
  ) as CellMetadata | undefined;
119
63
 
120
- if (metadata) {
64
+ if (
65
+ metadata &&
66
+ (metadata.type === "body" ||
67
+ metadata.type === "row_header")
68
+ ) {
121
69
  const isHeader = cell.tagName === "TH";
122
70
  bodyCells.push({
123
71
  element: cell as HTMLElement,
@@ -148,71 +96,23 @@ export function createConsolidatedStyleListener(
148
96
  metadata,
149
97
  });
150
98
  }
99
+
151
100
  groupHeaderRows.push(rowData);
152
101
  }
153
102
  }
154
103
 
155
- this._applyBodyCellStyles(
104
+ applyBodyCellStyles(
105
+ model,
156
106
  bodyCells,
157
107
  plugins,
158
108
  isSettingsOpen,
159
109
  isSelectable,
160
110
  isEditable,
161
111
  regularTable,
162
- selectedRowsMap,
163
- selectedPositionMap,
164
- viewer,
165
112
  );
166
113
 
167
- this._applyGroupHeaderStyles(groupHeaderRows, regularTable);
168
- this._applyColumnHeaderStyles(groupHeaderRows, regularTable, viewer);
169
- this._applyFocusStyle(bodyCells, regularTable, selectedPositionMap);
114
+ applyGroupHeaderStyles(model, groupHeaderRows, regularTable);
115
+ applyColumnHeaderStyles(model, groupHeaderRows, regularTable, viewer);
116
+ applyFocusStyle(model, bodyCells, regularTable, selectedPositionMap);
170
117
  };
171
118
  }
172
-
173
- declare module "../types.js" {
174
- interface DatagridModel {
175
- _applyBodyCellStyles(
176
- cells: CollectedCell[],
177
- plugins: ColumnsConfig,
178
- isSettingsOpen: boolean,
179
- isSelectable: boolean,
180
- isEditable: boolean,
181
- regularTable: RegularTableElement,
182
- selectedRowsMap: LocalSelectedRowsMap,
183
- selectedPositionMap: LocalSelectedPositionMap,
184
- viewer: PerspectiveViewerElement,
185
- ): void;
186
- _applyGroupHeaderStyles(
187
- headerRows: CollectedHeaderRow[],
188
- regularTable: RegularTableElement,
189
- ): void;
190
- _applyColumnHeaderStyles(
191
- headerRows: CollectedHeaderRow[],
192
- regularTable: RegularTableElement,
193
- viewer: PerspectiveViewerElement,
194
- ): void;
195
- _applyFocusStyle(
196
- cells: CollectedCell[],
197
- regularTable: RegularTableElement,
198
- selectedPositionMap: LocalSelectedPositionMap,
199
- ): void;
200
- _styleColumnHeaderRow(
201
- headerRow: CollectedHeaderRow,
202
- regularTable: RegularTableElement,
203
- is_menu_row: boolean,
204
- ): void;
205
- }
206
- }
207
-
208
- /**
209
- * Install the styling methods on the DatagridModel prototype.
210
- * This should be called once during module initialization.
211
- */
212
- export function installConsolidatedStyleMethods(modelPrototype: any): void {
213
- modelPrototype._applyBodyCellStyles = applyBodyCellStyles;
214
- modelPrototype._applyGroupHeaderStyles = applyGroupHeaderStyles;
215
- modelPrototype._applyColumnHeaderStyles = applyColumnHeaderStyles;
216
- modelPrototype._applyFocusStyle = applyFocusStyle;
217
- modelPrototype._styleColumnHeaderRow = styleColumnHeaderRow;
218
- }
@@ -12,7 +12,9 @@
12
12
 
13
13
  import { RegularTableElement } from "regular-table";
14
14
 
15
- import type { DatagridModel, PerspectiveViewerElement } from "../types.js";
15
+ import type { DatagridModel } from "../types.js";
16
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
17
+ import { styleColumnHeaderRow } from "./column_header.js";
16
18
 
17
19
  import { CollectedHeaderRow } from "./types.js";
18
20
 
@@ -20,15 +22,17 @@ import { CollectedHeaderRow } from "./types.js";
20
22
  * Apply styles to column header rows.
21
23
  */
22
24
  export function applyColumnHeaderStyles(
23
- this: DatagridModel,
25
+ model: DatagridModel,
24
26
  headerRows: CollectedHeaderRow[],
25
27
  regularTable: RegularTableElement,
26
- viewer: PerspectiveViewerElement,
28
+ viewer: HTMLPerspectiveViewerElement,
27
29
  ): void {
28
- if (headerRows.length === 0) return;
30
+ if (headerRows.length === 0) {
31
+ return;
32
+ }
29
33
 
30
34
  // Style selected column for settings panel
31
- const selectedColumn = this._column_settings_selected_column;
35
+ const selectedColumn = model._column_settings_selected_column;
32
36
  const len = headerRows.length;
33
37
  const settings_open = viewer.hasAttribute("settings");
34
38
 
@@ -66,7 +70,9 @@ export function applyColumnHeaderStyles(
66
70
  for (let i = 0; i < titlesRow.cells.length; i++) {
67
71
  const title = titlesRow.cells[i]?.element;
68
72
  const editBtn = editBtnsRow.cells[i]?.element;
69
- if (!title || !editBtn) continue;
73
+ if (!title || !editBtn) {
74
+ continue;
75
+ }
70
76
 
71
77
  const open = title.textContent === selectedColumn;
72
78
  title.classList.toggle("psp-menu-open", open);
@@ -76,19 +82,19 @@ export function applyColumnHeaderStyles(
76
82
  }
77
83
 
78
84
  // Style the actual column header rows
79
- const colHeadersIndex = this._config.split_by.length;
85
+ const colHeadersIndex = model._config.split_by.length;
80
86
  if (colHeadersIndex < headerRows.length) {
81
87
  const colHeaders = headerRows[colHeadersIndex];
82
88
  if (colHeaders) {
83
- this._styleColumnHeaderRow(colHeaders, regularTable, false);
89
+ styleColumnHeaderRow(model, colHeaders, regularTable, false);
84
90
  }
85
91
  }
86
92
 
87
- const menuHeadersIndex = this._config.split_by.length + 1;
93
+ const menuHeadersIndex = model._config.split_by.length + 1;
88
94
  if (menuHeadersIndex < headerRows.length) {
89
95
  const menuHeaders = headerRows[menuHeadersIndex];
90
96
  if (menuHeaders) {
91
- this._styleColumnHeaderRow(menuHeaders, regularTable, true);
97
+ styleColumnHeaderRow(model, menuHeaders, regularTable, true);
92
98
  }
93
99
  }
94
100
  }
@@ -11,18 +11,18 @@
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
13
  import { RegularTableElement } from "regular-table";
14
- import type { DatagridModel, SelectedPosition } from "../types.js";
15
- import { CollectedCell, LocalSelectedPositionMap } from "./types.js";
14
+ import type { DatagridModel, SelectedPositionMap } from "../types.js";
15
+ import { CollectedCell } from "./types.js";
16
16
 
17
17
  /**
18
18
  * Apply focus style to the selected cell.
19
19
  * Optimized to use collected cells instead of querySelectorAll.
20
20
  */
21
21
  export function applyFocusStyle(
22
- this: DatagridModel,
22
+ _model: DatagridModel,
23
23
  cells: CollectedCell[],
24
24
  regularTable: RegularTableElement,
25
- selectedPositionMap: LocalSelectedPositionMap,
25
+ selectedPositionMap: SelectedPositionMap,
26
26
  ): void {
27
27
  const selected_position = selectedPositionMap.get(regularTable);
28
28
  const host = regularTable.getRootNode() as Document;
@@ -37,6 +37,7 @@ export function applyFocusStyle(
37
37
  if (host.activeElement !== td) {
38
38
  td.focus({ preventScroll: true });
39
39
  }
40
+
40
41
  return;
41
42
  }
42
43
  }
@@ -60,7 +61,7 @@ export function applyFocusStyle(
60
61
  */
61
62
  export function focusSelectedCell(
62
63
  regularTable: RegularTableElement,
63
- selectedPositionMap: Map<RegularTableElement, SelectedPosition>,
64
+ selectedPositionMap: SelectedPositionMap,
64
65
  ): boolean {
65
66
  const selected_position = selectedPositionMap.get(regularTable);
66
67
  if (!selected_position) {
@@ -82,6 +83,7 @@ export function focusSelectedCell(
82
83
  if (host.activeElement !== cell) {
83
84
  (cell as HTMLElement).focus({ preventScroll: true });
84
85
  }
86
+
85
87
  return true;
86
88
  }
87
89
  }