@sportsdataverse/sdvtables 0.1.0 → 0.2.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.
- package/README.md +70 -112
- package/data/table_themes.json +12136 -0
- package/data/table_themes.json.sha256 +1 -0
- package/dist/aggrid.d.ts +104 -0
- package/dist/aggrid.js +230 -0
- package/dist/aggrid.js.map +1 -0
- package/dist/chunk-3TJR7TKS.js +223 -0
- package/dist/chunk-3TJR7TKS.js.map +1 -0
- package/dist/{chunk-UCRLJGDL.js → chunk-R375P3MN.js} +963 -276
- package/dist/chunk-R375P3MN.js.map +1 -0
- package/dist/chunk-UTOVFIFT.js +15176 -0
- package/dist/chunk-UTOVFIFT.js.map +1 -0
- package/dist/{chunk-U6W6MWKW.js → chunk-VLF2S6VW.js} +7 -5
- package/dist/chunk-VLF2S6VW.js.map +1 -0
- package/dist/chunk-WBTFIGYK.js +189 -0
- package/dist/chunk-WBTFIGYK.js.map +1 -0
- package/dist/{engine-CkfxYXAL.d.ts → engine-BFIPJUlC.d.ts} +1 -1
- package/dist/export.d.ts +1 -1
- package/dist/export.js +4 -3
- package/dist/export.js.map +1 -1
- package/dist/html.d.ts +8 -5
- package/dist/html.js +4 -3
- package/dist/index.d.ts +121 -8
- package/dist/index.js +51 -3
- package/dist/index.js.map +1 -1
- package/dist/mui.d.ts +134 -0
- package/dist/mui.js +193 -0
- package/dist/mui.js.map +1 -0
- package/dist/react.d.ts +2 -2
- package/dist/react.js +3 -2
- package/dist/react.js.map +1 -1
- package/dist/spec-A88vJX5A.d.ts +748 -0
- package/dist/tanstack-table.d.ts +113 -0
- package/dist/tanstack-table.js +98 -0
- package/dist/tanstack-table.js.map +1 -0
- package/dist/{tokens-CpYFsFtf.d.ts → tokens-CHwBt9gs.d.ts} +1 -1
- package/package.json +40 -3
- package/dist/chunk-4VKYHOHL.js +0 -2081
- package/dist/chunk-4VKYHOHL.js.map +0 -1
- package/dist/chunk-U6W6MWKW.js.map +0 -1
- package/dist/chunk-UCRLJGDL.js.map +0 -1
- package/dist/spec-BEhLDtj_.d.ts +0 -430
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { TableFeatures, RowData, ColumnDef } from '@tanstack/table-core';
|
|
2
|
+
import { T as TableSpec } from './spec-A88vJX5A.js';
|
|
3
|
+
import '@sportsdataverse/sdvplot';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The TanStack Table v9 adapter (`@tanstack/table-core` 9, MIT, and its React and Svelte adapters): an sdvtables spec
|
|
7
|
+
* as the options `useTable` (React) or `createTable` (Svelte) takes. Columns keep the HTML table's labels, alignment,
|
|
8
|
+
* number formats (a scaleNote and the rank suffix included) and sort, missing values last both ways; logo, wordmark,
|
|
9
|
+
* headshot and superscript-rank cells come out as plain data that the caller's `render` turns into its framework's
|
|
10
|
+
* markup. TanStack Table is headless: the caller owns the `<table>`, its CSS and its interactions.
|
|
11
|
+
* Pure: TanStack Table is never imported at runtime (types only), and nothing touches the DOM, so the module imports on
|
|
12
|
+
* a server and in any framework.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** A cell sdvtables draws as more than text, as data: `render` turns it into the caller's framework markup. */
|
|
16
|
+
type CellPart = {
|
|
17
|
+
readonly type: "image";
|
|
18
|
+
/** "logo" and "wordmark": a team's mark; "headshot": a player's photo. */
|
|
19
|
+
readonly kind: "logo" | "wordmark" | "headshot";
|
|
20
|
+
readonly src: string;
|
|
21
|
+
/** The team's name for a mark; "" for a headshot, which is decorative (the player's name sits in its row). */
|
|
22
|
+
readonly alt: string;
|
|
23
|
+
/** px */
|
|
24
|
+
readonly height: number;
|
|
25
|
+
/** The resolved team id or the player id, as the HTML table's `data-sdv-id`. */
|
|
26
|
+
readonly id: string;
|
|
27
|
+
/** A logo column with `includeName`: the cell's text, drawn after the image. */
|
|
28
|
+
readonly text?: string;
|
|
29
|
+
} | {
|
|
30
|
+
/** A rank with `superscript` (the default): `num` then `suffix` in a `<sup>` of `size` ("1", "st"). */
|
|
31
|
+
readonly type: "rank";
|
|
32
|
+
readonly num: string;
|
|
33
|
+
readonly suffix: string;
|
|
34
|
+
readonly size: string;
|
|
35
|
+
};
|
|
36
|
+
/** A column's CSS, from the spec: its alignment and width. */
|
|
37
|
+
interface ColumnStyle {
|
|
38
|
+
/** The HTML table's alignment: the spec's `align`, else right for numbers and centre for images. */
|
|
39
|
+
readonly textAlign: "left" | "center" | "right";
|
|
40
|
+
/** The spec's `width`, as given (any CSS width). */
|
|
41
|
+
readonly width?: string;
|
|
42
|
+
}
|
|
43
|
+
/** `tanstackTable` options. */
|
|
44
|
+
interface TanstackTableOptions<TFeatures extends TableFeatures> {
|
|
45
|
+
/**
|
|
46
|
+
* Your `tableFeatures({...})`: register `rowSortingFeature` and `sortedRowModel: createSortedRowModel()` for the
|
|
47
|
+
* columns' sort. It is passed through, and fixes the columns' type to your table's features.
|
|
48
|
+
*/
|
|
49
|
+
features: TFeatures;
|
|
50
|
+
/**
|
|
51
|
+
* Turns an image or superscript-rank cell into your framework's markup: a React element, or Svelte's
|
|
52
|
+
* `renderSnippet(snippet, part)`. Without it, those cells are text: the team or player value, and "1st".
|
|
53
|
+
*/
|
|
54
|
+
render?: (part: CellPart) => unknown;
|
|
55
|
+
}
|
|
56
|
+
/** What `tanstackTable` returns. */
|
|
57
|
+
interface SdvTanstackTable<TFeatures extends TableFeatures, TData extends RowData> {
|
|
58
|
+
/** For `useTable(options)` / `createTable(options)`, or spread with your own options (`initialState`, ...). */
|
|
59
|
+
options: {
|
|
60
|
+
features: TFeatures;
|
|
61
|
+
columns: ColumnDef<TFeatures, TData>[];
|
|
62
|
+
data: readonly TData[];
|
|
63
|
+
/** With the spec's `rowKey` only. */
|
|
64
|
+
getRowId?: (row: TData) => string;
|
|
65
|
+
};
|
|
66
|
+
/** Each column's CSS by column id (the spec's key), for its `<th>` and `<td>`. */
|
|
67
|
+
columnStyle: Readonly<Record<string, ColumnStyle>>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* An sdvtables spec as TanStack Table v9 options: `useTable(tanstackTable(spec, rows, { features }).options)`.
|
|
71
|
+
*
|
|
72
|
+
* - **Columns**: one accessor column per spec column, id the spec's key, header the HTML table's label (with a
|
|
73
|
+
* `scaleNote`'s suffix). Number cells (`num`, `int`, `pct`, `rank`, a `scaleNote`'s divisor and decimals) are the
|
|
74
|
+
* HTML table's text; a blank or unparseable number is missing (`undefined`), never 0.
|
|
75
|
+
* - **Sorting**: sdvtables' own comparator (the column's `compare`, else by kind), with missing values last in both
|
|
76
|
+
* directions (`sortUndefined: "last"`). Register `rowSortingFeature` and `createSortedRowModel()` to use it.
|
|
77
|
+
* - **Row ids**: with the spec's `rowKey`, `String(row[rowKey])`, checked unique and not blank (TanStack would merge two
|
|
78
|
+
* rows with one id); without it, TanStack's row index.
|
|
79
|
+
* - **Images**: `logo`, `wordmark` and `headshot` cells, and superscript ranks, go through `render` as a `CellPart`.
|
|
80
|
+
* A team or player with no image keeps its text, with one warning. Team values may be abbreviations, names or
|
|
81
|
+
* numeric ids.
|
|
82
|
+
*
|
|
83
|
+
* Other kinds (pills, bars, team colours, sparklines...) show their plain value, with one warning per kind.
|
|
84
|
+
* Synchronous: call `await prepare(spec)` (`@sportsdataverse/sdvtables/html`) first. Images are worked out once, from
|
|
85
|
+
* `rows`: build again when the rows change, and keep the result stable between renders (module scope or a memo).
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { createSortedRowModel, rowSortingFeature, tableFeatures } from "@tanstack/table-core";
|
|
90
|
+
* import { defineTable } from "@sportsdataverse/sdvtables";
|
|
91
|
+
* import { prepare } from "@sportsdataverse/sdvtables/html";
|
|
92
|
+
* import { tanstackTable } from "@sportsdataverse/sdvtables/tanstack-table";
|
|
93
|
+
*
|
|
94
|
+
* // 2024 regular season, nflverse games
|
|
95
|
+
* const rows = [
|
|
96
|
+
* { team: "KC", wins: 15, pf: 385 },
|
|
97
|
+
* { team: "BUF", wins: 13, pf: 525 },
|
|
98
|
+
* { team: "LAC", wins: 11, pf: 402 },
|
|
99
|
+
* ];
|
|
100
|
+
* const spec = defineTable<(typeof rows)[number]>()
|
|
101
|
+
* .columns((c) => [c.logo("team", { league: "nfl", height: 28 }), c.int("wins"), c.int("pf")])
|
|
102
|
+
* .rowKey("team")
|
|
103
|
+
* .build();
|
|
104
|
+
* await prepare(spec);
|
|
105
|
+
* const features = tableFeatures({ rowSortingFeature, sortedRowModel: createSortedRowModel() });
|
|
106
|
+
* const { options } = tanstackTable(spec, rows, { features });
|
|
107
|
+
* // in React: useTable(options), from @tanstack/react-table; in Svelte: createTable(options)
|
|
108
|
+
* options.columns.map((c) => [c.id, c.header]);
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function tanstackTable<TFeatures extends TableFeatures, TData extends RowData>(spec: TableSpec<TData>, rows: readonly TData[], o: TanstackTableOptions<TFeatures>): SdvTanstackTable<TFeatures, TData>;
|
|
112
|
+
|
|
113
|
+
export { type CellPart, type ColumnStyle, type SdvTanstackTable, type TanstackTableOptions, tanstackTable };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { scaleNotes, missingLast, formatterFor, unmapped, checkHeight, headshotUrls, logoMarks, rankParts, rowIds, value } from './chunk-WBTFIGYK.js';
|
|
2
|
+
import { alignOf, labelOf, teamNameSync } from './chunk-R375P3MN.js';
|
|
3
|
+
import { NUMERIC_KINDS, toNumber, isMissing, isBlank } from './chunk-UTOVFIFT.js';
|
|
4
|
+
|
|
5
|
+
// src/tanstack-table.ts
|
|
6
|
+
var TS = {
|
|
7
|
+
fn: "tanstackTable",
|
|
8
|
+
ns: "tanstack-table",
|
|
9
|
+
grid: "TanStack Table",
|
|
10
|
+
short: "TanStack Table",
|
|
11
|
+
built: "options"
|
|
12
|
+
};
|
|
13
|
+
function tanstackTable(spec, rows, o) {
|
|
14
|
+
const { scaled, labelSuffix } = scaleNotes(spec);
|
|
15
|
+
const columnStyle = {};
|
|
16
|
+
const columns = spec.columns.map((col) => {
|
|
17
|
+
columnStyle[col.key] = {
|
|
18
|
+
textAlign: alignOf(col),
|
|
19
|
+
...col.width === void 0 ? {} : { width: col.width }
|
|
20
|
+
};
|
|
21
|
+
const asc = missingLast(col, rows)("asc");
|
|
22
|
+
const numeric = NUMERIC_KINDS.has(col.kind);
|
|
23
|
+
const def = {
|
|
24
|
+
id: col.key,
|
|
25
|
+
header: labelOf(col) + (labelSuffix.get(col.key) ?? ""),
|
|
26
|
+
// a missing value is undefined, which sortUndefined keeps last both ways
|
|
27
|
+
accessorFn: (row) => {
|
|
28
|
+
const v = value(row, col.key);
|
|
29
|
+
return numeric ? toNumber(v) ?? void 0 : isMissing(v) ? void 0 : v;
|
|
30
|
+
},
|
|
31
|
+
cell: cellOf(col, formatterFor(col, scaled)),
|
|
32
|
+
sortFn: (a, b, id) => asc(a.getValue(id), b.getValue(id)),
|
|
33
|
+
sortUndefined: "last",
|
|
34
|
+
...col.sortable === void 0 ? {} : { enableSorting: col.sortable }
|
|
35
|
+
};
|
|
36
|
+
return def;
|
|
37
|
+
});
|
|
38
|
+
function cellOf(col, format) {
|
|
39
|
+
const text = (v) => format ? format(v) : isBlank(v) ? "" : String(v);
|
|
40
|
+
const { render } = o;
|
|
41
|
+
switch (col.kind) {
|
|
42
|
+
case "text":
|
|
43
|
+
case "num":
|
|
44
|
+
case "int":
|
|
45
|
+
case "pct":
|
|
46
|
+
return (ctx) => text(ctx.getValue());
|
|
47
|
+
case "rank":
|
|
48
|
+
return (ctx) => {
|
|
49
|
+
const r = col.superscript && render ? rankParts(ctx.getValue()) : null;
|
|
50
|
+
return r === null || !render ? text(ctx.getValue()) : render({ type: "rank", ...r, size: col.suffixSize });
|
|
51
|
+
};
|
|
52
|
+
case "logo":
|
|
53
|
+
case "wordmark": {
|
|
54
|
+
const h = checkHeight(col.height, col.kind);
|
|
55
|
+
const marks = logoMarks(col, rows);
|
|
56
|
+
const kind = col.kind;
|
|
57
|
+
const withName = kind === "logo" && col.includeName;
|
|
58
|
+
return (ctx) => {
|
|
59
|
+
const raw = text(ctx.getValue());
|
|
60
|
+
const t = raw.trim();
|
|
61
|
+
const m = marks.get(t);
|
|
62
|
+
if (m === void 0 || !render) return raw;
|
|
63
|
+
const alt = teamNameSync(col.league, m.id) ?? t;
|
|
64
|
+
return render({
|
|
65
|
+
type: "image",
|
|
66
|
+
kind,
|
|
67
|
+
src: m.url,
|
|
68
|
+
alt,
|
|
69
|
+
height: h,
|
|
70
|
+
id: m.id,
|
|
71
|
+
...withName ? { text: raw } : {}
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
case "headshot": {
|
|
76
|
+
const h = checkHeight(col.height, "headshot");
|
|
77
|
+
const urls = headshotUrls(col, rows, TS);
|
|
78
|
+
return (ctx) => {
|
|
79
|
+
const raw = text(ctx.getValue());
|
|
80
|
+
const src = urls.get(raw.trim());
|
|
81
|
+
return src === void 0 || !render ? raw : render({ type: "image", kind: "headshot", src, alt: "", height: h, id: raw.trim() });
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
default:
|
|
85
|
+
unmapped(col.kind, TS);
|
|
86
|
+
return (ctx) => text(ctx.getValue());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const getRowId = spec.rowKey === void 0 ? void 0 : rowIds(rows, spec.rowKey, TS);
|
|
90
|
+
return {
|
|
91
|
+
options: { features: o.features, columns, data: rows, ...getRowId === void 0 ? {} : { getRowId } },
|
|
92
|
+
columnStyle
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { tanstackTable };
|
|
97
|
+
//# sourceMappingURL=tanstack-table.js.map
|
|
98
|
+
//# sourceMappingURL=tanstack-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tanstack-table.ts"],"names":[],"mappings":";;;;;AAsFA,IAAM,EAAA,GAAe;AAAA,EACnB,EAAA,EAAI,eAAA;AAAA,EACJ,EAAA,EAAI,gBAAA;AAAA,EACJ,IAAA,EAAM,gBAAA;AAAA,EACN,KAAA,EAAO,gBAAA;AAAA,EACP,KAAA,EAAO;AACT,CAAA;AA4CO,SAAS,aAAA,CACd,IAAA,EACA,IAAA,EACA,CAAA,EACoC;AACpC,EAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,WAAW,IAAI,CAAA;AAC/C,EAAA,MAAM,cAA2C,EAAC;AAClD,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,KAAQ;AACxC,IAAA,WAAA,CAAY,GAAA,CAAI,GAAG,CAAA,GAAI;AAAA,MACrB,SAAA,EAAW,QAAQ,GAAG,CAAA;AAAA,MACtB,GAAI,IAAI,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,KAAA,EAAO,GAAA,CAAI,KAAA;AAAM,KACxD;AACA,IAAA,MAAM,GAAA,GAAM,WAAA,CAAY,GAAA,EAAK,IAAI,EAAE,KAAK,CAAA;AACxC,IAAA,MAAM,OAAA,GAAU,aAAA,CAAc,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA;AAC1C,IAAA,MAAM,GAAA,GAAM;AAAA,MACV,IAAI,GAAA,CAAI,GAAA;AAAA,MACR,MAAA,EAAQ,QAAQ,GAAG,CAAA,IAAK,YAAY,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,IAAK,EAAA,CAAA;AAAA;AAAA,MAEpD,UAAA,EAAY,CAAC,GAAA,KAAwB;AACnC,QAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,EAAK,GAAA,CAAI,GAAG,CAAA;AAC5B,QAAA,OAAO,OAAA,GAAW,SAAS,CAAC,CAAA,IAAK,SAAa,SAAA,CAAU,CAAC,IAAI,MAAA,GAAY,CAAA;AAAA,MAC3E,CAAA;AAAA,MACA,MAAM,MAAA,CAAO,GAAA,EAAK,YAAA,CAAa,GAAA,EAAK,MAAM,CAAC,CAAA;AAAA,MAC3C,MAAA,EAAQ,CAAC,CAAA,EAA2B,CAAA,EAA2B,EAAA,KAC7D,GAAA,CAAI,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,EAAG,CAAA,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA;AAAA,MACpC,aAAA,EAAe,MAAA;AAAA,MACf,GAAI,IAAI,QAAA,KAAa,MAAA,GAAY,EAAC,GAAI,EAAE,aAAA,EAAe,GAAA,CAAI,QAAA;AAAS,KACtE;AACA,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,SAAS,MAAA,CACP,KACA,MAAA,EAC0D;AAC1D,IAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAwB,MAAA,GAAS,MAAA,CAAO,CAAC,CAAA,GAAI,OAAA,CAAQ,CAAC,CAAA,GAAI,EAAA,GAAK,MAAA,CAAO,CAAC,CAAA;AACrF,IAAA,MAAM,EAAE,QAAO,GAAI,CAAA;AACnB,IAAA,QAAQ,IAAI,IAAA;AAAM,MAChB,KAAK,MAAA;AAAA,MACL,KAAK,KAAA;AAAA,MACL,KAAK,KAAA;AAAA,MACL,KAAK,KAAA;AACH,QAAA,OAAO,CAAC,GAAA,KAAQ,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA;AAAA,MACrC,KAAK,MAAA;AACH,QAAA,OAAO,CAAC,GAAA,KAAQ;AACd,UAAA,MAAM,CAAA,GAAI,IAAI,WAAA,IAAe,MAAA,GAAS,UAAU,GAAA,CAAI,QAAA,EAAU,CAAA,GAAI,IAAA;AAClE,UAAA,OAAO,MAAM,IAAA,IAAQ,CAAC,SAClB,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA,GACnB,MAAA,CAAO,EAAE,MAAM,MAAA,EAAQ,GAAG,GAAG,IAAA,EAAM,GAAA,CAAI,YAAY,CAAA;AAAA,QACzD,CAAA;AAAA,MACF,KAAK,MAAA;AAAA,MACL,KAAK,UAAA,EAAY;AACf,QAAA,MAAM,CAAA,GAAI,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,IAAI,IAAI,CAAA;AAC1C,QAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,GAAA,EAAK,IAAI,CAAA;AACjC,QAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,QAAA,MAAM,QAAA,GAAW,IAAA,KAAS,MAAA,IAAU,GAAA,CAAI,WAAA;AACxC,QAAA,OAAO,CAAC,GAAA,KAAQ;AACd,UAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,CAAA;AAC/B,UAAA,MAAM,CAAA,GAAI,IAAI,IAAA,EAAK;AACnB,UAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA;AACrB,UAAA,IAAI,CAAA,KAAM,MAAA,IAAa,CAAC,MAAA,EAAQ,OAAO,GAAA;AACvC,UAAA,MAAM,MAAM,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,CAAA,CAAE,EAAE,CAAA,IAAK,CAAA;AAC9C,UAAA,OAAO,MAAA,CAAO;AAAA,YACZ,IAAA,EAAM,OAAA;AAAA,YACN,IAAA;AAAA,YACA,KAAK,CAAA,CAAE,GAAA;AAAA,YACP,GAAA;AAAA,YACA,MAAA,EAAQ,CAAA;AAAA,YACR,IAAI,CAAA,CAAE,EAAA;AAAA,YACN,GAAI,QAAA,GAAW,EAAE,IAAA,EAAM,GAAA,KAAQ;AAAC,WACjC,CAAA;AAAA,QACH,CAAA;AAAA,MACF;AAAA,MACA,KAAK,UAAA,EAAY;AACf,QAAA,MAAM,CAAA,GAAI,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,UAAU,CAAA;AAC5C,QAAA,MAAM,IAAA,GAAO,YAAA,CAAa,GAAA,EAAK,IAAA,EAAM,EAAE,CAAA;AACvC,QAAA,OAAO,CAAC,GAAA,KAAQ;AACd,UAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,CAAA;AAC/B,UAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,MAAM,CAAA;AAC/B,UAAA,OAAO,GAAA,KAAQ,UAAa,CAAC,MAAA,GACzB,MACA,MAAA,CAAO,EAAE,MAAM,OAAA,EAAS,IAAA,EAAM,YAAY,GAAA,EAAK,GAAA,EAAK,IAAI,MAAA,EAAQ,CAAA,EAAG,IAAI,GAAA,CAAI,IAAA,IAAQ,CAAA;AAAA,QACzF,CAAA;AAAA,MACF;AAAA,MACA;AACE,QAAA,QAAA,CAAS,GAAA,CAAI,MAAM,EAAE,CAAA;AACrB,QAAA,OAAO,CAAC,GAAA,KAAQ,IAAA,CAAK,GAAA,CAAI,UAAU,CAAA;AAAA;AACvC,EACF;AAGA,EAAA,MAAM,QAAA,GAAW,KAAK,MAAA,KAAW,MAAA,GAAY,SAAY,MAAA,CAAO,IAAA,EAAM,IAAA,CAAK,MAAA,EAAQ,EAAE,CAAA;AACrF,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,EAAE,QAAA,EAAU,CAAA,CAAE,UAAU,OAAA,EAAS,IAAA,EAAM,IAAA,EAAM,GAAI,aAAa,MAAA,GAAY,EAAC,GAAI,EAAE,UAAS,EAAG;AAAA,IACtG;AAAA,GACF;AACF","file":"tanstack-table.js","sourcesContent":["/**\n * The TanStack Table v9 adapter (`@tanstack/table-core` 9, MIT, and its React and Svelte adapters): an sdvtables spec\n * as the options `useTable` (React) or `createTable` (Svelte) takes. Columns keep the HTML table's labels, alignment,\n * number formats (a scaleNote and the rank suffix included) and sort, missing values last both ways; logo, wordmark,\n * headshot and superscript-rank cells come out as plain data that the caller's `render` turns into its framework's\n * markup. TanStack Table is headless: the caller owns the `<table>`, its CSS and its interactions.\n * Pure: TanStack Table is never imported at runtime (types only), and nothing touches the DOM, so the module imports on\n * a server and in any framework.\n */\nimport type { CellContext, ColumnDef, RowData, Row as TRow, TableFeatures } from \"@tanstack/table-core\";\nimport {\n type GridName,\n checkHeight,\n formatterFor,\n headshotUrls,\n logoMarks,\n missingLast,\n rankParts,\n rowIds,\n scaleNotes,\n unmapped,\n value,\n} from \"./_grid.js\";\nimport { NUMERIC_KINDS, isMissing } from \"./engine.js\";\nimport { isBlank, toNumber } from \"./format.js\";\nimport { alignOf, labelOf } from \"./html/parts.js\";\nimport type { ColumnSpec, TableSpec } from \"./spec.js\";\nimport { teamNameSync } from \"./team-name.js\";\n\n/** A cell sdvtables draws as more than text, as data: `render` turns it into the caller's framework markup. */\nexport type CellPart =\n | {\n readonly type: \"image\";\n /** \"logo\" and \"wordmark\": a team's mark; \"headshot\": a player's photo. */\n readonly kind: \"logo\" | \"wordmark\" | \"headshot\";\n readonly src: string;\n /** The team's name for a mark; \"\" for a headshot, which is decorative (the player's name sits in its row). */\n readonly alt: string;\n /** px */\n readonly height: number;\n /** The resolved team id or the player id, as the HTML table's `data-sdv-id`. */\n readonly id: string;\n /** A logo column with `includeName`: the cell's text, drawn after the image. */\n readonly text?: string;\n }\n | {\n /** A rank with `superscript` (the default): `num` then `suffix` in a `<sup>` of `size` (\"1\", \"st\"). */\n readonly type: \"rank\";\n readonly num: string;\n readonly suffix: string;\n readonly size: string;\n };\n/** A column's CSS, from the spec: its alignment and width. */\nexport interface ColumnStyle {\n /** The HTML table's alignment: the spec's `align`, else right for numbers and centre for images. */\n readonly textAlign: \"left\" | \"center\" | \"right\";\n /** The spec's `width`, as given (any CSS width). */\n readonly width?: string;\n}\n/** `tanstackTable` options. */\nexport interface TanstackTableOptions<TFeatures extends TableFeatures> {\n /**\n * Your `tableFeatures({...})`: register `rowSortingFeature` and `sortedRowModel: createSortedRowModel()` for the\n * columns' sort. It is passed through, and fixes the columns' type to your table's features.\n */\n features: TFeatures;\n /**\n * Turns an image or superscript-rank cell into your framework's markup: a React element, or Svelte's\n * `renderSnippet(snippet, part)`. Without it, those cells are text: the team or player value, and \"1st\".\n */\n render?: (part: CellPart) => unknown;\n}\n/** What `tanstackTable` returns. */\nexport interface SdvTanstackTable<TFeatures extends TableFeatures, TData extends RowData> {\n /** For `useTable(options)` / `createTable(options)`, or spread with your own options (`initialState`, ...). */\n options: {\n features: TFeatures;\n columns: ColumnDef<TFeatures, TData>[];\n data: readonly TData[];\n /** With the spec's `rowKey` only. */\n getRowId?: (row: TData) => string;\n };\n /** Each column's CSS by column id (the spec's key), for its `<th>` and `<td>`. */\n columnStyle: Readonly<Record<string, ColumnStyle>>;\n}\n\nconst TS: GridName = {\n fn: \"tanstackTable\",\n ns: \"tanstack-table\",\n grid: \"TanStack Table\",\n short: \"TanStack Table\",\n built: \"options\",\n};\n\n/**\n * An sdvtables spec as TanStack Table v9 options: `useTable(tanstackTable(spec, rows, { features }).options)`.\n *\n * - **Columns**: one accessor column per spec column, id the spec's key, header the HTML table's label (with a\n * `scaleNote`'s suffix). Number cells (`num`, `int`, `pct`, `rank`, a `scaleNote`'s divisor and decimals) are the\n * HTML table's text; a blank or unparseable number is missing (`undefined`), never 0.\n * - **Sorting**: sdvtables' own comparator (the column's `compare`, else by kind), with missing values last in both\n * directions (`sortUndefined: \"last\"`). Register `rowSortingFeature` and `createSortedRowModel()` to use it.\n * - **Row ids**: with the spec's `rowKey`, `String(row[rowKey])`, checked unique and not blank (TanStack would merge two\n * rows with one id); without it, TanStack's row index.\n * - **Images**: `logo`, `wordmark` and `headshot` cells, and superscript ranks, go through `render` as a `CellPart`.\n * A team or player with no image keeps its text, with one warning. Team values may be abbreviations, names or\n * numeric ids.\n *\n * Other kinds (pills, bars, team colours, sparklines...) show their plain value, with one warning per kind.\n * Synchronous: call `await prepare(spec)` (`@sportsdataverse/sdvtables/html`) first. Images are worked out once, from\n * `rows`: build again when the rows change, and keep the result stable between renders (module scope or a memo).\n *\n * @example\n * ```ts\n * import { createSortedRowModel, rowSortingFeature, tableFeatures } from \"@tanstack/table-core\";\n * import { defineTable } from \"@sportsdataverse/sdvtables\";\n * import { prepare } from \"@sportsdataverse/sdvtables/html\";\n * import { tanstackTable } from \"@sportsdataverse/sdvtables/tanstack-table\";\n *\n * // 2024 regular season, nflverse games\n * const rows = [\n * { team: \"KC\", wins: 15, pf: 385 },\n * { team: \"BUF\", wins: 13, pf: 525 },\n * { team: \"LAC\", wins: 11, pf: 402 },\n * ];\n * const spec = defineTable<(typeof rows)[number]>()\n * .columns((c) => [c.logo(\"team\", { league: \"nfl\", height: 28 }), c.int(\"wins\"), c.int(\"pf\")])\n * .rowKey(\"team\")\n * .build();\n * await prepare(spec);\n * const features = tableFeatures({ rowSortingFeature, sortedRowModel: createSortedRowModel() });\n * const { options } = tanstackTable(spec, rows, { features });\n * // in React: useTable(options), from @tanstack/react-table; in Svelte: createTable(options)\n * options.columns.map((c) => [c.id, c.header]);\n * ```\n */\nexport function tanstackTable<TFeatures extends TableFeatures, TData extends RowData>(\n spec: TableSpec<TData>,\n rows: readonly TData[],\n o: TanstackTableOptions<TFeatures>,\n): SdvTanstackTable<TFeatures, TData> {\n const { scaled, labelSuffix } = scaleNotes(spec);\n const columnStyle: Record<string, ColumnStyle> = {};\n const columns = spec.columns.map((col) => {\n columnStyle[col.key] = {\n textAlign: alignOf(col),\n ...(col.width === undefined ? {} : { width: col.width }),\n };\n const asc = missingLast(col, rows)(\"asc\"); // TanStack reverses it for a descending sort\n const numeric = NUMERIC_KINDS.has(col.kind);\n const def = {\n id: col.key,\n header: labelOf(col) + (labelSuffix.get(col.key) ?? \"\"),\n // a missing value is undefined, which sortUndefined keeps last both ways\n accessorFn: (row: TData): unknown => {\n const v = value(row, col.key);\n return numeric ? (toNumber(v) ?? undefined) : isMissing(v) ? undefined : v;\n },\n cell: cellOf(col, formatterFor(col, scaled)),\n sortFn: (a: TRow<TFeatures, TData>, b: TRow<TFeatures, TData>, id: string) =>\n asc(a.getValue(id), b.getValue(id)),\n sortUndefined: \"last\" as const,\n ...(col.sortable === undefined ? {} : { enableSorting: col.sortable }),\n };\n return def as unknown as ColumnDef<TFeatures, TData>;\n });\n\n function cellOf(\n col: ColumnSpec<TData>,\n format: ((v: unknown) => string) | undefined,\n ): (ctx: CellContext<TFeatures, TData, unknown>) => unknown {\n const text = (v: unknown): string => (format ? format(v) : isBlank(v) ? \"\" : String(v));\n const { render } = o;\n switch (col.kind) {\n case \"text\":\n case \"num\":\n case \"int\":\n case \"pct\":\n return (ctx) => text(ctx.getValue());\n case \"rank\":\n return (ctx) => {\n const r = col.superscript && render ? rankParts(ctx.getValue()) : null;\n return r === null || !render\n ? text(ctx.getValue())\n : render({ type: \"rank\", ...r, size: col.suffixSize });\n };\n case \"logo\":\n case \"wordmark\": {\n const h = checkHeight(col.height, col.kind);\n const marks = logoMarks(col, rows);\n const kind = col.kind;\n const withName = kind === \"logo\" && col.includeName;\n return (ctx) => {\n const raw = text(ctx.getValue());\n const t = raw.trim(); // the lookup key: 12, \"12\" and \" 12 \" are one team\n const m = marks.get(t);\n if (m === undefined || !render) return raw; // blank, unknown team or no image: the text, as the HTML table\n const alt = teamNameSync(col.league, m.id) ?? t;\n return render({\n type: \"image\",\n kind,\n src: m.url,\n alt,\n height: h,\n id: m.id,\n ...(withName ? { text: raw } : {}),\n });\n };\n }\n case \"headshot\": {\n const h = checkHeight(col.height, \"headshot\");\n const urls = headshotUrls(col, rows, TS);\n return (ctx) => {\n const raw = text(ctx.getValue());\n const src = urls.get(raw.trim());\n return src === undefined || !render\n ? raw\n : render({ type: \"image\", kind: \"headshot\", src, alt: \"\", height: h, id: raw.trim() });\n };\n }\n default:\n unmapped(col.kind, TS);\n return (ctx) => text(ctx.getValue());\n }\n }\n\n // a repeated or blank rowKey value would give TanStack one id for two rows; checked once, here\n const getRowId = spec.rowKey === undefined ? undefined : rowIds(rows, spec.rowKey, TS);\n return {\n options: { features: o.features, columns, data: rows, ...(getRowId === undefined ? {} : { getRowId }) },\n columnStyle,\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as Density, a as ThemeRef } from './spec-
|
|
1
|
+
import { D as Density, a as ThemeRef } from './spec-A88vJX5A.js';
|
|
2
2
|
|
|
3
3
|
type Role = "body" | "pad" | "title" | "subtitle" | "label" | "group" | "source";
|
|
4
4
|
type DensitySizes = Readonly<Record<Role, number>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sportsdataverse/sdvtables",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Publication tables for SportsDataverse data — TableSpec, 18+3 themes, team logos/headshots/colors, static HTML renderer. TypeScript port of sdvplotR gt_* / gtUtils",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"html-tables",
|
|
12
12
|
"gt",
|
|
13
13
|
"great-tables",
|
|
14
|
-
"team-logos"
|
|
14
|
+
"team-logos",
|
|
15
|
+
"mui",
|
|
16
|
+
"mui-x-data-grid",
|
|
17
|
+
"ag-grid",
|
|
18
|
+
"tanstack-table"
|
|
15
19
|
],
|
|
16
20
|
"homepage": "https://plot.sportsdataverse.org",
|
|
17
21
|
"bugs": "https://github.com/sportsdataverse/sdvplot-js/issues",
|
|
@@ -22,6 +26,7 @@
|
|
|
22
26
|
},
|
|
23
27
|
"files": [
|
|
24
28
|
"dist",
|
|
29
|
+
"data",
|
|
25
30
|
"NOTICE.md"
|
|
26
31
|
],
|
|
27
32
|
"exports": {
|
|
@@ -37,6 +42,18 @@
|
|
|
37
42
|
"types": "./dist/react.d.ts",
|
|
38
43
|
"import": "./dist/react.js"
|
|
39
44
|
},
|
|
45
|
+
"./mui": {
|
|
46
|
+
"types": "./dist/mui.d.ts",
|
|
47
|
+
"import": "./dist/mui.js"
|
|
48
|
+
},
|
|
49
|
+
"./aggrid": {
|
|
50
|
+
"types": "./dist/aggrid.d.ts",
|
|
51
|
+
"import": "./dist/aggrid.js"
|
|
52
|
+
},
|
|
53
|
+
"./tanstack-table": {
|
|
54
|
+
"types": "./dist/tanstack-table.d.ts",
|
|
55
|
+
"import": "./dist/tanstack-table.js"
|
|
56
|
+
},
|
|
40
57
|
"./export": {
|
|
41
58
|
"types": "./dist/export.d.ts",
|
|
42
59
|
"import": "./dist/export.js"
|
|
@@ -44,11 +61,23 @@
|
|
|
44
61
|
"./package.json": "./package.json"
|
|
45
62
|
},
|
|
46
63
|
"peerDependencies": {
|
|
64
|
+
"@mui/x-data-grid": ">=9.15.0",
|
|
47
65
|
"@sportsdataverse/sdvplot": "^0",
|
|
66
|
+
"@tanstack/table-core": ">=9.3.1",
|
|
67
|
+
"ag-grid-community": ">=36.2.0",
|
|
48
68
|
"playwright": ">=1.45",
|
|
49
69
|
"react": ">=18"
|
|
50
70
|
},
|
|
51
71
|
"peerDependenciesMeta": {
|
|
72
|
+
"@mui/x-data-grid": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"@tanstack/table-core": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"ag-grid-community": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
52
81
|
"playwright": {
|
|
53
82
|
"optional": true
|
|
54
83
|
},
|
|
@@ -57,16 +86,24 @@
|
|
|
57
86
|
}
|
|
58
87
|
},
|
|
59
88
|
"devDependencies": {
|
|
89
|
+
"@emotion/react": "11.14.0",
|
|
90
|
+
"@emotion/styled": "11.14.1",
|
|
91
|
+
"@mui/material": "9.5.0",
|
|
92
|
+
"@mui/system": "9.5.0",
|
|
93
|
+
"@mui/x-data-grid": "9.15.0",
|
|
60
94
|
"@observablehq/plot": "^0.6.17",
|
|
95
|
+
"@tanstack/react-table": "9.3.1",
|
|
96
|
+
"@tanstack/table-core": "9.3.1",
|
|
61
97
|
"@testing-library/react": "^16.3.3",
|
|
62
98
|
"@types/react": "^19.3.0",
|
|
63
99
|
"@types/react-dom": "^19.3.0",
|
|
100
|
+
"ag-grid-community": "36.2.0",
|
|
64
101
|
"happy-dom": "^15.11.0",
|
|
65
102
|
"jsdom": "^26.1.0",
|
|
66
103
|
"playwright": "^1.64.0",
|
|
67
104
|
"react": "^19.3.0",
|
|
68
105
|
"react-dom": "^19.3.0",
|
|
69
|
-
"@sportsdataverse/sdvplot": "^0.
|
|
106
|
+
"@sportsdataverse/sdvplot": "^0.2.0"
|
|
70
107
|
},
|
|
71
108
|
"repository": {
|
|
72
109
|
"type": "git",
|