@perspective-dev/viewer-datagrid 4.4.1 → 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 (37) hide show
  1. package/dist/cdn/perspective-viewer-datagrid.js +4 -4
  2. package/dist/cdn/perspective-viewer-datagrid.js.map +4 -4
  3. package/dist/esm/custom_elements/datagrid.d.ts +12 -17
  4. package/dist/esm/model/meta_columns.d.ts +1 -0
  5. package/dist/esm/perspective-viewer-datagrid.js +3 -3
  6. package/dist/esm/perspective-viewer-datagrid.js.map +4 -4
  7. package/dist/esm/plugin/column_config_schema.d.ts +31 -0
  8. package/package.json +1 -1
  9. package/src/ts/color_utils.ts +50 -13
  10. package/src/ts/custom_elements/datagrid.ts +63 -48
  11. package/src/ts/data_listener/format_tree_header.ts +2 -2
  12. package/src/ts/data_listener/formatter_cache.ts +8 -95
  13. package/src/ts/data_listener/index.ts +9 -3
  14. package/src/ts/event_handlers/click/edit_click.ts +3 -0
  15. package/src/ts/event_handlers/dispatch_click.ts +4 -1
  16. package/src/ts/event_handlers/expand_collapse.ts +4 -1
  17. package/src/ts/event_handlers/header_click.ts +9 -3
  18. package/src/ts/event_handlers/keydown/edit_keydown.ts +11 -2
  19. package/src/ts/event_handlers/select_region.ts +15 -4
  20. package/src/ts/event_handlers/sort.ts +4 -1
  21. package/src/ts/get_cell_config.ts +10 -3
  22. package/src/ts/model/column_overrides.ts +3 -5
  23. package/src/ts/model/create.ts +22 -5
  24. package/src/ts/{plugin/column_style_controls.ts → model/meta_columns.ts} +33 -62
  25. package/src/ts/model/toolbar.ts +11 -2
  26. package/src/ts/plugin/activate.ts +3 -1
  27. package/src/ts/plugin/column_config_schema.ts +187 -0
  28. package/src/ts/plugin/draw.ts +1 -0
  29. package/src/ts/plugin/restore.ts +6 -2
  30. package/src/ts/plugin/save.ts +1 -5
  31. package/src/ts/style_handlers/body.ts +6 -2
  32. package/src/ts/style_handlers/column_header.ts +6 -2
  33. package/src/ts/style_handlers/consolidated.ts +1 -0
  34. package/src/ts/style_handlers/editable.ts +6 -2
  35. package/src/ts/style_handlers/focus.ts +2 -0
  36. package/src/ts/style_handlers/group_header.ts +10 -4
  37. package/dist/esm/plugin/column_style_controls.d.ts +0 -28
@@ -37,7 +37,10 @@ export async function sortHandler(
37
37
  target: HTMLElement,
38
38
  ): Promise<void> {
39
39
  const meta = regularTable.getMeta(target);
40
- if (!meta?.column_header) return;
40
+ if (!meta?.column_header) {
41
+ return;
42
+ }
43
+
41
44
  const column_name = meta.column_header[model._config.split_by.length];
42
45
  const sort_method =
43
46
  event.ctrlKey ||
@@ -12,6 +12,7 @@
12
12
 
13
13
  import type { View, ViewConfig, Filter, Scalar } from "@perspective-dev/client";
14
14
  import type { CellConfigResult } from "./types.js";
15
+ import { isMetaColumn } from "./model/meta_columns.js";
15
16
 
16
17
  interface ModelWithViewAndConfig {
17
18
  _view: View;
@@ -42,8 +43,14 @@ export default async function getCellConfig(
42
43
  })
43
44
  .filter((x): x is Filter => x !== undefined);
44
45
 
45
- const column_index = group_by.length > 0 ? col_idx + 1 : col_idx;
46
- const column_paths = Object.keys(r[0])[column_index];
46
+ // Filter out *all* meta columns before indexing into the row's
47
+ // keys the DuckDB virtual server's JSON output now includes
48
+ // per-level `__ROW_PATH_<n>__` columns alongside the
49
+ // `__ROW_PATH__` sidecar, so the previous `+1` skip (which
50
+ // assumed exactly one leading meta column) lands on a meta key
51
+ // when group_by has multiple levels.
52
+ const user_keys = Object.keys(r[0]).filter((k) => !isMetaColumn(k));
53
+ const column_paths = user_keys[col_idx];
47
54
  const result: CellConfigResult = {
48
55
  row: r[0] as Record<string, unknown>,
49
56
  column_names: [],
@@ -60,7 +67,7 @@ export default async function getCellConfig(
60
67
  return pivot_value ? [pivot, "==", pivot_value] : undefined;
61
68
  })
62
69
  .filter((x): x is Filter => x !== undefined)
63
- .filter(([, , value]) => value !== "__ROW_PATH__");
70
+ .filter(([, , value]) => !isMetaColumn(value as string));
64
71
  }
