Skip to content

Commit 13b5dd6

Browse files
committed
Better TypeScript support for CellMetadata
1 parent a17ee17 commit 13b5dd6

File tree

9 files changed

+183
-87
lines changed

9 files changed

+183
-87
lines changed

src/ts/constants.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
1010
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1111

12-
// Singleton `WeakMap`s to store metadata for td/th elements, as well as the
13-
// datagrids themselves for each `<perspective-viewer>`
14-
export const METADATA_MAP = new WeakMap();
15-
1612
// Output runtime debug info like FPS.
1713
export const DEBUG = true;
1814

src/ts/events.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
1010
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1111

12-
import { METADATA_MAP } from "./constants";
1312
import { RegularVirtualTableViewModel } from "./scroll_panel";
1413
import { throttle_tag } from "./utils";
1514
import { CellMetadata } from "./types";
15+
import { METADATA_MAP } from "./view_model";
1616

1717
/**
1818
* When enabled, override iOS overscroll behavior by emulating scroll position
@@ -180,7 +180,7 @@ export class RegularViewEventModel extends RegularVirtualTableViewModel {
180180
}
181181

182182
const metadata = METADATA_MAP.get(element);
183-
if (is_resize) {
183+
if (is_resize && metadata) {
184184
event.stopImmediatePropagation();
185185

186186
// Clear column size data
@@ -215,7 +215,7 @@ export class RegularViewEventModel extends RegularVirtualTableViewModel {
215215
: this.table_model.body.cells) {
216216
for (const td of event.shiftKey
217217
? row
218-
: [row[metadata._virtual_x]]) {
218+
: [row[metadata.virtual_x!]]) {
219219
if (!td) {
220220
continue;
221221
}
@@ -250,7 +250,7 @@ export class RegularViewEventModel extends RegularVirtualTableViewModel {
250250
}
251251

252252
const metadata = METADATA_MAP.get(element);
253-
if (is_resize) {
253+
if (is_resize && metadata) {
254254
this._on_resize_column(
255255
event,
256256
element as HTMLTableCellElement,

src/ts/regular-table.ts

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
// ┃ * [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). * ┃
1010
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1111

12-
import { METADATA_MAP } from "./constants";
1312
import { RegularViewEventModel } from "./events";
1413
import { RegularTableViewModel } from "./table";
15-
import { DataListener, SetDataListenerOptions } from "./types";
14+
import { CellMetadata, DataListener, FPSRecord, SetDataListenerOptions } from "./types";
1615
import { get_draw_fps } from "./utils";
16+
import { METADATA_MAP } from "./view_model";
1717

1818
type VirtualMode = "both" | "horizontal" | "vertical" | "none";
1919

@@ -55,26 +55,6 @@ export class RegularTableElement extends RegularViewEventModel {
5555
}
5656
}
5757

58-
/**
59-
* Reset the viewport of this regular table.
60-
*/
61-
private _reset_viewport(): void {
62-
this._start_row = undefined;
63-
this._end_row = undefined;
64-
this._start_col = undefined;
65-
this._end_col = undefined;
66-
}
67-
68-
/**
69-
* Reset the scroll position of this regular table back to the origin.
70-
*/
71-
private _reset_scroll(): void {
72-
this._column_sizes.indices = [];
73-
this.scrollTop = 0;
74-
this.scrollLeft = 0;
75-
this._reset_viewport();
76-
}
77-
7858
/**
7959
* Reset column autosizing, such that column sizes will be recalculated
8060
* on the next draw() call.
@@ -202,30 +182,30 @@ export class RegularTableElement extends RegularViewEventModel {
202182
* coordinates-like object to refer to metadata by logical position.
203183
* @returns {MetaData} The metadata associated with the element.
204184
*/
205-
getMeta(element: HTMLElement | any): any {
206-
if (typeof element === "undefined") {
185+
getMeta(element?: HTMLElement | CellMetadata): CellMetadata | undefined {
186+
if ( element === undefined) {
207187
return;
208188
} else if (element instanceof HTMLElement) {
209189
return METADATA_MAP.get(element);
210-
} else if (element.row_header_x >= 0) {
211-
if (element.row_header_x < this._view_cache.row_headers_length) {
190+
} else if ("row_header_x" in element && element.row_header_x && element.row_header_x >= 0) {
191+
if (element.row_header_x! < this._view_cache.row_headers_length) {
212192
const td = this.table_model.body._fetch_cell(
213-
element.y,
214-
element.row_header_x,
193+
element.y!,
194+
element.row_header_x!,
215195
);
216196
return this.getMeta(td);
217197
}
218-
} else if (element.column_header_y >= 0) {
198+
} else if ("column_header_y" in element && element.column_header_y! >= 0) {
219199
if (
220-
element.column_header_y < this._view_cache.column_headers_length
200+
element.column_header_y! < this._view_cache.column_headers_length
221201
) {
222-
const td = this.table_model.body._fetch_cell(
223-
element.column_header_y,
224-
element.y,
202+
const td = this.table_model.header._fetch_cell(
203+
element.column_header_y!,
204+
element.x!,
225205
);
226206
return this.getMeta(td);
227207
}
228-
} else {
208+
} else if ("dx" in element) {
229209
return this.getMeta(
230210
this.table_model.body._fetch_cell(
231211
element.dy,
@@ -253,13 +233,7 @@ export class RegularTableElement extends RegularViewEventModel {
253233
* @returns {Performance} Performance data aggregated since the last
254234
* call to `getDrawFPS()`.
255235
*/
256-
getDrawFPS(): {
257-
avg: number;
258-
real_fps: number;
259-
virtual_fps: number;
260-
num_frames: number;
261-
elapsed: number;
262-
} {
236+
getDrawFPS(): FPSRecord {
263237
return get_draw_fps();
264238
}
265239

@@ -362,3 +336,32 @@ export class RegularTableElement extends RegularViewEventModel {
362336
if (document.createElement("regular-table").constructor === HTMLElement) {
363337
window.customElements.define("regular-table", RegularTableElement);
364338
}
339+
340+
// Custom Elements extensions
341+
declare global {
342+
namespace JSX {
343+
interface IntrinsicElements {
344+
"regular-table": RegularTableElement;
345+
}
346+
}
347+
}
348+
349+
declare global {
350+
interface Document {
351+
createElement(
352+
tagName: "regular-table",
353+
options?: ElementCreationOptions,
354+
): RegularTableElement;
355+
querySelector<E extends Element = Element>(selectors: string): E | null;
356+
querySelector(
357+
selectors: "regular-table",
358+
): RegularTableElement | null;
359+
}
360+
361+
interface CustomElementRegistry {
362+
get(
363+
tagName: "regular-table",
364+
): typeof RegularTableElement;
365+
}
366+
}
367+

src/ts/table.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,10 @@ abstract class RegularTableViewModelBase {
257257
x0: number,
258258
): Promise<FetchResult> {
259259
let missing_cidx = Math.max(dcidx + Math.floor(x0), 0);
260-
viewport.start_col = missing_cidx;
260+
const new_viewport = structuredClone(viewport);
261+
new_viewport.start_col = missing_cidx;
261262
this._calculateViewportExtension(
262-
viewport,
263+
new_viewport,
263264
view_state,
264265
container_width,
265266
num_columns,
@@ -268,10 +269,10 @@ abstract class RegularTableViewModelBase {
268269
);
269270

270271
const new_col = await view(
271-
Math.floor(viewport.start_col),
272-
Math.floor(viewport.start_row),
273-
Math.ceil(viewport.end_col),
274-
Math.ceil(viewport.end_row),
272+
Math.floor(new_viewport.start_col),
273+
Math.floor(new_viewport.start_row),
274+
Math.ceil(new_viewport.end_col),
275+
Math.ceil(new_viewport.end_row),
275276
);
276277

277278
let column_header_merge_depth: number | undefined;
@@ -289,7 +290,7 @@ abstract class RegularTableViewModelBase {
289290
return { column_header_merge_depth, merge_headers };
290291
}
291292

292-
viewport.end_col = viewport.start_col + new_col.data.length;
293+
viewport.end_col = new_viewport.start_col + new_col.data.length;
293294
for (let i = 0; i < new_col.data.length; i++) {
294295
view_response.data[dcidx + i] = new_col.data[i];
295296
if (new_col.metadata && view_response.metadata) {
@@ -415,10 +416,6 @@ export class RegularTableViewModel extends RegularTableViewModelBase {
415416
}
416417
}
417418

418-
clearWidthStyles() {
419-
this._columnWidthStyleSheet?.replaceSync("");
420-
}
421-
422419
/**
423420
* Updates column width styles for all columns using adoptedStyleSheets.
424421
* Generates CSS rules with :nth-child selectors for both auto-sized and

src/ts/tbody.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import {
1313
BodyDrawResult,
1414
CellMetadata,
15+
CellMetadataBuilder,
1516
CellScalar,
1617
ColumnState,
1718
ViewState,
@@ -32,7 +33,7 @@ export class RegularBodyViewModel extends ViewModel {
3233
{ column_name }: ColumnState,
3334
{ ridx_offset }: ViewState,
3435
size_key: number,
35-
): { td: HTMLTableCellElement; metadata: CellMetadata } {
36+
): { td: HTMLTableCellElement; metadata: CellMetadataBuilder } {
3637
const td = this._get_cell(tagName, ridx, cidx);
3738
const metadata = this._get_or_create_metadata(td);
3839
metadata.y = ridx + Math.floor(ridx_offset);
@@ -83,7 +84,7 @@ export class RegularBodyViewModel extends ViewModel {
8384
column_data_listener_metadata,
8485
} = column_state;
8586
let { row_height } = view_state;
86-
let metadata: CellMetadata | undefined;
87+
let metadata: CellMetadataBuilder | undefined;
8788
const ridx_offset: number[] = [];
8889
const tds: Array<{ td: HTMLTableCellElement; metadata: CellMetadata }> =
8990
[];
@@ -103,7 +104,7 @@ export class RegularBodyViewModel extends ViewModel {
103104

104105
for (const val of column_data) {
105106
let obj:
106-
| { td: HTMLTableCellElement; metadata: CellMetadata }
107+
| { td: HTMLTableCellElement; metadata: CellMetadataBuilder }
107108
| undefined;
108109
if (th) {
109110
const valArray = val as CellScalar[];
@@ -113,6 +114,7 @@ export class RegularBodyViewModel extends ViewModel {
113114
ridx - ridx_off_i,
114115
cidx_i,
115116
);
117+
116118
const prev_row_metadata =
117119
this._get_or_create_metadata(prev_row);
118120

@@ -153,11 +155,13 @@ export class RegularBodyViewModel extends ViewModel {
153155
view_state,
154156
i,
155157
);
158+
156159
const td = obj.td;
157160
const meta = obj.metadata;
158161
td.style.display = "";
159162
td.removeAttribute("rowspan");
160163
td.removeAttribute("colspan");
164+
meta.type = "row_header";
161165
meta.row_header = valArray;
162166
meta.row_header_x = i;
163167
meta.y0 = y0_floor;
@@ -168,7 +172,7 @@ export class RegularBodyViewModel extends ViewModel {
168172
}
169173
ridx_offset[i] = 1;
170174
cidx_offset[ridx] = 1;
171-
tds[i] = obj;
175+
tds[i] = obj as {td: HTMLTableCellElement, metadata: CellMetadata};
172176
}
173177
} else {
174178
obj = this._draw_td(
@@ -185,7 +189,8 @@ export class RegularBodyViewModel extends ViewModel {
185189
meta.user = column_data_listener_metadata[ridx];
186190
}
187191

188-
meta.x = x_floor;
192+
meta.type = "body";
193+
meta.x = x_floor || 0;
189194
meta.x1 = x1_ceil;
190195
meta.row_header = row_headers?.[ridx] || [];
191196
meta.y0 = y0_floor;
@@ -197,7 +202,7 @@ export class RegularBodyViewModel extends ViewModel {
197202
meta.x0 = x0_floor;
198203
}
199204

200-
tds[0] = obj;
205+
tds[0] = obj as {td: HTMLTableCellElement, metadata: CellMetadata};
201206
}
202207

203208
ridx++;

src/ts/thead.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import {
1515
ColumnSizes,
1616
CellMetadata,
1717
CellScalar,
18+
CellMetadataRowHeader,
19+
CellMetadataColumnHeader,
20+
CellMetadataBuilder,
1821
} from "./types";
1922

2023
/**
@@ -25,7 +28,7 @@ import {
2528
* @class RegularHeaderViewModel
2629
*/
2730
export class RegularHeaderViewModel extends ViewModel {
28-
private _group_header_cache: [CellMetadata, HTMLTableCellElement, number][];
31+
private _group_header_cache: [CellMetadataBuilder, HTMLTableCellElement, number][];
2932
private _offset_cache: number[];
3033

3134
constructor(
@@ -65,7 +68,7 @@ export class RegularHeaderViewModel extends ViewModel {
6568
column: CellScalar[],
6669
column_name: unknown,
6770
th: HTMLTableCellElement,
68-
): CellMetadata {
71+
): CellMetadataBuilder {
6972
const metadata = this._get_or_create_metadata(th);
7073
metadata.column_header = column;
7174
metadata.value = column_name;
@@ -77,7 +80,7 @@ export class RegularHeaderViewModel extends ViewModel {
7780
column_name: unknown,
7881
th: HTMLTableCellElement,
7982
size_key: number | number[],
80-
): CellMetadata {
83+
): CellMetadataBuilder {
8184
const metadata = this._get_or_create_metadata(th);
8285
metadata.column_header = column;
8386
metadata.value = column_name;
@@ -123,7 +126,7 @@ export class RegularHeaderViewModel extends ViewModel {
123126
}
124127

125128
let th: HTMLTableCellElement | undefined;
126-
let metadata: CellMetadata | undefined;
129+
let metadata: CellMetadataBuilder | undefined;
127130
let column_name: unknown;
128131
let output: HeaderDrawResult | undefined = undefined;
129132
column_header_merge_depth =
@@ -172,7 +175,7 @@ export class RegularHeaderViewModel extends ViewModel {
172175
);
173176

174177
if (typeof output === "undefined") {
175-
output = { th, metadata };
178+
output = { th, metadata } as {th: HTMLTableCellElement, metadata: CellMetadata};
176179
}
177180

178181
for (const [group_meta] of this._group_header_cache) {
@@ -194,17 +197,19 @@ export class RegularHeaderViewModel extends ViewModel {
194197
metadata.x0 = Math.floor(x0);
195198
metadata.virtual_x = _virtual_x;
196199
if (colspan === 1) {
200+
metadata.type = "corner";
197201
metadata.row_header_x = Array.isArray(size_key)
198202
? size_key[0]
199203
: size_key;
200204
} else {
205+
metadata.type = "column_header";
201206
delete metadata.row_header_x;
202207
}
203208
}
204209
}
205210

206211
this._clean_rows(this._offset_cache.length);
207-
output = output || { th: th!, metadata: metadata! };
212+
output = output || { th: th!, metadata: metadata! } as {th: HTMLTableCellElement, metadata: CellMetadata};
208213
return output;
209214
}
210215

0 commit comments

Comments
 (0)