@sportsdataverse/sdvtables 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/NOTICE.md +4 -0
- package/README.md +561 -2
- package/dist/chunk-4VKYHOHL.js +2081 -0
- package/dist/chunk-4VKYHOHL.js.map +1 -0
- package/dist/chunk-U6W6MWKW.js +179 -0
- package/dist/chunk-U6W6MWKW.js.map +1 -0
- package/dist/chunk-UCRLJGDL.js +1628 -0
- package/dist/chunk-UCRLJGDL.js.map +1 -0
- package/dist/engine-CkfxYXAL.d.ts +190 -0
- package/dist/export.d.ts +88 -0
- package/dist/export.js +309 -0
- package/dist/export.js.map +1 -0
- package/dist/html.d.ts +330 -0
- package/dist/html.js +5 -0
- package/dist/html.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +72 -0
- package/dist/react.js +183 -0
- package/dist/react.js.map +1 -0
- package/dist/spec-BEhLDtj_.d.ts +430 -0
- package/dist/tokens-CpYFsFtf.d.ts +75 -0
- package/package.json +86 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/export/compose.ts","../src/export/index.ts"],"names":["n","InputError"],"mappings":"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","file":"export.js","sourcesContent":["import { InputError } from \"@sportsdataverse/sdvplot\";\nimport { escapeHtml } from \"../html/escape.js\";\nimport { renderHTML } from \"../html/index.js\";\nimport type { TableSpec } from \"../spec.js\";\n\nexport type TableItem<Row> = { spec: TableSpec<Row>; rows: readonly Row[] } | string;\nexport interface ComposeOptions {\n title?: string;\n subtitle?: string;\n caption?: string;\n sourceNote?: string;\n captionRule?: boolean;\n}\nexport interface GridOptions extends ComposeOptions {\n ncol?: number;\n gap?: number;\n align?: \"top\" | \"center\" | \"bottom\";\n labels?: readonly string[];\n}\nexport interface StackOptions extends ComposeOptions {\n gap?: number;\n align?: \"left\" | \"center\" | \"right\";\n}\n\n/**\n * Python `_STYLE_DEFAULTS` (_export.py:469-475) as one sheet: title 28px/700/#111111 centred, subtitle 16px/400/#666666\n * centred, caption 12px/400/#8A8A8A centred, source note 12px/400/#8A8A8A right, grid label 12px/600/#555555 left, all in\n * `system-ui, -apple-system, sans-serif` (:467). A title with no subtitle keeps the subtitle's 12px gap (:564-565);\n * `captionRule` is a 1px rule UNDER the caption in its colour, padded 6px (:566-567, :574).\n */\nconst COMPOSE_CSS =\n \".sdvt-compose{display:inline-block;font-family:system-ui,-apple-system,sans-serif}\" +\n \".sdvt-compose-title{font-size:28px;font-weight:700;color:#111111;text-align:center;margin:0 0 4px}\" +\n \".sdvt-compose-title:last-child{margin-bottom:12px}\" +\n \".sdvt-compose-subtitle{font-size:16px;font-weight:400;color:#666666;text-align:center;margin:0 0 12px}\" +\n \".sdvt-compose-caption{font-size:12px;font-weight:400;color:#8A8A8A;text-align:center;margin:10px 0 0}\" +\n \".sdvt-compose-source{font-size:12px;font-weight:400;color:#8A8A8A;text-align:right;margin:6px 0 0}\" +\n \".sdvt-compose-rule{border-bottom:1px solid #8A8A8A;padding-bottom:6px}\" +\n \".sdvt-compose-label{font-size:12px;font-weight:600;color:#555555;text-align:left;margin:0 0 6px}\";\n\n/**\n * A group value as `batchToPNG` puts it in a file name (Python `gt_save_batch`): each run of characters outside\n * `A-Za-z0-9._-` becomes \"-\", the ends are trimmed of \"-\", and it is lower-cased.\n * Export plumbing: it may change before 1.0.\n *\n * @beta\n */\nexport function slug(value: unknown): string {\n return String(value)\n .replace(/[^A-Za-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase();\n}\n\nfunction itemHTML<Row>(item: TableItem<Row>): string {\n return typeof item === \"string\" ? item : renderHTML(item.spec, item.rows);\n}\nfunction checkItems<Row>(items: readonly TableItem<Row>[]): void {\n if (items.length === 0) throw new InputError(\"at least one table is required\");\n}\nfunction checkPixels(name: string, value: number): void {\n if (!(Number.isFinite(value) && value >= 0))\n throw new InputError(`${name} must be a non-negative number of pixels, got ${String(value)}`);\n}\n/** Python's `align not in places` check: the CSS value for a known name, else InputError. */\nfunction placeOf(align: string, places: Readonly<Record<string, string>>): string {\n const place = places[align];\n if (place === undefined)\n throw new InputError(\n `align must be one of ${Object.keys(places).join(\", \")}, got ${JSON.stringify(align)}`,\n );\n return place;\n}\n\n/** A table's wrapper as `assemble` writes it (class, then id); ids match /^[A-Za-z][\\w-]*$/, so no regex escaping. */\nconst WRAPPER = /<div class=\"sdvt [^\"]*\" id=\"([A-Za-z][\\w-]*)\"/g;\n\n/**\n * One spec composed twice renders one wrapper id twice: every repeat gets the first free `-2`, `-3`… suffix, on its\n * wrapper (and the `id`/`for` of its controls) and on the `#id` selectors of its own `<style>`s, so each table\n * keeps its decorations. A table is the markup from its wrapper to the next one.\n */\nfunction uniqueIds(body: string): string {\n const starts = [...body.matchAll(WRAPPER)];\n const taken = new Set(starts.map((m) => m[1] as string));\n if (taken.size === starts.length) return body;\n const seen = new Set<string>();\n let out = body.slice(0, starts[0]?.index);\n starts.forEach((m, i) => {\n const id = m[1] as string;\n let table = body.slice(m.index, starts[i + 1]?.index);\n if (seen.has(id)) {\n let n = 2;\n while (taken.has(`${id}-${n}`)) n++;\n const to = `${id}-${n}`;\n taken.add(to);\n table = table\n .replace(new RegExp(`(\\\\s(?:id|for)=\")${id}(?=[\"-])`, \"g\"), `$1${to}`)\n .replace(/<style>[\\s\\S]*?<\\/style>/g, (css) =>\n // a selector only: the next brace is the rule's `{`, so a color equal to the id (`#fade;`) is left alone\n css.replace(new RegExp(`#${id}(?![\\\\w-])(?=[^{}]*\\\\{)`, \"g\"), `#${to}`),\n );\n }\n seen.add(id);\n out += table;\n });\n return out;\n}\n\n/** Title/subtitle above, caption/source note below — the shared frame of gt_grid and gt_stack_tables. */\nexport function composePage(\n body: string,\n { title, subtitle, caption, sourceNote, captionRule = false }: ComposeOptions = {},\n): string {\n const head =\n title || subtitle\n ? `<header class=\"sdvt-compose-head\">${title ? `<div class=\"sdvt-compose-title\">${escapeHtml(title)}</div>` : \"\"}${subtitle ? `<p class=\"sdvt-compose-subtitle\">${escapeHtml(subtitle)}</p>` : \"\"}</header>`\n : \"\";\n const foot =\n caption || sourceNote\n ? `<footer class=\"sdvt-compose-foot\">${caption ? `<p class=\"sdvt-compose-caption${captionRule ? \" sdvt-compose-rule\" : \"\"}\">${escapeHtml(caption)}</p>` : \"\"}${sourceNote ? `<p class=\"sdvt-compose-source\">${escapeHtml(sourceNote)}</p>` : \"\"}</footer>`\n : \"\";\n return `<div class=\"sdvt-compose\"><style>${COMPOSE_CSS}</style>${head}${uniqueIds(body)}${foot}</div>`;\n}\n\n/** Port of gt_grid: small multiples, `ncol` across, rows follow from the count. */\nexport function gridTables<Row>(\n items: readonly TableItem<Row>[],\n { ncol = 2, gap = 24, align = \"top\", labels, ...compose }: GridOptions = {},\n): string {\n checkItems(items);\n if (!Number.isInteger(ncol) || ncol < 1)\n throw new InputError(`ncol must be an integer of at least 1, got ${String(ncol)}`);\n const place = placeOf(align, { top: \"start\", center: \"center\", bottom: \"end\" });\n checkPixels(\"gap\", gap);\n if (labels !== undefined && labels.length === 0)\n throw new InputError(\"labels must be non-empty; omit it for no labels\");\n const cells = items.map((item, i) => {\n const label =\n labels === undefined\n ? \"\"\n : `<div class=\"sdvt-compose-label\">${escapeHtml(labels[i % labels.length] ?? \"\")}</div>`;\n return `<div class=\"sdvt-compose-cell\">${label}${itemHTML(item)}</div>`;\n });\n const grid = `<div class=\"sdvt-grid\" style=\"display:grid;grid-template-columns:repeat(${ncol},max-content);gap:${gap}px;align-items:${place};justify-content:center\">${cells.join(\"\")}</div>`;\n return composePage(grid, compose);\n}\n\n/** Port of gt_stack_tables: a vertical stack. */\nexport function stackTables<Row>(\n items: readonly TableItem<Row>[],\n { gap = 16, align = \"center\", ...compose }: StackOptions = {},\n): string {\n checkItems(items);\n const place = placeOf(align, { left: \"flex-start\", center: \"center\", right: \"flex-end\" });\n checkPixels(\"gap\", gap);\n const stack = `<div class=\"sdvt-stack\" style=\"display:flex;flex-direction:column;gap:${gap}px;align-items:${place}\">${items.map(itemHTML).join(\"\")}</div>`;\n return composePage(stack, compose);\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { InputError, OptionalDependencyError, SdvplotError, warn } from \"@sportsdataverse/sdvplot\";\nimport {\n type Aspect,\n type Gravity,\n canvasFor,\n checkColor,\n offsetFor,\n parseAspect,\n parseGravity,\n peerMissing,\n} from \"@sportsdataverse/sdvplot/export\";\nimport type { Browser, Page } from \"playwright\";\nimport { escapeAttr } from \"../html/escape.js\";\nimport { renderHTML } from \"../html/index.js\";\nimport type { TableSpec } from \"../spec.js\";\nimport { type TableItem, slug } from \"./compose.js\";\n\nexport { gridTables, stackTables, composePage, slug } from \"./compose.js\";\nexport type { ComposeOptions, GridOptions, StackOptions, TableItem } from \"./compose.js\";\n\n/**\n * Options for {@link htmlToPNG} and {@link tableToPNG}; defaults are Python `gt_save_crop`'s. Its `expand` (the page\n * captured before trimming) is fixed here, as it only has to leave background around the content. (The HTML itself\n * takes `RenderOptions` from `@sportsdataverse/sdvtables/html`.)\n */\nexport interface PNGOptions {\n /** the final image width in pixels, the height following (Python `width`); absent: the rendered width */\n width?: number;\n /** the rendering zoom (Python `zoom`); default 2, a sharp (retina) image */\n deviceScaleFactor?: number;\n /** the color around the content; default \"white\" */\n background?: string;\n /** image pixels of `background` left around the trimmed content (Python `whitespace`, truncated to an integer); default 50 */\n whitespace?: number;\n /** stylesheet URLs (Google Fonts) awaited via document.fonts.ready */\n fontLinks?: readonly string[];\n /** also write the PNG here (must end in .png) */\n file?: string;\n}\n/** Options for {@link socialCrop}; defaults are Python `gt_social_crop`'s (whitespace 60). */\nexport interface SocialCropOptions extends PNGOptions {\n aspect?: Aspect;\n gravity?: Gravity;\n}\n/** Options for {@link batchToPNG}, as Python `gt_save_batch` (no `width`; each file is named by its group). */\nexport interface BatchOptions extends Omit<PNGOptions, \"width\" | \"file\"> {\n dir: string;\n matchWidth?: boolean;\n}\n\ninterface Resolved {\n width: number | undefined;\n deviceScaleFactor: number;\n background: string;\n whitespace: number;\n fontLinks: readonly string[];\n file: string | undefined;\n}\n\n/** The page width tables lay out in; a wider table grows the page rather than being clipped. */\nconst VIEWPORT = 1200;\n/** CSS px of page captured around the content, so the trim finds plain background on every side. */\nconst EXPAND = 5;\n/**\n * Chromium's canvas limits (Blink: 65,535 px a side, 32,768 x 8,192 px in all; measured in playwright 1.64's\n * chromium). Past either, `toDataURL` returns \"data:,\" and `getImageData` reads blank, without an error.\n */\nconst MAX_SIDE = 65_535;\nconst MAX_AREA = 32_768 * 8_192;\nconst REMEDY =\n \"put fewer rows in each image (rows.slice() a page at a time, batchToPNG by a group column, or gridTables to set tables side by side), or lower deviceScaleFactor\";\nconst n = (v: number): string => v.toLocaleString(\"en-US\");\n\n/** I1: a canvas past Chromium's limits draws nothing; say so, with the size, before drawing it. */\nfunction checkCanvas(what: string, w: number, h: number, o: Resolved): void {\n if (w <= MAX_SIDE && h <= MAX_SIDE && w * h <= MAX_AREA) return;\n throw new SdvplotError(\n `${what} ${n(w)} × ${n(h)} px at deviceScaleFactor ${o.deviceScaleFactor}, past Chromium's canvas limit of ${n(MAX_SIDE)} px a side and ${n(MAX_AREA)} px in all; ${REMEDY}`,\n );\n}\n\nconst checkPng = (file: string): void => {\n // Python _check_file: the extension must be a format the writer produces; here that is PNG only\n if (!/\\.png$/i.test(file)) throw new InputError(`file must end in .png, got ${JSON.stringify(file)}`);\n};\n\nfunction resolve({\n width,\n deviceScaleFactor = 2,\n background = \"white\",\n whitespace = 50,\n fontLinks = [],\n file,\n}: PNGOptions): Resolved {\n if (width !== undefined && !(Number.isInteger(width) && width > 0))\n throw new InputError(`width must be a positive integer of pixels, got ${String(width)}`);\n if (!(Number.isFinite(deviceScaleFactor) && deviceScaleFactor > 0))\n throw new InputError(`deviceScaleFactor must be a positive number, got ${String(deviceScaleFactor)}`);\n if (!(Number.isFinite(whitespace) && whitespace >= 0))\n throw new InputError(`whitespace must be a non-negative number of pixels, got ${String(whitespace)}`);\n checkColor(\"background\", background);\n if (file !== undefined) checkPng(file);\n // Python _pixels: int()\n return { width, deviceScaleFactor, background, whitespace: Math.trunc(whitespace), fontLinks, file };\n}\n\nasync function launch(): Promise<Browser> {\n const pw = await import(\"playwright\").catch((e: unknown) => {\n throw new OptionalDependencyError(\n peerMissing(e, \"playwright\")\n ? \"sdvtables/export needs the optional peer playwright, which is not installed: pnpm add -D playwright && pnpm exec playwright install chromium\"\n : `sdvtables/export could not load the optional peer playwright (installed, but it failed to load): ${String(e)}`,\n { cause: e },\n );\n });\n try {\n return await pw.chromium.launch();\n } catch (e) {\n if (e instanceof Error && /Executable doesn't exist/.test(e.message))\n throw new OptionalDependencyError(\n \"sdvtables/export found playwright but not its chromium browser: pnpm exec playwright install chromium\",\n { cause: e },\n );\n throw e;\n }\n}\n\nfunction page(body: string, o: Resolved): string {\n const links = o.fontLinks.map((href) => `<link rel=\"stylesheet\" href=\"${escapeAttr(href)}\">`).join(\"\");\n return `<!doctype html><html><head><meta charset=\"utf-8\">${links}<style>html,body{margin:0;background:${o.background}}#sdv-root{display:inline-block;padding:${EXPAND}px;background:${o.background}}</style></head><body><div id=\"sdv-root\">${body}</div></body></html>`;\n}\n\n/** A screenshot (base64 PNG) and its trim box: x, y, width, height in image pixels. */\ninterface Shot {\n png: string;\n trim: [number, number, number, number];\n}\n\n/** In the page: Python `_trim` (ImageMagick, fuzz 0), the box of the pixels unlike the top-left one; all one color: the whole image. */\nasync function trimBox(png: string): Promise<[number, number, number, number]> {\n const img = new Image();\n img.src = `data:image/png;base64,${png}`;\n await img.decode();\n const c = document.createElement(\"canvas\");\n c.width = img.width;\n c.height = img.height;\n const g = c.getContext(\"2d\") as CanvasRenderingContext2D;\n g.drawImage(img, 0, 0);\n const px = new Uint32Array(g.getImageData(0, 0, c.width, c.height).data.buffer);\n const bg = px[0];\n let [x0, y0, x1, y1] = [c.width, c.height, -1, -1];\n for (let y = 0, i = 0; y < c.height; y++)\n for (let x = 0; x < c.width; x++, i++)\n if (px[i] !== bg) {\n if (x < x0) x0 = x;\n if (x > x1) x1 = x;\n if (y < y0) y0 = y;\n y1 = y;\n }\n return x1 < 0 ? [0, 0, c.width, c.height] : [x0, y0, x1 - x0 + 1, y1 - y0 + 1];\n}\n\n/** In the page: the trimmed shot placed at dx, dy on a w x h canvas of `bg`, then scaled to fw x fh; a base64 PNG. */\nasync function drawPNG(a: {\n png: string;\n trim: [number, number, number, number];\n w: number;\n h: number;\n dx: number;\n dy: number;\n fw: number;\n fh: number;\n bg: string;\n}): Promise<string> {\n const img = new Image();\n img.src = `data:image/png;base64,${a.png}`;\n await img.decode();\n const c = document.createElement(\"canvas\");\n c.width = a.w;\n c.height = a.h;\n const g = c.getContext(\"2d\") as CanvasRenderingContext2D;\n g.fillStyle = a.bg;\n g.fillRect(0, 0, a.w, a.h);\n const [x, y, tw, th] = a.trim;\n g.drawImage(img, x, y, tw, th, a.dx, a.dy, tw, th);\n let out = c;\n if (a.fw !== a.w || a.fh !== a.h) {\n out = document.createElement(\"canvas\");\n out.width = a.fw;\n out.height = a.fh;\n const s = out.getContext(\"2d\") as CanvasRenderingContext2D;\n s.imageSmoothingQuality = \"high\";\n s.drawImage(c, 0, 0, a.fw, a.fh);\n }\n return out.toDataURL(\"image/png\").slice(\"data:image/png;base64,\".length);\n}\n\n/** `html` rendered at the zoom (a wide table is never clipped) and trimmed: Python `_trim(_render_gt(...))`. */\nasync function snap(p: Page, html: string, o: Resolved): Promise<Shot> {\n await p.setViewportSize({ width: VIEWPORT, height: 800 });\n await p.setContent(page(html, o), { waitUntil: \"load\" });\n await p.evaluate(() => document.fonts.ready);\n const root = p.locator(\"#sdv-root\");\n const box = await root.boundingBox();\n if (box) {\n const z = o.deviceScaleFactor;\n checkCanvas(\"the table renders\", Math.ceil(box.width * z), Math.ceil(box.height * z), o);\n }\n if (box && box.width > VIEWPORT) await p.setViewportSize({ width: Math.ceil(box.width), height: 800 });\n const png = Buffer.from(await root.screenshot({ type: \"png\" })).toString(\"base64\");\n return { png, trim: await p.evaluate(trimBox, png) };\n}\n\n/**\n * Python's finishing steps, in image pixels: `_extent` to `minWidth` (centred), `_pad` by `whitespace`, the social\n * `_canvas` + `_extent` by gravity, `_fit_width` to `width`. Writes `o.file` when set.\n */\nasync function finish(\n p: Page,\n shot: Shot,\n o: Resolved,\n { minWidth = 0, ratio, gravity = \"center\" }: { minWidth?: number; ratio?: number; gravity?: Gravity } = {},\n): Promise<Uint8Array> {\n const [, , tw, th] = shot.trim;\n const ws = o.whitespace;\n let [w, h] = [Math.max(tw, minWidth) + 2 * ws, th + 2 * ws];\n let [dx, dy] = [Math.floor((w - 2 * ws - tw) / 2) + ws, ws];\n if (ratio !== undefined) {\n const [cw, ch] = canvasFor(w, h, ratio);\n const [ox, oy] = offsetFor(cw - w, ch - h, gravity);\n [w, h, dx, dy] = [cw, ch, dx + ox, dy + oy];\n }\n // Python _fit_width: the height rounded half up, as ImageMagick\n const [fw, fh] =\n o.width === undefined ? [w, h] : [o.width, Math.max(1, Math.floor((h * o.width) / w + 0.5))];\n checkCanvas(\"the image would be\", w, h, o);\n checkCanvas(\"the image scaled to `width` would be\", fw, fh, o);\n const b64 = await p.evaluate(drawPNG, {\n png: shot.png,\n trim: shot.trim,\n w,\n h,\n dx,\n dy,\n fw,\n fh,\n bg: o.background,\n });\n // \"data:,\" (no base64): a canvas Chromium would not allocate; never return or write an empty image\n if (b64 === \"\")\n throw new SdvplotError(`Chromium returned an empty image for ${n(fw)} × ${n(fh)} px; ${REMEDY}`);\n const png = new Uint8Array(Buffer.from(b64, \"base64\"));\n if (o.file !== undefined) await writeFile(o.file, png);\n return png;\n}\n\nasync function withPage<T>(o: Resolved, fn: (p: Page) => Promise<T>): Promise<T> {\n const browser = await launch();\n try {\n return await fn(await browser.newPage({ deviceScaleFactor: o.deviceScaleFactor }));\n } finally {\n await browser.close();\n }\n}\n\n/**\n * gt_save_crop for any HTML: rendered at `deviceScaleFactor`, trimmed to its content, `whitespace` image pixels of\n * `background` put back around it, then scaled to `width` when given. An image past Chromium's canvas limit (65,535\n * px a side, 268,435,456 px in all; near 1,000 plain rows at zoom 2) throws `SdvplotError` naming its size, before\n * anything is drawn or written.\n */\nexport async function htmlToPNG(html: string, options: PNGOptions = {}): Promise<Uint8Array> {\n const o = resolve(options);\n return withPage(o, async (p) => finish(p, await snap(p, html, o), o));\n}\n\n/** gt_save_crop: {@link htmlToPNG} of the rendered table. */\nexport function tableToPNG<Row>(\n spec: TableSpec<Row>,\n rows: readonly Row[],\n options: PNGOptions = {},\n): Promise<Uint8Array> {\n return htmlToPNG(renderHTML(spec, rows), options);\n}\n\n/** gt_social_crop: the trimmed, padded table on a fixed-ratio canvas placed by `gravity`; the table is never cropped. */\nexport async function socialCrop<Row>(\n spec: TableSpec<Row>,\n rows: readonly Row[],\n { aspect = \"1:1\", gravity = \"center\", ...rest }: SocialCropOptions = {},\n): Promise<Uint8Array> {\n const ratio = parseAspect(aspect);\n const place = parseGravity(gravity);\n const o = resolve({ whitespace: 60, ...rest });\n const html = renderHTML(spec, rows);\n return withPage(o, async (p) => finish(p, await snap(p, html, o), o, { ratio, gravity: place }));\n}\n\n/**\n * gt_save_batch: one image per group value, `{group}` in the file name replaced by `slug(value)`. A group whose table\n * fails to build (`build` or the spec throws) is skipped and named in one warning at the end; when none builds, the\n * error lists every failure. Python's `quiet` progress lines are not ported.\n */\nexport async function batchToPNG<Row, G extends keyof Row>(\n rows: readonly Row[],\n group: G,\n build: (groupRows: Row[], value: Row[G]) => TableItem<Row>,\n filePattern: string,\n { dir, matchWidth = true, ...rest }: BatchOptions,\n): Promise<string[]> {\n if (!filePattern.includes(\"{group}\"))\n throw new InputError(`filePattern must contain \"{group}\", got ${filePattern}`);\n checkPng(filePattern);\n const o = resolve(rest);\n const groups = new Map<Row[G], Row[]>();\n for (const r of rows) {\n const v = r[group];\n if (v === null || v === undefined) continue;\n const bucket = groups.get(v);\n if (bucket) bucket.push(r);\n else groups.set(v, [r]);\n }\n if (groups.size === 0) throw new InputError(`no non-missing values in column ${String(group)}`);\n const names = [...groups.keys()].map((v) => filePattern.replace(\"{group}\", slug(v)));\n const shared = [...new Set(names.filter((n, i) => names.indexOf(n) !== i))].sort();\n if (shared.length > 0)\n // Python gt_save_batch: two values must never write one file\n throw new InputError(\n `group values write to the same file name: ${shared.join(\", \")}; rename the values first`,\n );\n const items: { file: string; html: string }[] = [];\n const failed: string[] = [];\n [...groups].forEach(([v, rs], i) => {\n try {\n const built = build(rs, v);\n items.push({\n file: join(dir, names[i] as string),\n html: typeof built === \"string\" ? built : renderHTML(built.spec, built.rows),\n });\n } catch (e) {\n failed.push(`${String(v)}: ${e instanceof Error ? e.message : String(e)}`);\n }\n });\n if (items.length === 0) throw new SdvplotError(`No group built successfully:\\n${failed.join(\"\\n\")}`);\n await mkdir(dir, { recursive: true });\n const out = await withPage(o, async (p) => {\n const shots: Shot[] = [];\n for (const it of items) shots.push(await snap(p, it.html, o));\n // Python: every trimmed image extended (centred) to the widest one's width, then padded\n const minWidth = matchWidth ? Math.max(...shots.map((s) => s.trim[2])) : 0;\n for (const [i, it] of items.entries())\n await finish(p, shots[i] as Shot, { ...o, file: it.file }, { minWidth });\n return items.map((it) => it.file);\n });\n if (failed.length > 0)\n warn(\n `sdvtables:batch:${filePattern}:${failed.join(\"|\")}`,\n `${failed.length} group(s) failed and were skipped:\\n${failed.join(\"\\n\")}`,\n );\n return out;\n}\n"]}
|
package/dist/html.d.ts
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { League } from '@sportsdataverse/sdvplot';
|
|
2
|
+
import { S as Sort, T as TableCursor, a as Table } from './engine-CkfxYXAL.js';
|
|
3
|
+
export { c as createTable } from './engine-CkfxYXAL.js';
|
|
4
|
+
import { C as ColumnSpec, T as TableSpec, a as ThemeRef, D as Density } from './spec-BEhLDtj_.js';
|
|
5
|
+
import { T as Theme, G as GoogleFont } from './tokens-CpYFsFtf.js';
|
|
6
|
+
|
|
7
|
+
interface RenderOptions {
|
|
8
|
+
readonly css?: "inline" | "none";
|
|
9
|
+
readonly fonts?: boolean;
|
|
10
|
+
/** Phase 5: a sort button on every `sortable !== false` column, and aria-sort on the sorted one */
|
|
11
|
+
readonly interactive?: boolean;
|
|
12
|
+
/** Phase 5: the engine's current sort, for aria-sort */
|
|
13
|
+
readonly sort?: Sort | null;
|
|
14
|
+
/** Phase 5: engine-hidden column keys (merged with decoration-hidden columns); a key that is not a column throws `TableSpecError` */
|
|
15
|
+
readonly hidden?: readonly string[];
|
|
16
|
+
/** J31 (A5): page-relative indices of selected rows → `sdvt-selected` on their `<tr>` */
|
|
17
|
+
readonly selected?: ReadonlySet<number>;
|
|
18
|
+
/**
|
|
19
|
+
* J31 (A4): rows the scale/legend domains, outlier limits and row-accent levels are computed from, and the rows
|
|
20
|
+
* an index row selector (`boldRows([5])`) counts in; default the rendered rows. Interactive renders pass the
|
|
21
|
+
* table's full source rows (A49), so nothing re-colours or moves while the user pages, filters, sorts or brushes.
|
|
22
|
+
* It must hold the same row OBJECTS as `rows` (matched by identity, as the engine passes them), not equal copies:
|
|
23
|
+
* a rendered row missing from it is colored from its own value (a rank fill gets none) and warns once per column.
|
|
24
|
+
*/
|
|
25
|
+
readonly domainRows?: readonly unknown[];
|
|
26
|
+
/**
|
|
27
|
+
* Task 10 (A48): with `interactive`, render the table as a selectable ARIA grid: `role="grid"` and
|
|
28
|
+
* `aria-multiselectable="true"` on the table, `tabindex="0"` on the body row whose index is `grid.row` (clamped to
|
|
29
|
+
* the rows) and `"-1"` on the others, `aria-selected` on every body row, and `sdvt-col-current` plus
|
|
30
|
+
* `aria-current="true"` on the header of `grid.col`. Ignored without `interactive`.
|
|
31
|
+
*/
|
|
32
|
+
readonly grid?: TableCursor;
|
|
33
|
+
}
|
|
34
|
+
/** One render split into strings: `assemble` joins them into `renderHTML`'s output; `tableHTML` is the part that depends on the rows. */
|
|
35
|
+
interface RenderedParts {
|
|
36
|
+
/** the table id (`tableId(spec)`), also the wrapper's `id` */
|
|
37
|
+
readonly id: string;
|
|
38
|
+
/** the Google Fonts `<link>`, or "" */
|
|
39
|
+
readonly link: string;
|
|
40
|
+
/** class, id, data-sdvt-theme, data-sdvt-density — UNESCAPED values, in this order */
|
|
41
|
+
readonly wrapperAttrs: Readonly<Record<string, string>>;
|
|
42
|
+
/** the shared theme sheet (`styleSheet`) without the tag, or "" when css === "none" */
|
|
43
|
+
readonly sheet: string;
|
|
44
|
+
/** the decorations' own rules without the tag, or "" — part of the table block, so hydrate re-renders them */
|
|
45
|
+
readonly rules: string;
|
|
46
|
+
/** decoration blocks placed before the table element (top border bars and legends), or "" */
|
|
47
|
+
readonly before: string;
|
|
48
|
+
/** the caption element (title, subtitle), or "" */
|
|
49
|
+
readonly caption: string;
|
|
50
|
+
/** header rows above the main one, or "" (no decoration emits any yet) */
|
|
51
|
+
readonly headRows: string;
|
|
52
|
+
/** the `<th>` cells of the main header row */
|
|
53
|
+
readonly head: string;
|
|
54
|
+
/** each SHOWN column's header text, unescaped, keyed by column key (a marginalia rename and scaleNote suffix included): the toolbar's filter labels */
|
|
55
|
+
readonly labels: ReadonlyMap<string, string>;
|
|
56
|
+
/** every body `<tr>` (group header rows included) */
|
|
57
|
+
readonly rows: string;
|
|
58
|
+
/** the tfoot element (source notes, footnotes), or "" */
|
|
59
|
+
readonly foot: string;
|
|
60
|
+
/** decoration blocks placed after the table element (bottom border bars and legends), or "" */
|
|
61
|
+
readonly after: string;
|
|
62
|
+
/** the `<table>` tag's attributes with a leading space (Task 10: the grid role), or "" */
|
|
63
|
+
readonly tableAttrs: string;
|
|
64
|
+
}
|
|
65
|
+
declare function labelOf<Row>(col: ColumnSpec<Row>): string;
|
|
66
|
+
/** Class shared by every table with the same theme name + density + options (two sdvTeam tables for different teams get different keys). */
|
|
67
|
+
declare function themeKey(ref: ThemeRef): string;
|
|
68
|
+
/** The `<style>` body without the tag: token block + base sheet + the theme's own rules, scoped to `.sdvt-t-<key>`. A host page emits it once per key. */
|
|
69
|
+
declare function styleSheet<Row>(spec: TableSpec<Row>, theme?: Theme): string;
|
|
70
|
+
/** The `aria-sort` value of column `key` under `sort`: "none" unless `sort` is on that column. */
|
|
71
|
+
declare function sortAria(sort: Sort | null | undefined, key: string): "ascending" | "descending" | "none";
|
|
72
|
+
/** ` k="v"` for each entry, in order. Values are attribute-escaped; keys are NOT escaped, so they must be trusted names. */
|
|
73
|
+
declare function attrsText(attrs: Readonly<Record<string, string>>): string;
|
|
74
|
+
/** The table block: the decorations' own `<style>`, then before + `<table>` + after. hydrate re-renders exactly this. */
|
|
75
|
+
declare function tableHTML(p: RenderedParts): string;
|
|
76
|
+
/**
|
|
77
|
+
* The fonts link, then the wrapper holding the theme sheet and `inner` (default: the table block).
|
|
78
|
+
* `inner` is inserted as raw, unescaped HTML: pass trusted renderer output (`tableHTML`) only, never data.
|
|
79
|
+
*/
|
|
80
|
+
declare function assemble(p: RenderedParts, inner?: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Render `rows` of `spec` as {@link RenderedParts}; `assemble(renderParts(spec, rows, opts))` is `renderHTML`'s output.
|
|
83
|
+
* Throws `TableSpecError` for a column key missing from the first row, an unknown `hidden` key, or an invalid spec.
|
|
84
|
+
*/
|
|
85
|
+
declare function renderParts<Row>(input: TableSpec<Row>, rows: readonly Row[], opts?: RenderOptions): RenderedParts;
|
|
86
|
+
/** The Google Fonts link element `renderHTML(spec, ...)` would emit (theme and decoration fonts), or "": for a page's head. */
|
|
87
|
+
declare const fontsLinkFor: <Row>(spec: TableSpec<Row>) => string;
|
|
88
|
+
|
|
89
|
+
/** One scaled column (pills, ranks, percentile), computed once per column by Task 8's columnScales. */
|
|
90
|
+
interface ColumnScale {
|
|
91
|
+
readonly domain: readonly [number, number];
|
|
92
|
+
readonly palette: readonly string[];
|
|
93
|
+
readonly reverse: boolean;
|
|
94
|
+
readonly values: readonly (number | null)[];
|
|
95
|
+
readonly color: (v: number) => string | null;
|
|
96
|
+
/** colorPills: the widest label in `ch`, computed once per column (gt_color_pills); 1 otherwise. */
|
|
97
|
+
readonly labelWidth: number;
|
|
98
|
+
}
|
|
99
|
+
/** Decided once here; Tasks 7, 8 and 10 fill the maps (index.ts passes them empty until then). */
|
|
100
|
+
interface RenderContext<Row> {
|
|
101
|
+
readonly spec: TableSpec<Row>;
|
|
102
|
+
readonly rows: readonly Row[];
|
|
103
|
+
/** J31 (A4): the rows scale and legend domains come from (`RenderOptions.domainRows`, default `rows`). */
|
|
104
|
+
readonly domainRows: readonly Row[];
|
|
105
|
+
readonly theme: Theme;
|
|
106
|
+
readonly id: string;
|
|
107
|
+
readonly sel: string;
|
|
108
|
+
readonly columns: readonly ColumnSpec<Row>[];
|
|
109
|
+
readonly groupKey: string | undefined;
|
|
110
|
+
readonly warn: (key: string, message: string) => void;
|
|
111
|
+
/** Task 7: team ids per team column, ONE resolveSync per column (J28), keyed by the column key. */
|
|
112
|
+
readonly teamIds: ReadonlyMap<string, readonly (string | undefined)[]>;
|
|
113
|
+
/** Task 8: scales per pills/ranks/percentile column, keyed by column key. */
|
|
114
|
+
readonly scales: ReadonlyMap<string, ColumnScale>;
|
|
115
|
+
/** Task 8: the last scale in column order — what gt_legend_continuous reads back as `_sdvplot_scale`. */
|
|
116
|
+
readonly recorded: ColumnScale | undefined;
|
|
117
|
+
/** Task 10: scaleNote divisor + decimals per num/int column; applyDecorations fills it before the row loop. */
|
|
118
|
+
readonly scaled: Map<string, {
|
|
119
|
+
readonly divisor: number;
|
|
120
|
+
readonly decimals: number;
|
|
121
|
+
}>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** The Google Fonts css2 `<link>` for these faces (weights merged per family, families sorted); "" when there are none. */
|
|
125
|
+
declare function fontsLink(fonts: readonly GoogleFont[]): string;
|
|
126
|
+
|
|
127
|
+
/** J31: the engine id of the body row an event landed in; null for a header, toolbar, pager, group row, or outside the table. */
|
|
128
|
+
declare function rowIdAt<Row>(table: Table<Row>, target: EventTarget | null): string | null;
|
|
129
|
+
/** A click anywhere inside the table wrapper — shared by hydrate and `<SdvTable/>`. */
|
|
130
|
+
declare function handleClick<Row>(table: Table<Row>, target: EventTarget | null): void;
|
|
131
|
+
/** An `input` event anywhere inside the wrapper. */
|
|
132
|
+
declare function handleInput<Row>(table: Table<Row>, target: EventTarget | null): void;
|
|
133
|
+
/** J31: `mouseover` / `mouseleave` inside the wrapper → the engine's hover event (null off a body row). */
|
|
134
|
+
declare function handleHover<Row>(table: Table<Row>, target: EventTarget | null): void;
|
|
135
|
+
/** Task 10: what a key means to an interactive table (see {@link keyAction}). */
|
|
136
|
+
type KeyAction = {
|
|
137
|
+
readonly type: "cursor";
|
|
138
|
+
readonly row: number;
|
|
139
|
+
readonly col: string | null;
|
|
140
|
+
} | {
|
|
141
|
+
readonly type: "sort";
|
|
142
|
+
readonly col: string;
|
|
143
|
+
} | {
|
|
144
|
+
readonly type: "search";
|
|
145
|
+
} | {
|
|
146
|
+
readonly type: "toggle";
|
|
147
|
+
readonly row: number;
|
|
148
|
+
};
|
|
149
|
+
/** Task 10: everything {@link keyAction} reads; {@link handleKeydown} gathers it from the engine and the DOM. */
|
|
150
|
+
interface KeyContext {
|
|
151
|
+
/** the `data-row` of the body row the key landed in, or null (toolbar, header, pager) */
|
|
152
|
+
readonly focused: number | null;
|
|
153
|
+
/**
|
|
154
|
+
* the key landed on that body row itself, not on a link or button inside it (that control keeps its Enter, Space
|
|
155
|
+
* and left/right keys)
|
|
156
|
+
*/
|
|
157
|
+
readonly onRow: boolean;
|
|
158
|
+
/** the engine's cursor (`table.state.cursor`) */
|
|
159
|
+
readonly cursor: TableCursor;
|
|
160
|
+
/** the sorted column (`table.state.sort?.col`), or null */
|
|
161
|
+
readonly sorted: string | null;
|
|
162
|
+
/** the shown sortable columns in header order: the `data-sdv-sort` buttons */
|
|
163
|
+
readonly cols: readonly string[];
|
|
164
|
+
/** the page's body rows' `data-row` values in display order (`groupBy` reorders them) */
|
|
165
|
+
readonly order: readonly number[];
|
|
166
|
+
/** `spec.interactive.hotkeys !== false`: the letter keys and `/` are on */
|
|
167
|
+
readonly hotkeys: boolean;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Task 10 (A45, G19): the action a keydown means, or null when it means nothing here. Pure. `j`/`k` (and the down and
|
|
171
|
+
* up arrows) move the cursor row in display order, and enter the grid at the cursor row when the key came from
|
|
172
|
+
* outside the rows; `h`/`l` (left and right arrows) move the cursor column over the shown sortable columns, starting
|
|
173
|
+
* from the cursor column, else the sorted one, else the first; `s` sorts that column; `/` goes to the search box;
|
|
174
|
+
* Enter and Space toggle the selection of the row the key landed on. Moves stop at the edges: `j`/`k` stop at the
|
|
175
|
+
* first and last row of the CURRENT page and never turn it (the pager does), `h`/`l` at the first and last sortable
|
|
176
|
+
* column. A left/right key that lands on a link or button inside a row (`focused` set, `onRow` false) is that
|
|
177
|
+
* control's: null.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* import { keyAction } from "@sportsdataverse/sdvtables/html";
|
|
182
|
+
*
|
|
183
|
+
* // `l` on the first row of a table sorted by wins: the cursor column moves right, to net_epa
|
|
184
|
+
* keyAction("l", {
|
|
185
|
+
* focused: 0,
|
|
186
|
+
* onRow: true,
|
|
187
|
+
* cursor: { row: 0, col: null },
|
|
188
|
+
* sorted: "wins",
|
|
189
|
+
* cols: ["team", "wins", "net_epa"],
|
|
190
|
+
* order: [0, 1, 2],
|
|
191
|
+
* hotkeys: true,
|
|
192
|
+
* });
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
declare function keyAction(key: string, k: KeyContext): KeyAction | null;
|
|
196
|
+
/**
|
|
197
|
+
* Task 10 (A45, A48): a keydown anywhere inside `root`, the table wrapper; shared by hydrate and `<SdvTable/>`.
|
|
198
|
+
* Ignored with Ctrl, Meta or Alt held, during IME composition, or when it comes from a text field (input, textarea,
|
|
199
|
+
* select, contenteditable). Otherwise {@link keyAction} decides, and a key that acts is consumed (`preventDefault`):
|
|
200
|
+
* a cursor move focuses the destination row BEFORE the engine re-renders, so the re-render's focus restore keeps it
|
|
201
|
+
* there; `s` and Enter/Space go through {@link handleClick} on the column's sort button or on the row, exactly as a
|
|
202
|
+
* click, once per press (a held key's repeats are consumed but toggle nothing); `/` focuses the search box, and passes
|
|
203
|
+
* through to the browser (quick-find) when `root` has none. `spec.interactive.hotkeys: false` leaves only the arrows,
|
|
204
|
+
* Enter and Space.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* import { createTable, defineTable } from "@sportsdataverse/sdvtables";
|
|
209
|
+
* import { handleKeydown, renderHTML } from "@sportsdataverse/sdvtables/html";
|
|
210
|
+
*
|
|
211
|
+
* // 2024 AFC: Kansas City 15 wins, Buffalo 13
|
|
212
|
+
* const spec = defineTable<{ team: string; wins: number }>()
|
|
213
|
+
* .columns((c) => [c.text("team"), c.int("wins")])
|
|
214
|
+
* .build();
|
|
215
|
+
* const table = createTable(spec, [
|
|
216
|
+
* { team: "KC", wins: 15 },
|
|
217
|
+
* { team: "BUF", wins: 13 },
|
|
218
|
+
* ]);
|
|
219
|
+
* const root = document.createElement("div");
|
|
220
|
+
* root.innerHTML = renderHTML(table, { fonts: false });
|
|
221
|
+
* root.addEventListener("keydown", (e) => handleKeydown(table, root, e));
|
|
222
|
+
* root
|
|
223
|
+
* .querySelector("[data-sdv-body] tr[data-row]")
|
|
224
|
+
* ?.dispatchEvent(new KeyboardEvent("keydown", { key: "j", bubbles: true, cancelable: true }));
|
|
225
|
+
* table.state.cursor; // { row: 1, col: null }
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
declare function handleKeydown<Row>(table: Table<Row>, root: Element, e: KeyboardEvent): void;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Progressive enhancement for markup produced by `renderHTML(table)`: one delegated click + input listener drive the
|
|
232
|
+
* engine; each change re-renders ONLY the table block (`[data-sdv-body]`) and the pager, once, on the next animation
|
|
233
|
+
* frame, however many changes land in it (the engine state itself moves synchronously). One exception: a click,
|
|
234
|
+
* pointer move or key on the table while a change to its rows (a sort, filter, page turn or `setRows`) waits for that
|
|
235
|
+
* frame draws it at once, so the event never reads an old row as the one now at its index; a click or key on a row
|
|
236
|
+
* this replaced acts on nothing, and Enter or Space on it is consumed, so the page does not scroll. A change that keeps
|
|
237
|
+
* the rows (a selection, the cursor, a keyed row re-sent as a new object) waits for its frame. Toolbar inputs are
|
|
238
|
+
* rebuilt only when a column is hidden or shown; otherwise their values are synced from the engine state, so an
|
|
239
|
+
* external filter change shows in the box. A row hover (the pointer's, or a linked figure's through `linkSelection`)
|
|
240
|
+
* re-renders nothing: the row gets the `sdvt-hover` class, which survives the next re-render; a hover the engine
|
|
241
|
+
* already holds (`getHover`) shows on attach. A focused control, or a focusable element inside a rendered cell, that
|
|
242
|
+
* the re-render replaced gets focus back (shadow-root mounts included). Attaching does NOT reconcile the SSR markup
|
|
243
|
+
* against the engine state: render the markup from the same table state you hydrate. Hydrating an element again
|
|
244
|
+
* replaces its previous binding (HMR, client-side navigation, an effect without cleanup) after drawing any change that
|
|
245
|
+
* binding still owed, so every control still acts once. The returned teardown is idempotent and drops a render still
|
|
246
|
+
* owed; hydrating that element again redraws it (on the next frame, or at once for an event that comes first), so React
|
|
247
|
+
* StrictMode's mount, cleanup, mount leaves no stale rows. Until the teardown runs, the table's subscriber keeps `el`
|
|
248
|
+
* alive as long as the table lives.
|
|
249
|
+
*/
|
|
250
|
+
declare function hydrate<Row>(el: Element, table: Table<Row>): () => void;
|
|
251
|
+
|
|
252
|
+
/** J31 (A4, A5): the engine-driven render options, built in ONE place for renderInteractive, hydrate and `<SdvTable/>`. */
|
|
253
|
+
declare function tableRenderOptions<Row>(table: Table<Row>): RenderOptions;
|
|
254
|
+
/** The pager's page text, `"Page <page> of <pageCount>"` with a 1-based page, e.g. `"Page 1 of 3"`. */
|
|
255
|
+
declare function pagerLabel<Row>(table: Table<Row>): string;
|
|
256
|
+
/**
|
|
257
|
+
* Global search box, then one filter input per shown `filterable` column, each with a visually hidden `<label>`
|
|
258
|
+
* naming the column by its shown header text. `value` is written last (React's attribute order). `labels` defaults
|
|
259
|
+
* to a render of the table's current page; pass `renderParts(…).labels` when you already have one.
|
|
260
|
+
*/
|
|
261
|
+
declare function renderToolbar<Row>(table: Table<Row>, labels?: ReadonlyMap<string, string>): string;
|
|
262
|
+
/**
|
|
263
|
+
* The pager: Previous and Next buttons around {@link pagerLabel}, a polite live region. Rendered only when
|
|
264
|
+
* `pageSize` is finite. An edge button is `aria-disabled`, not `disabled`, so a keyboard user paging to the end
|
|
265
|
+
* keeps focus on it (a disabled button drops focus to the page body); a click on it does nothing.
|
|
266
|
+
*/
|
|
267
|
+
declare function renderPager<Row>(table: Table<Row>): string;
|
|
268
|
+
/** The interactive document: the wrapper holding the style, toolbar, body block and pager, in that order. */
|
|
269
|
+
declare function renderInteractive<Row>(table: Table<Row>, opts?: RenderOptions): string;
|
|
270
|
+
|
|
271
|
+
/** Leagues whose shards the spec needs (team-aware columns + the sdvTeam theme). Headshot columns need no shard: ESPN ids are pure URLs. */
|
|
272
|
+
declare function leaguesOf<Row>(spec: TableSpec<Row>): League[];
|
|
273
|
+
/** The documented preparation step: every league shard the spec names, plus the gsis map when a headshot column uses gsis ids (J27). Task 7 adds team names. */
|
|
274
|
+
declare function prepare<Row>(spec: TableSpec<Row>): Promise<void>;
|
|
275
|
+
/**
|
|
276
|
+
* Static markup from a spec, or the interactive document (toolbar, aria-sort headers, pager) from a `createTable`
|
|
277
|
+
* instance.
|
|
278
|
+
*
|
|
279
|
+
* A spec renders as one HTML string, synchronously: the theme as a scoped `<style>` (with `css: "none"` the host
|
|
280
|
+
* page emits `styleSheet(spec)` once instead), then the table. Cells that read league data (logos, team names) need
|
|
281
|
+
* `await prepare(spec)` first, or use `renderHTMLAsync`. Throws `TableSpecError` for a column the rows lack or an
|
|
282
|
+
* unknown theme.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* ```ts
|
|
286
|
+
* import { defineTable } from "@sportsdataverse/sdvtables";
|
|
287
|
+
* import { renderHTML } from "@sportsdataverse/sdvtables/html";
|
|
288
|
+
*
|
|
289
|
+
* const rows = [
|
|
290
|
+
* { team: "BUF", pf: 525, pa: 368 },
|
|
291
|
+
* { team: "DEN", pf: 425, pa: 311 },
|
|
292
|
+
* { team: "LAC", pf: 402, pa: 301 },
|
|
293
|
+
* ];
|
|
294
|
+
* const spec = defineTable<(typeof rows)[number]>()
|
|
295
|
+
* .columns((c) => [c.text("team"), c.int("pf", { label: "Points for" }), c.int("pa", { label: "Points against" })])
|
|
296
|
+
* .theme("athletic")
|
|
297
|
+
* .build();
|
|
298
|
+
* renderHTML(spec, rows);
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
declare function renderHTML<Row>(table: Table<Row>, opts?: RenderOptions): string;
|
|
302
|
+
declare function renderHTML<Row>(spec: TableSpec<Row>, rows: readonly Row[], opts?: RenderOptions): string;
|
|
303
|
+
|
|
304
|
+
declare function renderHTMLAsync<Row>(spec: TableSpec<Row>, rows: readonly Row[], opts?: RenderOptions): Promise<string>;
|
|
305
|
+
declare function toElement<Row>(spec: TableSpec<Row>, rows: readonly Row[], opts?: RenderOptions): HTMLElement;
|
|
306
|
+
/**
|
|
307
|
+
* gt_theme_preview (_themes.py:2058-2064): one HTML string per theme, first n rows, compact; sdvTeam shown with
|
|
308
|
+
* league nfl and no team.
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```ts
|
|
312
|
+
* import { defineTable } from "@sportsdataverse/sdvtables";
|
|
313
|
+
* import { themePreview } from "@sportsdataverse/sdvtables/html";
|
|
314
|
+
*
|
|
315
|
+
* const rows = [
|
|
316
|
+
* { team: "KC", wins: 15, losses: 2 },
|
|
317
|
+
* { team: "BUF", wins: 13, losses: 4 },
|
|
318
|
+
* ];
|
|
319
|
+
* const spec = defineTable<(typeof rows)[number]>()
|
|
320
|
+
* .columns((c) => [c.text("team"), c.int("wins"), c.int("losses")])
|
|
321
|
+
* .build();
|
|
322
|
+
* Object.values(themePreview(spec, rows, ["sdv", "athletic", "midnight"])).join("\n");
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
declare function themePreview<Row>(spec: TableSpec<Row>, rows: readonly Row[], themes?: readonly string[], o?: {
|
|
326
|
+
n?: number;
|
|
327
|
+
density?: Density;
|
|
328
|
+
}): Record<string, string>;
|
|
329
|
+
|
|
330
|
+
export { type ColumnScale, GoogleFont, type KeyAction, type KeyContext, type RenderContext, type RenderOptions, type RenderedParts, assemble, attrsText, labelOf as columnLabel, fontsLink, fontsLinkFor, handleClick, handleHover, handleInput, handleKeydown, hydrate, keyAction, labelOf, leaguesOf, pagerLabel, prepare, renderHTML, renderHTMLAsync, renderInteractive, renderPager, renderParts, renderToolbar, rowIdAt, sortAria, styleSheet, tableHTML, tableRenderOptions, themeKey, themePreview, toElement };
|
package/dist/html.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { hydrate, leaguesOf, prepare, renderHTML, renderHTMLAsync, themePreview, toElement } from './chunk-U6W6MWKW.js';
|
|
2
|
+
export { assemble, attrsText, labelOf as columnLabel, fontsLink, fontsLinkFor, handleClick, handleHover, handleInput, handleKeydown, keyAction, labelOf, pagerLabel, renderInteractive, renderPager, renderParts, renderToolbar, rowIdAt, sortAria, styleSheet, tableHTML, tableRenderOptions, themeKey } from './chunk-UCRLJGDL.js';
|
|
3
|
+
export { createTable } from './chunk-4VKYHOHL.js';
|
|
4
|
+
//# sourceMappingURL=html.js.map
|
|
5
|
+
//# sourceMappingURL=html.js.map
|
package/dist/html.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"html.js"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { b as ColumnBase, C as ColumnSpec, N as NumericKey, T as TableSpec, D as Density, c as Decoration, P as Predicate, R as RowSelector, a as ThemeRef } from './spec-BEhLDtj_.js';
|
|
2
|
+
export { A as Align, d as ColumnKind, e as DecorationType, F as FormatType, f as PredicateOp, S as StringKey, g as TeamOpts, h as TextStyle } from './spec-BEhLDtj_.js';
|
|
3
|
+
import { SdvplotError } from '@sportsdataverse/sdvplot';
|
|
4
|
+
export { RowFilter } from '@sportsdataverse/sdvplot';
|
|
5
|
+
import { a as ThemeDef, T as Theme } from './tokens-CpYFsFtf.js';
|
|
6
|
+
export { D as DENSITY, G as GoogleFont, b as TOKEN_KEYS, c as ThemeTokens } from './tokens-CpYFsFtf.js';
|
|
7
|
+
export { C as Comparator, F as FilterValue, N as NUMERIC_KINDS, S as Sort, b as SortDir, a as Table, T as TableCursor, d as TableEvent, e as TableOptions, f as TableSnapshot, g as TableState, V as ValuePredicate, h as applyFilters, i as applySort, j as comparatorFor, c as createTable, k as findColumn, l as isMissing, n as nextSortDir, p as paginate, w as withMissingLast } from './engine-CkfxYXAL.js';
|
|
8
|
+
|
|
9
|
+
declare class TableSpecError extends SdvplotError {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Opt<T, K extends PropertyKey> = Omit<T, "kind" | "key" | K>;
|
|
13
|
+
type Base<Row, K extends keyof Row & string> = Omit<ColumnBase<Row, K>, "key">;
|
|
14
|
+
type Col<Row, Kind extends ColumnSpec<Row>["kind"]> = Extract<ColumnSpec<Row>, {
|
|
15
|
+
kind: Kind;
|
|
16
|
+
}>;
|
|
17
|
+
type Partialize<T, Req extends keyof T> = Partial<Omit<T, Req>> & Pick<T, Req>;
|
|
18
|
+
interface ColumnFactory<Row> {
|
|
19
|
+
text<K extends keyof Row & string>(key: K, o?: Base<Row, K>): Col<Row, "text">;
|
|
20
|
+
num<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "num">, never>>): Col<Row, "num">;
|
|
21
|
+
int<K extends NumericKey<Row>>(key: K, o?: Base<Row, K>): Col<Row, "int">;
|
|
22
|
+
pct<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "pct">, never>>): Col<Row, "pct">;
|
|
23
|
+
rank<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "rank">, never>>): Col<Row, "rank">;
|
|
24
|
+
delta<K extends NumericKey<Row>>(from: K, to: NumericKey<Row>, o?: Base<Row, K> & Partial<Opt<Col<Row, "delta">, "to">>): Col<Row, "delta">;
|
|
25
|
+
tally(keys: readonly [NumericKey<Row>, ...NumericKey<Row>[]], o?: Base<Row, NumericKey<Row>> & Partial<Opt<Col<Row, "tally">, "keys">>): Col<Row, "tally">;
|
|
26
|
+
logo<K extends keyof Row & string>(key: K, o: Base<Row, K> & Partialize<Opt<Col<Row, "logo">, never>, "league">): Col<Row, "logo">;
|
|
27
|
+
wordmark<K extends keyof Row & string>(key: K, o: Base<Row, K> & Partialize<Opt<Col<Row, "wordmark">, never>, "league">): Col<Row, "wordmark">;
|
|
28
|
+
headshot<K extends keyof Row & string>(key: K, o: Base<Row, K> & Partialize<Opt<Col<Row, "headshot">, never>, "league">): Col<Row, "headshot">;
|
|
29
|
+
colorPills<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "colorPills">, never>>): Col<Row, "colorPills">;
|
|
30
|
+
colorRanks<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "colorRanks">, never>>): Col<Row, "colorRanks">;
|
|
31
|
+
colorResults<K extends keyof Row & string>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "colorResults">, never>>): Col<Row, "colorResults">;
|
|
32
|
+
percentileBar<K extends NumericKey<Row>>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "percentileBar">, never>>): Col<Row, "percentileBar">;
|
|
33
|
+
indicatorBox<K extends keyof Row & string>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "indicatorBox">, never>>): Col<Row, "indicatorBox">;
|
|
34
|
+
highlight<K extends keyof Row & string>(key: K, when: Col<Row, "highlight">["when"], o?: Base<Row, K> & Partial<Opt<Col<Row, "highlight">, "when">>): Col<Row, "highlight">;
|
|
35
|
+
highlightNa<K extends keyof Row & string>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "highlightNa">, never>>): Col<Row, "highlightNa">;
|
|
36
|
+
mergeStackTeamColor<K extends keyof Row & string>(key: K, stack: keyof Row & string, team: keyof Row & string, o: Base<Row, K> & Partialize<Opt<Col<Row, "mergeStackTeamColor">, "stack" | "team">, "league">): Col<Row, "mergeStackTeamColor">;
|
|
37
|
+
teamColorBar<K extends keyof Row & string>(key: K, o: Base<Row, K> & Partialize<Opt<Col<Row, "teamColorBar">, never>, "league">): Col<Row, "teamColorBar">;
|
|
38
|
+
teamColorBg<K extends keyof Row & string>(key: K, o: Base<Row, K> & Partialize<Opt<Col<Row, "teamColorBg">, never>, "league">): Col<Row, "teamColorBg">;
|
|
39
|
+
image<K extends keyof Row & string>(key: K, o?: Base<Row, K> & Partial<Opt<Col<Row, "image">, never>>): Col<Row, "image">;
|
|
40
|
+
/** gtUtils aliases — same objects, old names (see src/aliases.ts). */
|
|
41
|
+
fmtRank: ColumnFactory<Row>["rank"];
|
|
42
|
+
fmtTally: ColumnFactory<Row>["tally"];
|
|
43
|
+
}
|
|
44
|
+
/** gtUtils/sdvplot `_RANK_PALETTE` (green → red), shared by colorRanks, the legend fallback and tiers. */
|
|
45
|
+
declare const RANK_PALETTE: readonly string[];
|
|
46
|
+
declare function columnFactory<Row>(): ColumnFactory<Row>;
|
|
47
|
+
type D<Row, T extends Decoration<Row>["type"]> = Extract<Decoration<Row>, {
|
|
48
|
+
type: T;
|
|
49
|
+
}>;
|
|
50
|
+
declare class TableBuilder<Row> {
|
|
51
|
+
private readonly s;
|
|
52
|
+
constructor(s: TableSpec<Row>);
|
|
53
|
+
private add;
|
|
54
|
+
id(id: string): TableBuilder<Row>;
|
|
55
|
+
/** J31: the link id column (see `TableSpec.rowKey`). */
|
|
56
|
+
rowKey(key: keyof Row & string): TableBuilder<Row>;
|
|
57
|
+
columns(fn: (c: ColumnFactory<Row>) => readonly ColumnSpec<Row>[]): TableBuilder<Row>;
|
|
58
|
+
theme(name: string, o?: {
|
|
59
|
+
density?: Density;
|
|
60
|
+
options?: Readonly<Record<string, string>>;
|
|
61
|
+
}): TableBuilder<Row>;
|
|
62
|
+
title(text: string): TableBuilder<Row>;
|
|
63
|
+
subtitle(text: string): TableBuilder<Row>;
|
|
64
|
+
titleHeader(title: string, o?: Omit<D<Row, "titleHeader">, "type" | "title">): TableBuilder<Row>;
|
|
65
|
+
sourceNote(html: string, o?: {
|
|
66
|
+
unsafe?: boolean;
|
|
67
|
+
}): TableBuilder<Row>;
|
|
68
|
+
caption538(o?: Partial<Omit<D<Row, "caption538">, "type">>): TableBuilder<Row>;
|
|
69
|
+
groupBy(key: keyof Row & string): TableBuilder<Row>;
|
|
70
|
+
groupStripes(o?: Partial<Omit<D<Row, "groupStripes">, "type">>): TableBuilder<Row>;
|
|
71
|
+
rowAccent(key: keyof Row & string, o?: Partial<Omit<D<Row, "rowAccent">, "type" | "key">>): TableBuilder<Row>;
|
|
72
|
+
boldRows(rows: D<Row, "boldRows">["rows"], o?: Partial<Omit<D<Row, "boldRows">, "type" | "rows">>): TableBuilder<Row>;
|
|
73
|
+
spotlight(rows: D<Row, "spotlight">["rows"], o?: Partial<Omit<D<Row, "spotlight">, "type" | "rows">>): TableBuilder<Row>;
|
|
74
|
+
cutline(after: number | readonly number[], o?: Partial<Omit<D<Row, "cutline">, "type" | "after">>): TableBuilder<Row>;
|
|
75
|
+
borderGrid(o?: Partial<Omit<D<Row, "borderGrid">, "type">>): TableBuilder<Row>;
|
|
76
|
+
borderBars(side: "top" | "bottom", colors: readonly string[], o?: Partial<Omit<D<Row, "borderBars">, "type" | "side" | "colors">>): TableBuilder<Row>;
|
|
77
|
+
legendContinuous(o?: Partial<Omit<D<Row, "legendContinuous">, "type">>): TableBuilder<Row>;
|
|
78
|
+
legendDiscrete(key: D<Row, "legendDiscrete">["key"], o?: Partial<Omit<D<Row, "legendDiscrete">, "type" | "key">>): TableBuilder<Row>;
|
|
79
|
+
significance(pairs: D<Row, "significance">["pairs"], o?: Partial<Omit<D<Row, "significance">, "type" | "pairs">>): TableBuilder<Row>;
|
|
80
|
+
outliers(columns: readonly (keyof Row & string)[], o?: Partial<Omit<D<Row, "outliers">, "type" | "columns">>): TableBuilder<Row>;
|
|
81
|
+
scaleNote(columns: readonly (keyof Row & string)[], o?: Partial<Omit<D<Row, "scaleNote">, "type" | "columns">>): TableBuilder<Row>;
|
|
82
|
+
socialTag(accounts: Readonly<Record<string, string>>, o?: Partial<Omit<D<Row, "socialTag">, "type" | "accounts">>): TableBuilder<Row>;
|
|
83
|
+
watermark(o?: Partial<Omit<D<Row, "watermark">, "type">>): TableBuilder<Row>;
|
|
84
|
+
wrapLabels(o?: Partial<Omit<D<Row, "wrapLabels">, "type">>): TableBuilder<Row>;
|
|
85
|
+
marginalia(columns: readonly (keyof Row & string)[], o?: Partial<Omit<D<Row, "marginalia">, "type" | "columns">>): TableBuilder<Row>;
|
|
86
|
+
snake(o?: Partial<Omit<D<Row, "snake">, "type">>): TableBuilder<Row>;
|
|
87
|
+
tiers(levels: readonly string[], tierKey: keyof Row & string, imageColumns: readonly (keyof Row & string)[], o?: Partial<Omit<D<Row, "tiers">, "type" | "levels" | "tierKey" | "imageColumns">>): TableBuilder<Row>;
|
|
88
|
+
font(family: string, o?: Partial<Omit<D<Row, "font">, "type" | "family">>): TableBuilder<Row>;
|
|
89
|
+
build(): TableSpec<Row>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Start a table spec for rows of type `Row`: chain `.columns(...)`, decorations and `.theme(...)`, then `.build()`.
|
|
93
|
+
* The spec is plain data: render it with `renderHTML` (`@sportsdataverse/sdvtables/html`).
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* import { defineTable } from "@sportsdataverse/sdvtables";
|
|
98
|
+
* import { renderHTML } from "@sportsdataverse/sdvtables/html";
|
|
99
|
+
*
|
|
100
|
+
* const rows = [
|
|
101
|
+
* { team: "KC", wins: 15, losses: 2 },
|
|
102
|
+
* { team: "BUF", wins: 13, losses: 4 },
|
|
103
|
+
* { team: "LAC", wins: 11, losses: 6 },
|
|
104
|
+
* ];
|
|
105
|
+
* const spec = defineTable<(typeof rows)[number]>()
|
|
106
|
+
* .columns((c) => [c.text("team"), c.int("wins"), c.int("losses")])
|
|
107
|
+
* .title("AFC, 2024")
|
|
108
|
+
* .build();
|
|
109
|
+
* renderHTML(spec, rows);
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function defineTable<Row>(): TableBuilder<Row>;
|
|
113
|
+
|
|
114
|
+
declare function matches<Row>(p: Predicate<Row>, row: Row): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* The indices into `rows` that `sel` picks. A predicate tests each row; an index array names positions in `source`
|
|
117
|
+
* (default `rows`), matched to `rows` by identity. An interactive render passes the table's source rows, so `[5]`
|
|
118
|
+
* stays the sixth data row whatever page, filter or sort shows it (A49). Throws `TableSpecError` for an index outside `source`.
|
|
119
|
+
*/
|
|
120
|
+
declare function selectRows<Row>(sel: RowSelector<Row>, rows: readonly Row[], source?: readonly Row[]): number[];
|
|
121
|
+
|
|
122
|
+
declare function snakeAlign<Row>(rows: readonly Row[], o?: {
|
|
123
|
+
nCols?: number;
|
|
124
|
+
rowsPerCol?: number;
|
|
125
|
+
fill?: Row | null;
|
|
126
|
+
}): (Row | null)[][];
|
|
127
|
+
|
|
128
|
+
declare const THEMES: Readonly<Record<string, ThemeDef>>;
|
|
129
|
+
declare const THEME_NAMES: readonly string[];
|
|
130
|
+
declare function resolveTheme(ref: ThemeRef): Theme;
|
|
131
|
+
|
|
132
|
+
/** sdvplotR .theme_secondary_on() (_marks.py:619-628): fg blended toward bg as far as still clears 4.5:1 (weights 0.45 + i*0.05, unrounded). */
|
|
133
|
+
declare function secondaryOn(bg: string, fg: string, target?: number): string;
|
|
134
|
+
|
|
135
|
+
/** One sdvplotR/gtUtils name and where it lives in sdvtables. */
|
|
136
|
+
interface Alias {
|
|
137
|
+
readonly target: string;
|
|
138
|
+
readonly status: "ported" | "phase-5" | "not-ported";
|
|
139
|
+
readonly note?: string;
|
|
140
|
+
}
|
|
141
|
+
/** sdvplotR/gtUtils function name → sdvtables equivalent. */
|
|
142
|
+
declare const GT_ALIASES: Readonly<Record<string, Alias>>;
|
|
143
|
+
/** Look up the sdvtables equivalent of an sdvplotR/gtUtils function name. */
|
|
144
|
+
declare const aliasFor: (name: string) => Alias | undefined;
|
|
145
|
+
/** The five-colour midnight palette (same values as sdvplotR `pal_midnight()`). */
|
|
146
|
+
declare const PAL_MIDNIGHT: readonly string[];
|
|
147
|
+
|
|
148
|
+
/** The package version, injected from package.json at build time. */
|
|
149
|
+
declare const VERSION: string;
|
|
150
|
+
|
|
151
|
+
export { type Alias, ColumnBase, type ColumnFactory, ColumnSpec, Decoration, Density, GT_ALIASES, NumericKey, PAL_MIDNIGHT, Predicate, RANK_PALETTE, RowSelector, THEMES, THEME_NAMES, TableBuilder, TableSpec, TableSpecError, Theme, ThemeDef, ThemeRef, VERSION, aliasFor, columnFactory, defineTable, matches, resolveTheme, secondaryOn, selectRows, snakeAlign };
|