@perspective-dev/viewer-datagrid 4.3.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 (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 +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 +6 -2
  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 +3 -5
  39. package/src/css/mitered-headers.css +64 -0
  40. package/src/css/perspective-viewer-datagrid.css +6 -0
  41. package/src/{less/pro.less → css/pro.css} +32 -31
  42. package/src/css/regular_table.css +589 -0
  43. package/src/{less/row-hover.less → css/row-hover.css} +48 -29
  44. package/src/{less/scrollbar.less → css/scrollbar.css} +16 -15
  45. package/src/{less/sub-cell-scroll.less → css/sub-cell-scroll.css} +14 -13
  46. package/src/{less/toolbar.less → css/toolbar.css} +57 -39
  47. package/src/ts/color_utils.ts +144 -16
  48. package/src/ts/custom_elements/datagrid.ts +11 -12
  49. package/src/ts/custom_elements/toolbar.ts +4 -5
  50. package/src/ts/data_listener/format_cell.ts +28 -9
  51. package/src/ts/data_listener/formatter_cache.ts +1 -1
  52. package/src/ts/data_listener/index.ts +4 -8
  53. package/src/ts/event_handlers/click/edit_click.ts +7 -6
  54. package/src/ts/event_handlers/click.ts +39 -68
  55. package/src/ts/event_handlers/dispatch_click.ts +24 -25
  56. package/src/ts/event_handlers/expand_collapse.ts +7 -7
  57. package/src/ts/event_handlers/focus.ts +38 -35
  58. package/src/ts/event_handlers/header_click.ts +101 -62
  59. package/src/ts/event_handlers/keydown/edit_keydown.ts +49 -52
  60. package/src/ts/event_handlers/select_region.ts +144 -133
  61. package/src/ts/event_handlers/sort.ts +16 -24
  62. package/src/ts/model/column_overrides.ts +13 -4
  63. package/src/ts/model/create.ts +55 -59
  64. package/src/ts/model/toolbar.ts +23 -7
  65. package/src/ts/plugin/activate.ts +120 -92
  66. package/src/ts/plugin/column_style_controls.ts +1 -1
  67. package/src/ts/plugin/save.ts +1 -0
  68. package/src/ts/style_handlers/body.ts +56 -61
  69. package/src/ts/style_handlers/column_header.ts +16 -19
  70. package/src/ts/style_handlers/consolidated.ts +22 -123
  71. package/src/ts/style_handlers/editable.ts +10 -8
  72. package/src/ts/style_handlers/focus.ts +5 -5
  73. package/src/ts/style_handlers/group_header.ts +3 -2
  74. package/src/ts/style_handlers/table_cell/boolean.ts +3 -3
  75. package/src/ts/style_handlers/table_cell/cell_flash.ts +11 -11
  76. package/src/ts/style_handlers/table_cell/datetime.ts +14 -11
  77. package/src/ts/style_handlers/table_cell/numeric.ts +24 -25
  78. package/src/ts/style_handlers/table_cell/row_header.ts +2 -2
  79. package/src/ts/style_handlers/table_cell/string.ts +20 -18
  80. package/src/ts/style_handlers/types.ts +0 -10
  81. package/src/ts/types.ts +28 -20
  82. package/dist/esm/event_handlers/deselect_all.d.ts +0 -5
  83. package/dist/esm/event_handlers/row_select_click.d.ts +0 -4
  84. package/src/less/mitered-headers.less +0 -65
  85. package/src/less/regular_table.less +0 -526
  86. package/src/ts/event_handlers/deselect_all.ts +0 -28
  87. package/src/ts/event_handlers/row_select_click.ts +0 -92
@@ -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
  /**
@@ -10,9 +10,8 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import chroma from "chroma-js";
14
13
  import { createDataListener } from "../data_listener/index.js";
15
- import { blend, make_color_record } from "../color_utils.js";
14
+ import { blend, make_color_record, parseColor } from "../color_utils.js";
16
15
  import type {
17
16
  ColumnType,
18
17
  Table,
@@ -26,10 +25,27 @@ import {
26
25
  type Schema,
27
26
  type ElemFactory,
28
27
  type EditMode,
29
- type PerspectiveViewerElement,
30
- get_psp_type,
31
28
  } from "../types.js";
32
- import { CellMetadata } from "regular-table/dist/esm/types.js";
29
+ import type { HTMLPerspectiveViewerElement } from "@perspective-dev/viewer";
30
+
31
+ function arraysChanged<T>(a: T[], b: T[]): boolean {
32
+ if (a.length !== b.length) return true;
33
+ for (let i = 0; i < a.length; i++) {
34
+ if (a[i] !== b[i]) return true;
35
+ }
36
+ return false;
37
+ }
38
+
39
+ function nestedArraysChanged<T>(a: T[][], b: T[][]): boolean {
40
+ if (a.length !== b.length) return true;
41
+ for (let i = 0; i < a.length; i++) {
42
+ if (a[i].length !== b[i].length) return true;
43
+ for (let j = 0; j < a[i].length; j++) {
44
+ if (a[i][j] !== b[i][j]) return true;
45
+ }
46
+ }
47
+ return false;
48
+ }
33
49
 
34
50
  function get_rule(regular: HTMLElement, tag: string, def: string): string {
35
51
  const color = window.getComputedStyle(regular).getPropertyValue(tag).trim();
@@ -70,61 +86,33 @@ export async function createModel(
70
86
  regular: RegularTable,
71
87
  table: Table,
72
88
  view: View,
89
+ theme: string,
73
90
  extend: Partial<DatagridModel> = {},
74
91
  ): Promise<DatagridModel> {
75
92
  const config = (await view.get_config()) as ViewConfig;
76
93
  if (this?.model?._config) {
77
94
  const old = this.model._config;
78
- let group_by_changed = old.group_by.length !== config.group_by.length;
95
+ const group_by_changed = arraysChanged(old.group_by, config.group_by);
79
96
  const type_changed =
80
97
  (old.group_by.length === 0 || config.group_by.length === 0) &&
81
98
  group_by_changed;
82
99
 
83
- if (!group_by_changed) {
84
- for (const lvl in old.group_by) {
85
- group_by_changed ||= config.group_by[lvl] !== old.group_by[lvl];
86
- }
87
- }
88
-
89
- let split_by_changed = old.split_by.length !== config.split_by.length;
90
- if (!split_by_changed) {
91
- for (const lvl in old.split_by) {
92
- split_by_changed ||= config.split_by[lvl] !== old.split_by[lvl];
93
- }
94
- }
100
+ const split_by_changed = arraysChanged(old.split_by, config.split_by);
101
+ const columns_changed = arraysChanged(old.columns, config.columns);
102
+ const filter_changed = nestedArraysChanged(
103
+ old.filter as unknown[][],
104
+ config.filter as unknown[][],
105
+ );
95
106
 
96
- let columns_changed = old.columns.length !== config.columns.length;
97
- if (!columns_changed) {
98
- for (const lvl in old.columns) {
99
- columns_changed ||= config.columns[lvl] !== old.columns[lvl];
100
- }
101
- }
102
-
103
- let filter_changed = old.filter.length !== config.filter.length;
104
- if (!filter_changed) {
105
- for (const lvl in old.filter) {
106
- for (const i in config.filter[lvl]) {
107
- filter_changed ||=
108
- config.filter[lvl][i as unknown as number] !==
109
- old.filter[lvl][i as unknown as number];
110
- }
111
- }
112
- }
113
-
114
- let sort_changed = old.sort.length !== config.sort.length;
115
- if (!sort_changed) {
116
- for (const lvl in old.sort) {
117
- for (const i in config.sort[lvl]) {
118
- sort_changed ||=
119
- config.sort[lvl][i as unknown as number] !==
120
- old.sort[lvl][i as unknown as number];
121
- }
122
- }
123
- }
107
+ const sort_changed = nestedArraysChanged(
108
+ old.sort as unknown[][],
109
+ config.sort as unknown[][],
110
+ );
124
111
 
125
112
  const group_rollup_mode_changed =
126
113
  old.group_rollup_mode !== config.group_rollup_mode;
127
114
 
115
+ const theme_changed = this.model._theme !== theme;
128
116
  this._reset_scroll_top = group_by_changed;
129
117
  this._reset_scroll_left = split_by_changed;
130
118
  this._reset_select =
@@ -139,6 +127,7 @@ export async function createModel(
139
127
  split_by_changed ||
140
128
  group_by_changed ||
141
129
  columns_changed ||
130
+ theme_changed ||
142
131
  type_changed;
143
132
  }
144
133
 
@@ -148,19 +137,19 @@ export async function createModel(
148
137
  view.num_rows(),
149
138
  view.schema(),
150
139
  view.expression_schema(),
151
- (this.parentElement as PerspectiveViewerElement).getEditPort(),
140
+ (this.parentElement as HTMLPerspectiveViewerElement).getEditPort(),
152
141
  ]);
153
142
 
154
- const _plugin_background = chroma(
155
- get_rule(regular, "--plugin--background", "#FFFFFF"),
156
- ).rgb();
143
+ const _plugin_background = parseColor(
144
+ get_rule(regular, "--psp--background-color", "#FFFFFF"),
145
+ );
157
146
 
158
147
  const _pos_fg_color = make_color_record(
159
- get_rule(regular, "--rt-pos-cell--color", "#338DCD"),
148
+ get_rule(regular, "--psp-datagrid--pos-cell--color", "#338DCD"),
160
149
  );
161
150
 
162
151
  const _neg_fg_color = make_color_record(
163
- get_rule(regular, "--rt-neg-cell--color", "#FF5942"),
152
+ get_rule(regular, "--psp-datagrid--neg-cell--color", "#FF5942"),
164
153
  );
165
154
 
166
155
  const _pos_bg_color = make_color_record(
@@ -172,7 +161,7 @@ export async function createModel(
172
161
  );
173
162
 
174
163
  const _color = make_color_record(
175
- get_rule(regular, "--active--color", "#ff0000"),
164
+ get_rule(regular, "--psp-active--color", "#ff0000"),
176
165
  );
177
166
 
178
167
  const _schema: Schema = {
@@ -187,10 +176,17 @@ export async function createModel(
187
176
  const _column_paths: string[] = [];
188
177
  const _is_editable: boolean[] = [];
189
178
  const _column_types: ColumnType[] = [];
179
+ let _edit_mode: EditMode = this._edit_mode || "READ_ONLY";
180
+
181
+ if (
182
+ _edit_mode === "SELECT_ROW_TREE" &&
183
+ (config.group_by.length === 0 || config.group_rollup_mode === "flat")
184
+ ) {
185
+ _edit_mode = "READ_ONLY";
186
+ this._edit_mode = _edit_mode;
187
+ }
190
188
 
191
- const _edit_mode: EditMode = this._edit_mode || "READ_ONLY";
192
189
  this._edit_button!.dataset.editMode = _edit_mode;
193
-
194
190
  const model: DatagridModel = Object.assign(extend, {
195
191
  _edit_port,
196
192
  _view: view,
@@ -208,6 +204,7 @@ export async function createModel(
208
204
  _neg_bg_color,
209
205
  _column_paths,
210
206
  _column_types,
207
+ _theme: theme,
211
208
  _is_editable,
212
209
  _edit_mode,
213
210
  _selection_state: {
@@ -224,10 +221,9 @@ export async function createModel(
224
221
  }) as DatagridModel;
225
222
 
226
223
  regular.setDataListener(
227
- createDataListener(this.parentElement as PerspectiveViewerElement).bind(
228
- model,
229
- regular,
230
- ) as any,
224
+ createDataListener(
225
+ this.parentElement as HTMLPerspectiveViewerElement,
226
+ ).bind(model, regular) as any,
231
227
  {
232
228
  virtual_mode: (window
233
229
  .getComputedStyle(regular)
@@ -10,7 +10,11 @@
10
10
  // ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11
11
  // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12
12
 
13
- import type { DatagridPluginElement, EditMode } from "../types.js";
13
+ import type {
14
+ DatagridModel,
15
+ DatagridPluginElement,
16
+ EditMode,
17
+ } from "../types.js";
14
18
 
15
19
  export const EDIT_MODES: readonly EditMode[] = [
16
20
  "READ_ONLY",
@@ -18,23 +22,37 @@ export const EDIT_MODES: readonly EditMode[] = [
18
22
  "SELECT_ROW",
19
23
  "SELECT_COLUMN",
20
24
  "SELECT_REGION",
25
+ "SELECT_ROW_TREE",
21
26
  ] as const;
22
27
 
28
+ function isSelectRowTreeAvailable(model?: DatagridModel): boolean {
29
+ if (!model) return false;
30
+ return (
31
+ model._config.group_by.length > 0 &&
32
+ model._config.group_rollup_mode !== "flat"
33
+ );
34
+ }
35
+
23
36
  export function toggle_edit_mode(
24
37
  this: DatagridPluginElement,
25
38
  mode?: EditMode,
26
39
  ): void {
27
40
  if (typeof mode === "undefined") {
28
- mode =
29
- EDIT_MODES[
30
- (EDIT_MODES.indexOf(this._edit_mode) + 1) % EDIT_MODES.length
31
- ];
41
+ let idx = EDIT_MODES.indexOf(this._edit_mode);
42
+ do {
43
+ idx = (idx + 1) % EDIT_MODES.length;
44
+ } while (
45
+ EDIT_MODES[idx] === "SELECT_ROW_TREE" &&
46
+ !isSelectRowTreeAvailable(this.model)
47
+ );
48
+ mode = EDIT_MODES[idx];
32
49
  }
33
50
 
34
51
  (this.parentElement as any)?.setSelection?.();
35
52
  this._edit_mode = mode;
36
53
  if (this.model) {
37
54
  this.model._edit_mode = mode;
55
+ this.model._tree_selection_id = undefined;
38
56
  this.model._selection_state = {
39
57
  selected_areas: [],
40
58
  dirty: true,
@@ -44,8 +62,6 @@ export function toggle_edit_mode(
44
62
  if (this._edit_button !== undefined) {
45
63
  this._edit_button.dataset.editMode = mode;
46
64
  }
47
-
48
- this.dataset.editMode = mode;
49
65
  }
50
66
 
51
67
  export function toggle_scroll_lock(