65
72
 
66
73
  const filter = _config.filter.concat(row_filters).concat(column_filters);
@@ -10,11 +10,7 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import type {
14
- ColumnOverrides,
15
- DatagridPluginElement,
16
- RegularTable,
17
- } from "../types.js";
13
+ import type { ColumnOverrides, DatagridPluginElement } from "../types.js";
18
14
 
19
15
  interface RegularTableWithOverrides {
20
16
  restoreColumnSizes(overrides: Record<number, number | undefined>): void;
@@ -60,6 +56,7 @@ export function restore_column_size_overrides(
60
56
  | undefined;
61
57
  } else {
62
58
  const index = this.model!._column_paths.indexOf(key);
59
+
63
60
  // Skip keys that don't resolve to a known column — e.g. on the
64
61
  // first draw after `activate`, `_column_paths` has not yet been
65
62
  // populated by the data listener, so we leave any existing
@@ -68,6 +65,7 @@ export function restore_column_size_overrides(
68
65
  if (index === -1) {
69
66
  continue;
70
67
  }
68
+
71
69
  overrides[index + tree_header_offset] = old_sizes[key] as
72
70
  | number
73
71
  | undefined;
@@ -29,21 +29,36 @@ import {
29
29
  import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
30
30
 
31
31
  function arraysChanged<T>(a: T[], b: T[]): boolean {
32
- if (a.length !== b.length) return true;
32
+ if (a.length !== b.length) {
33
+ return true;
34
+ }
35
+
33
36
  for (let i = 0; i < a.length; i++) {
34
- if (a[i] !== b[i]) return true;
37
+ if (a[i] !== b[i]) {
38
+ return true;
39
+ }
35
40
  }
41
+
36
42
  return false;
37
43
  }
38
44
 
39
45
  function nestedArraysChanged<T>(a: T[][], b: T[][]): boolean {
40
- if (a.length !== b.length) return true;
46
+ if (a.length !== b.length) {
47
+ return true;
48
+ }
49
+
41
50
  for (let i = 0; i < a.length; i++) {
42
- if (a[i].length !== b[i].length) return true;
51
+ if (a[i].length !== b[i].length) {
52
+ return true;
53
+ }
54
+
43
55
  for (let j = 0; j < a[i].length; j++) {
44
- if (a[i][j] !== b[i][j]) return true;
56
+ if (a[i][j] !== b[i][j]) {
57
+ return true;
58
+ }
45
59
  }
46
60
  }
61
+
47
62
  return false;
48
63
  }
49
64
 
@@ -75,6 +90,7 @@ class ElemFactoryImpl implements ElemFactory {
75
90
  if (!this._elements[this._index]) {
76
91
  this._elements[this._index] = document.createElement(this._name);
77
92
  }
93
+
78
94
  const elem = this._elements[this._index];
79
95
  this._index += 1;
80
96
  return elem;
@@ -216,6 +232,7 @@ export async function createModel(
216
232
  }),
217
233
  _series_color_map: new Map<string, string>(),
218
234
  _series_color_seed: new Map<string, number>(),
235
+
219
236
  // get_psp_type,
220
237
  _div_factory: extend._div_factory || new ElemFactoryImpl("div"),
221
238
  }) as DatagridModel;
@@ -10,67 +10,38 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import type { ColumnType } from "@perspective-dev/client";
14
- import type { DatagridPluginElement } from "../types.js";
13
+ /**
14
+ * Single-source-of-truth predicate for "this column is metadata, hide
15
+ * it from the user-visible grid." Five distinct names show up across
16
+ * the perspective protocol; older datagrid code filtered them by
17
+ * exact-match in three places, which only worked when the wire shape
18
+ * was the JSON-sidecar form (`__ROW_PATH__` array-of-arrays).
19
+ *
20
+ * The DuckDB virtual-server backend additionally surfaces per-level
21
+ * `__ROW_PATH_<n>__` columns directly in `to_columns_string` /
22
+ * `to_json` output (a side effect of keeping them in the frozen Arrow
23
+ * batch so that `to_arrow` consumers — viewer-charts via
24
+ * `with_typed_arrays` — see them inline, matching native
25
+ * `perspective-server`'s `to_arrow` behavior). Without this helper,
26
+ * those per-level columns slip through the legacy exact-match filters
27
+ * and render as user columns to the right of the grid.
28
+ *
29
+ * Match list:
30
+ * - `__ROW_PATH__` — JSON sidecar; used by the tree header.
31
+ * - `__ROW_PATH_<n>__` — per-level columns from the virtual server's
32
+ * inline-arrow shape.
33
+ * - `__ID__` — per-row identity column.
34
+ * - `__GROUPING_ID__` — internal SQL-rollup discriminator. The
35
+ * virtual server strips it server-side, but
36
+ * we cover it defensively in case a future
37
+ * backend leaks it.
38
+ *
39
+ * User columns named with leading/trailing double-underscores (e.g.
40
+ * `__user_col__`) are *not* matched — the regex requires the exact
41
+ * stems above.
42
+ */
43
+ const META_COLUMN_RE = /^__(?:ROW_PATH(?:_\d+)?|ID|GROUPING_ID)__$/;
15
44
 
16
- interface NumberStyleOpts {
17
- datagrid_number_style: {
18
- fg_gradient: number;
19
- pos_fg_color: string;
20
- neg_fg_color: string;
21
- number_fg_mode: string;
22
- bg_gradient: number;
23
- pos_bg_color: string;
24
- neg_bg_color: string;
25
- number_bg_mode: string;
26
- };
27
- number_string_format: boolean;
28
- }
29
-
30
- interface DatetimeStyleOpts {
31
- datagrid_datetime_style?: {
32
- color: string;
33
- bg_color: string;
34
- };
35
- datagrid_string_style?: {
36
- color: string;
37
- bg_color: string;
38
- };
39
- }
40
-
41
- export type ColumnStyleOpts = NumberStyleOpts | DatetimeStyleOpts | null;
42
-
43
- export default function column_style_opts(
44
- this: DatagridPluginElement,
45
- type: ColumnType,
46
- _group: string,
47
- ): ColumnStyleOpts {
48
- if (type === "integer" || type === "float") {
49
- return {
50
- datagrid_number_style: {
51
- fg_gradient: 0,
52
- pos_fg_color: this.model!._pos_fg_color[0],
53
- neg_fg_color: this.model!._neg_fg_color[0],
54
- number_fg_mode: "color",
55
- bg_gradient: 0,
56
- pos_bg_color: this.model!._pos_bg_color[0],
57
- neg_bg_color: this.model!._neg_bg_color[0],
58
- number_bg_mode: "disabled",
59
- },
60
- number_string_format: true,
61
- };
62
- } else if (type === "date" || type === "datetime" || type === "string") {
63
- const control =
64
- type === "date" || type === "datetime"
65
- ? "datagrid_datetime_style"
66
- : `datagrid_string_style`;
67
- return {
68
- [control]: {
69
- color: this.model!._color[0],
70
- bg_color: this.model!._color[0],
71
- },
72
- } as DatetimeStyleOpts;
73
- } else {
74
- return null;
75
- }
45
+ export function isMetaColumn(name: string): boolean {
46
+ return META_COLUMN_RE.test(name);
76
47
  }
@@ -10,6 +10,7 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
+ import { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
13
14
  import type {
14
15
  DatagridModel,
15
16
  DatagridPluginElement,
@@ -26,7 +27,10 @@ export const EDIT_MODES: readonly EditMode[] = [
26
27
  ] as const;
27
28
 
28
29
  function isSelectRowTreeAvailable(model?: DatagridModel): boolean {
29
- if (!model) return false;
30
+ if (!model) {
31
+ return false;
32
+ }
33
+
30
34
  return (
31
35
  model._config.group_by.length > 0 &&
32
36
  model._config.group_rollup_mode !== "flat"
@@ -45,10 +49,11 @@ export function toggle_edit_mode(
45
49
  EDIT_MODES[idx] === "SELECT_ROW_TREE" &&
46
50
  !isSelectRowTreeAvailable(this.model)
47
51
  );
52
+
48
53
  mode = EDIT_MODES[idx];
49
54
  }
50
55
 
51
- (this.parentElement as any)?.setSelection?.();
56
+ (this.parentElement as HTMLPerspectiveViewerElement)?.setSelection?.();
52
57
  this._edit_mode = mode;
53
58
  if (this.model) {
54
59
  this.model._edit_mode = mode;
@@ -59,6 +64,10 @@ export function toggle_edit_mode(
59
64
  };
60
65
  }
61
66
 
67
+ (this.parentElement as HTMLPerspectiveViewerElement)?.restore?.({
68
+ plugin_config: { edit_mode: mode },
69
+ });
70
+
62
71
  if (this._edit_button !== undefined) {
63
72
  this._edit_button.dataset.editMode = mode;
64
73
  }
@@ -91,7 +91,9 @@ export async function activate(
91
91
  area: SelectionArea,
92
92
  isDeselect: boolean,
93
93
  ) => {
94
- if (model._edit_mode !== "SELECT_ROW_TREE") return;
94
+ if (model._edit_mode !== "SELECT_ROW_TREE") {
95
+ return;
96
+ }
95
97
 
96
98
  // Store the selected row identity on the model so it persists
97
99
  // even when the selected row scrolls out of the viewport.
@@ -0,0 +1,187 @@
1
+ // ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2
+ // ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3
+ // ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4
+ // ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5
+ // ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6
+ // ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7
+ // ┃ Copyright (c) 2017, the Perspective Authors. ┃
8
+ // ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9
+ // ┃ This file is part of the Perspective library, distributed under the terms ┃
10
+ // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
+
13
+ import type { ColumnType } from "@perspective-dev/client";
14
+ import type { DatagridPluginElement } from "../types.js";
15
+
16
+ interface ViewerConfigLike {
17
+ group_by?: string[];
18
+ group_rollup_mode?: string;
19
+ }
20
+
21
+ type ControlSpec = Record<string, unknown> & { kind: string };
22
+
23
+ export interface ColumnConfigSchema {
24
+ fields: ControlSpec[];
25
+ }
26
+
27
+ /**
28
+ * Plugin schema for the Datagrid column-settings sidebar. Returns the
29
+ * controls the viewer should render in the Style tab for a given column.
30
+ *
31
+ * Each entry in `fields` is a `ControlSpec` discriminated by `kind`.
32
+ * Composite kinds (`NumberStyle`, `DatetimeFormat`, `StringFormat`,
33
+ * `NumberFormat`, `AggregateDepth`) own a fixed key namespace and
34
+ * carry only their `default`. Primitive kinds (`Enum`, `Bool`, `Color`,
35
+ * etc.) carry their own `key` (storage) and `label` (UI) inline.
36
+ *
37
+ * Aggregate Depth is plugin-owned — surfaced only inside the Datagrid
38
+ * because rollup-mode pivots are a Datagrid concern. Emitted only when
39
+ * the active view has a non-empty `group_by` and rollup mode is `Rollup`.
40
+ */
41
+ interface ColumnStats {
42
+ abs_max?: number;
43
+ }
44
+
45
+ export default function column_config_schema(
46
+ this: DatagridPluginElement,
47
+ type: ColumnType,
48
+ _group: string | undefined,
49
+ _column_name: string,
50
+ current_value: Record<string, unknown> | null,
51
+ viewer_config?: ViewerConfigLike,
52
+ column_stats?: ColumnStats,
53
+ ): ColumnConfigSchema {
54
+ const fields: ControlSpec[] = [];
55
+
56
+ if (type === "integer" || type === "float") {
57
+ const pos_fg = this.model!._pos_fg_color[0];
58
+ const neg_fg = this.model!._neg_fg_color[0];
59
+ const pos_bg = this.model!._pos_bg_color[0];
60
+ const neg_bg = this.model!._neg_bg_color[0];
61
+
62
+ fields.push({
63
+ kind: "Enum",
64
+ key: "number_fg_mode",
65
+ default: "color",
66
+ variants: [
67
+ { value: "disabled", label: "Disabled" },
68
+ { value: "color", label: "Color" },
69
+ { value: "bar", label: "Bar" },
70
+ { value: "label-bar", label: "Gradient" },
71
+ ],
72
+ });
73
+
74
+ const fg_mode = (current_value?.number_fg_mode as string) ?? "color";
75
+ if (fg_mode !== "disabled") {
76
+ fields.push({
77
+ kind: "ColorRange",
78
+ key_pos: "pos_fg_color",
79
+ key_neg: "neg_fg_color",
80
+ default_pos: pos_fg,
81
+ default_neg: neg_fg,
82
+ is_gradient: false,
83
+ });
84
+ }
85
+
86
+ if (fg_mode === "bar" || fg_mode === "label-bar") {
87
+ fields.push({
88
+ kind: "Number",
89
+ key: "fg_gradient",
90
+ default: column_stats?.abs_max ?? 0,
91
+ include: true,
92
+ });
93
+ }
94
+
95
+ fields.push({
96
+ kind: "Enum",
97
+ key: "number_bg_mode",
98
+ default: "disabled",
99
+ variants: [
100
+ { value: "disabled", label: "Disabled" },
101
+ { value: "color", label: "Color" },
102
+ { value: "gradient", label: "Gradient" },
103
+ { value: "pulse", label: "Pulse" },
104
+ ],
105
+ });
106
+
107
+ const bg_mode = (current_value?.number_bg_mode as string) ?? "disabled";
108
+ if (bg_mode !== "disabled") {
109
+ fields.push({
110
+ kind: "ColorRange",
111
+ key_pos: "pos_bg_color",
112
+ key_neg: "neg_bg_color",
113
+ default_pos: pos_bg,
114
+ default_neg: neg_bg,
115
+ is_gradient: bg_mode === "gradient" || bg_mode === "pulse",
116
+ });
117
+ }
118
+
119
+ if (bg_mode === "gradient") {
120
+ fields.push({
121
+ kind: "Number",
122
+ key: "bg_gradient",
123
+ include: true,
124
+ default: column_stats?.abs_max ?? 0,
125
+ });
126
+ }
127
+
128
+ fields.push({ kind: "NumberFormat" });
129
+ } else if (type === "date" || type === "datetime") {
130
+ fields.push({ kind: "DatetimeFormat" });
131
+
132
+ fields.push({
133
+ kind: "Enum",
134
+ key: "datetime_color_mode",
135
+ default: "none",
136
+ variants: [
137
+ { value: "none", label: "None" },
138
+ { value: "foreground", label: "Foreground" },
139
+ { value: "background", label: "Background" },
140
+ ],
141
+ });
142
+
143
+ const dt_mode =
144
+ (current_value?.datetime_color_mode as string) ?? "none";
145
+
146
+ if (dt_mode !== "none") {
147
+ fields.push({
148
+ kind: "Color",
149
+ key: "color",
150
+ default: this.model!._color[0],
151
+ });
152
+ }
153
+ } else if (type === "string") {
154
+ fields.push({ kind: "StringFormat" });
155
+
156
+ fields.push({
157
+ kind: "Enum",
158
+ key: "string_color_mode",
159
+ default: "none",
160
+ variants: [
161
+ { value: "none", label: "None" },
162
+ { value: "foreground", label: "Foreground" },
163
+ { value: "background", label: "Background" },
164
+ { value: "series", label: "Series" },
165
+ ],
166
+ });
167
+
168
+ const str_mode = (current_value?.string_color_mode as string) ?? "none";
169
+ if (str_mode !== "none") {
170
+ fields.push({
171
+ kind: "Color",
172
+ key: "color",
173
+ default: this.model!._color[0],
174
+ });
175
+ }
176
+ }
177
+
178
+ const group_by = viewer_config?.group_by ?? [];
179
+ const is_rollup =
180
+ (viewer_config?.group_rollup_mode ?? "rollup") === "rollup";
181
+
182
+ if (group_by.length > 0 && is_rollup) {
183
+ fields.push({ kind: "AggregateDepth" });
184
+ }
185
+
186
+ return { fields };
187
+ }
@@ -47,6 +47,7 @@ export async function draw(
47
47
  this.regular_table.scrollLeft = 0;
48
48
  this._reset_scroll_left = false;
49
49
  }
50
+
50
51
  if (this._reset_select) {
51
52
  this.regular_table.dispatchEvent(
52
53
  new CustomEvent("psp-deselect-all", { bubbles: false }),
@@ -92,16 +92,20 @@ export function restore(
92
92
  }
93
93
  }
94
94
 
95
- if ("edit_mode" in token && token.edit_mode) {
96
- if (EDIT_MODES.indexOf(token.edit_mode) !== -1) {
95
+ if ("edit_mode" in token) {
96
+ if (EDIT_MODES.indexOf(token.edit_mode!) !== -1) {
97
97
  toggle_edit_mode.call(this, token.edit_mode);
98
98
  } else {
99
99
  console.error("Unknown edit mode " + token.edit_mode);
100
100
  }
101
+ } else {
102
+ toggle_edit_mode.call(this, "READ_ONLY");
101
103
  }
102
104
 
103
105
  if ("scroll_lock" in token) {
104
106
  toggle_scroll_lock.call(this, token.scroll_lock);
107
+ } else {
108
+ toggle_scroll_lock.call(this, false);
105
109
  }
106
110
 
107
111
  const datagrid = this.regular_table;
@@ -11,11 +11,7 @@
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
13
  import { save_column_size_overrides } from "../model/column_overrides.js";
14
- import type {
15
- DatagridPluginElement,
16
- DatagridPluginConfig,
17
- EditMode,
18
- } from "../types.js";
14
+ import type { DatagridPluginElement, DatagridPluginConfig } from "../types.js";
19
15
 
20
16
  export function save(
21
17
  this: DatagridPluginElement,
@@ -185,8 +185,11 @@ export function applyBodyCellStyles(
185
185
  td.classList.toggle("psp-select-region-inactive", isSub);
186
186
  }
187
187
  }
188
- } else {
189
- td.classList.toggle("psp-select-region", false);
188
+ // } else if (
189
+ // model._edit_mode === "READ_ONLY" ||
190
+ // model._edit_mode === "EDIT"
191
+ // ) {
192
+ // td.classList.toggle("psp-select-region", false);
190
193
  }
191
194
 
192
195
  // Apply editable styling (if editable)
@@ -212,6 +215,7 @@ export function applyBodyCellStyles(
212
215
  if (isEditable !== td.hasAttribute("contenteditable")) {
213
216
  td.toggleAttribute("contenteditable", isEditable);
214
217
  }
218
+
215
219
  td.classList.toggle("boolean-editable", false);
216
220
  }
217
221
  } else {
@@ -72,7 +72,10 @@ export function style_selected_column(
72
72
  if (model._config.columns.length > 1) {
73
73
  for (const r of regularTable.querySelectorAll("td")) {
74
74
  const meta = regularTable.getMeta(r);
75
- if (!meta?.column_header) continue;
75
+ if (!meta?.column_header) {
76
+ continue;
77
+ }
78
+
76
79
  const isOpen =
77
80
  meta.column_header[
78
81
  meta.column_header.length - 2
@@ -104,8 +107,9 @@ export function styleColumnHeaderRow(
104
107
  !metadata ||
105
108
  metadata.type === "body" ||
106
109
  metadata.type === "row_header"
107
- )
110
+ ) {
108
111
  continue;
112
+ }
109
113
 
110
114
  const column_name =
111
115
  metadata.column_header?.[model._config.split_by.length];
@@ -96,6 +96,7 @@ export function createConsolidatedStyleListener(
96
96
  metadata,
97
97
  });
98
98
  }
99
+
99
100
  groupHeaderRows.push(rowData);
100
101
  }
101
102
  }
@@ -27,7 +27,9 @@ export function applyColumnHeaderStyles(
27
27
  regularTable: RegularTableElement,
28
28
  viewer: HTMLPerspectiveViewerElement,
29
29
  ): void {
30
- if (headerRows.length === 0) return;
30
+ if (headerRows.length === 0) {
31
+ return;
32
+ }
31
33
 
32
34
  // Style selected column for settings panel
33
35
  const selectedColumn = model._column_settings_selected_column;
@@ -68,7 +70,9 @@ export function applyColumnHeaderStyles(
68
70
  for (let i = 0; i < titlesRow.cells.length; i++) {
69
71
  const title = titlesRow.cells[i]?.element;
70
72
  const editBtn = editBtnsRow.cells[i]?.element;
71
- if (!title || !editBtn) continue;
73
+ if (!title || !editBtn) {
74
+ continue;
75
+ }
72
76
 
73
77
  const open = title.textContent === selectedColumn;
74
78
  title.classList.toggle("psp-menu-open", open);
@@ -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
  }
@@ -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
  }
@@ -28,12 +28,14 @@ export function applyGroupHeaderStyles(
28
28
  let marked = new Set<number>();
29
29
 
30
30
  for (let y = 0; y < headerRows.length; y++) {
31
- const { row, cells } = headerRows[y];
31
+ const { cells } = headerRows[y];
32
32
  const tops = new Set<number>();
33
33
 
34
34
  for (let x = 0; x < cells.length; x++) {
35
35
  const { element: td, metadata } = cells[x];
36
- if (!metadata) continue;
36
+ if (!metadata) {
37
+ continue;
38
+ }
37
39
 
38
40
  td.style.backgroundColor = "";
39
41
 
@@ -63,13 +65,17 @@ export function applyGroupHeaderStyles(
63
65
 
64
66
  // Calculate spanning for psp-is-top
65
67
  let xx = x;
66
- for (; m[y] && m[y][xx]; ++xx);
68
+ for (; m[y] && m[y][xx]; ++xx) {}
69
+
67
70
  tops.add(xx);
68
71
 
69
72
  const cell = td;
70
73
  for (let tx = xx; tx < xx + cell.colSpan; ++tx) {
71
74
  for (let ty = y; ty < y + cell.rowSpan; ++ty) {
72
- if (!m[ty]) m[ty] = [];
75
+ if (!m[ty]) {
76
+ m[ty] = [];
77
+ }
78
+
73
79
  m[ty][tx] = true;
74
80
  }
75
81
  }