flexdesk 0.6.1 → 0.6.2
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 +44 -0
- package/css/base.css +43 -0
- package/css/flexdesk.css +43 -0
- package/dist/charts.js +2 -2
- package/dist/{chunk-IYV5JVYB.js → chunk-CPYBQN3Q.js} +273 -3
- package/dist/chunk-CPYBQN3Q.js.map +7 -0
- package/dist/{chunk-ZMCRDOCF.js → chunk-XYUZF5CD.js} +2 -2
- package/dist/flexdesk.css +43 -0
- package/dist/flow.js +1 -1
- package/dist/tiles.js +2 -2
- package/dist/widgets.js +8 -2
- package/dist/widgets.js.map +1 -1
- package/package.json +1 -1
- package/src/ui/components/data_table.js +335 -3
- package/dist/chunk-IYV5JVYB.js.map +0 -7
- /package/dist/{chunk-ZMCRDOCF.js.map → chunk-XYUZF5CD.js.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/ui/utils/raf_resize_observer.js", "../src/ui/components/table_values.js", "../src/ui/components/data_table.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * rAF-coalesced ResizeObserver.\n *\n * Running layout-mutating work \u2014 `Plotly.Plots.resize()`, Monaco's\n * `editor.layout()`, a canvas resize, or a re-render \u2014 *synchronously* inside a\n * ResizeObserver callback makes the engine emit the (spec-defined, benign but\n * console-error-level) \"ResizeObserver loop completed with undelivered\n * notifications\" warning: the callback mutates layout, which produces more\n * resize notifications it can't deliver in the same dispatch.\n *\n * Deferring the work to the next animation frame is the root-cause fix \u2014 the\n * engine delivers all pending notifications first, so there's nothing left\n * \"undelivered\" \u2014 and coalescing collapses a burst of resize events into a\n * single render.\n *\n * @param {(entries: ResizeObserverEntry[]) => void} callback\n * @returns {ResizeObserver}\n */\nexport function createRafResizeObserver(callback) {\n let scheduled = false;\n let latestEntries = [];\n return new ResizeObserver((entries) => {\n latestEntries = entries;\n if (scheduled) return;\n scheduled = true;\n requestAnimationFrame(() => {\n scheduled = false;\n callback(latestEntries);\n });\n });\n}\n", "/**\n * table_values.js \u2014 the REAL VALUE behind a date, a timestamp or a duration\n * cell, and the words a reader sees for it.\n *\n * A list that hands DataTable already-formatted text sorts that text: \"10/5/2026\"\n * before \"9/30/2026\", \"3.2 s\" before \"850 ms\", \"5 Oct\" before \"30 Sep\". The\n * cure is to hand the table the VALUE (an ISO string, a `Date`, epoch\n * milliseconds, a duration in milliseconds) and let it format for the eye while\n * it sorts and filters by the value. That is what a column typed `date`,\n * `datetime` or `duration` does (0.5.0), and these are the functions it uses.\n *\n * They are exported (through `data_table.js`) so a consumer that draws a value\n * somewhere else \u2014 a detail pane, a tooltip \u2014 writes the same words the table\n * writes, rather than an eighth private formatter.\n *\n * \u2550\u2550 THE DEFAULT IS ISO \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * `YYYY-MM-DD` for a date and `YYYY-MM-DD HH:mm` for a timestamp. It sorts as\n * text, it reads the same in every locale, and it is what the product owner of\n * the first consumer asked for: *\"Flexdesk default should be the ISO date\"*. A\n * consumer that wants something else passes a pattern (below) or a function.\n *\n * \u2550\u2550 PATTERNS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * YYYY 2026 YY 26 MMMM October MMM Oct MM 10 M 10\n * DD 05 D 5 dddd Monday ddd Mon\n * HH 14 H 14 hh 02 h 2 mm 05 m 5\n * ss 09 s 9 SSS 042 A PM a pm\n * [literal] anything in square brackets is copied verbatim\n *\n * Month and weekday NAMES are English. A consumer that needs another language\n * passes a function, which can use `Intl.DateTimeFormat` with whatever locale it\n * likes; this module has no locale data and wants none.\n *\n * \u2550\u2550 TIME ZONES \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * A value WITH a zone (`\u2026Z`, `\u2026+02:00`, a `Date`, epoch ms) is an instant, and\n * it is drawn in the reader's local zone unless `utc` is asked for. A value\n * WITHOUT one (`2026-10-05`, `2026-10-05 14:30`) is a wall-clock reading, and\n * it is taken in the zone it will be drawn in \u2014 so `2026-10-05` is drawn as\n * `2026-10-05` everywhere. (`Date.parse('2026-10-05')` reads it as UTC\n * midnight, which west of Greenwich is the evening of the 4th: a calendar date\n * that moves a day depending on where it is read.)\n *\n * \u2550\u2550 WHAT IS READ AS A DATE: ISO 8601, A `Date`, EPOCH MS \u2014 NOTHING ELSE \u2550\u2550\n *\n * Text that is not ISO 8601 is NOT handed to `Date.parse`. Its other forms are\n * implementation-defined, and V8's reads almost anything: `'2'`, `'12'`,\n * `'1/2'` and `'5 Oct'` are all dates in 2001 there. A cell holding `'12'` was\n * drawn `2001-12-01`, and a date filter being typed \u2014 `2`, `20`, `202`,\n * `2026-` \u2014 emptied the table at every other keystroke, because each half was\n * read as an instant nothing equalled. So: an ISO string, a `Date` or a\n * number, or it is text \u2014 drawn as it came, sorted last, and matched by a\n * filter's words. An impossible calendar date (`2026-02-31`) is text too, not\n * the 3rd of March it would roll over to.\n */\n\nconst MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July',\n 'August', 'September', 'October', 'November', 'December'];\nconst WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday',\n 'Friday', 'Saturday'];\n\n/** The ISO default for a `date` column. */\nexport const ISO_DATE = 'YYYY-MM-DD';\n/** The ISO default for a `datetime` column. */\nexport const ISO_DATETIME = 'YYYY-MM-DD HH:mm';\n\n// An ISO 8601 date, optionally with a time (`T` or a space) and a zone.\nconst ISO_RE = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ](\\d{2}):(\\d{2})(?::(\\d{2})(?:[.,](\\d{1,9}))?)?)?\\s*(Z|[+-]\\d{2}(?::?\\d{2})?)?$/i;\n\nconst pad = (n, w = 2) => String(Math.trunc(Math.abs(n))).padStart(w, '0');\n\n/** Days in a month (0-based), proleptic Gregorian \u2014 as `Date` counts them. */\nfunction daysInMonth(y, mo) {\n if (mo !== 1) return [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][mo];\n return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28;\n}\n\n/**\n * Epoch ms for calendar parts (month 0-based), in UTC or the local zone. Not\n * `new Date(y, \u2026)` or `Date.UTC(y, \u2026)`: both read a year below 100 as 19xx, so\n * `0001-01-01` \u2014 a common \"no date\" sentinel \u2014 would be drawn `1901-01-01`.\n * Parts past their range roll over, which is what a period's END wants; a\n * VALUE is checked before it gets here.\n */\nfunction partsToTime(utc, y, mo, d = 1, h = 0, mi = 0, s = 0, ms = 0) {\n const date = new Date(0);\n if (utc) {\n date.setUTCFullYear(y, mo, d);\n date.setUTCHours(h, mi, s, ms);\n } else {\n date.setFullYear(y, mo, d);\n date.setHours(h, mi, s, ms);\n }\n return date.getTime();\n}\n\n/**\n * Epoch milliseconds for a date-like value, or `NaN` when it is not one.\n *\n * @param {Date|number|string|null|undefined} value a `Date`, epoch ms, or an\n * ISO 8601 string. Any other text is `NaN` \u2014 see \"What is read as a date\"\n * in the header \u2014 and so is a calendar date that does not exist\n * (`2026-02-31`, `2026-02-29`).\n * @param {{utc?: boolean}} [o] read a zone-less string as UTC rather than local\n * @returns {number}\n */\nexport function parseDateValue(value, { utc = false } = {}) {\n if (value == null || value === '') return NaN;\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'number') return Number.isFinite(value) ? value : NaN;\n const text = String(value).trim();\n if (!text) return NaN;\n const m = ISO_RE.exec(text);\n if (!m) return NaN;\n const y = Number(m[1]);\n const mo = Number(m[2]);\n const d = Number(m[3]);\n if (mo < 1 || mo > 12 || d < 1 || d > daysInMonth(y, mo - 1)) return NaN;\n const h = m[4] ? Number(m[4]) : 0;\n const mi = m[5] ? Number(m[5]) : 0;\n const s = m[6] ? Number(m[6]) : 0;\n const ms = m[7] ? Math.round(Number(`0.${m[7]}`) * 1000) : 0;\n // 24:00 is the end of the day (ISO 8601); 24:01 is nothing. A leap second\n // (:60) is the next minute's first.\n if (h > 24 || mi > 59 || s > 60 || (h === 24 && (mi || s || ms))) return NaN;\n const zone = m[8];\n if (zone) {\n let offset = 0;\n if (zone.toUpperCase() !== 'Z') {\n const sign = zone[0] === '-' ? -1 : 1;\n const digits = zone.slice(1).replace(':', '');\n offset = sign * (Number(digits.slice(0, 2)) * 60 + Number(digits.slice(2, 4) || 0));\n }\n return partsToTime(true, y, mo - 1, d, h, mi, s, ms) - offset * 60000;\n }\n return partsToTime(utc, y, mo - 1, d, h, mi, s, ms);\n}\n\n/**\n * Draw a date-like value with a pattern (see the header). An unreadable value\n * is drawn AS IT CAME rather than as nothing: a blank cell would hide that the\n * data held something unexpected.\n *\n * @param {Date|number|string|null|undefined} value\n * @param {string|Function} [pattern='YYYY-MM-DD'] a pattern, or\n * `(date: Date) => string`\n * @param {{utc?: boolean}} [o] draw in UTC rather than the local zone\n * @returns {string}\n */\nexport function formatDate(value, pattern = ISO_DATE, { utc = false } = {}) {\n if (value == null || value === '') return '';\n const t = parseDateValue(value, { utc });\n if (!Number.isFinite(t)) return String(value);\n const date = new Date(t);\n if (typeof pattern === 'function') return String(pattern(date) ?? '');\n const get = utc\n ? {\n y: date.getUTCFullYear(), mo: date.getUTCMonth(), d: date.getUTCDate(),\n wd: date.getUTCDay(), h: date.getUTCHours(), mi: date.getUTCMinutes(),\n s: date.getUTCSeconds(), ms: date.getUTCMilliseconds(),\n }\n : {\n y: date.getFullYear(), mo: date.getMonth(), d: date.getDate(),\n wd: date.getDay(), h: date.getHours(), mi: date.getMinutes(),\n s: date.getSeconds(), ms: date.getMilliseconds(),\n };\n const h12 = get.h % 12 === 0 ? 12 : get.h % 12;\n return String(pattern || ISO_DATE).replace(\n /\\[([^\\]]*)\\]|YYYY|YY|MMMM|MMM|MM|M|dddd|ddd|DD|D|HH|H|hh|h|mm|m|ss|s|SSS|A|a/g,\n (tok, literal) => {\n if (literal !== undefined) return literal;\n switch (tok) {\n case 'YYYY': return pad(get.y, 4);\n case 'YY': return pad(get.y % 100);\n case 'MMMM': return MONTHS[get.mo];\n case 'MMM': return MONTHS[get.mo].slice(0, 3);\n case 'MM': return pad(get.mo + 1);\n case 'M': return String(get.mo + 1);\n case 'dddd': return WEEKDAYS[get.wd];\n case 'ddd': return WEEKDAYS[get.wd].slice(0, 3);\n case 'DD': return pad(get.d);\n case 'D': return String(get.d);\n case 'HH': return pad(get.h);\n case 'H': return String(get.h);\n case 'hh': return pad(h12);\n case 'h': return String(h12);\n case 'mm': return pad(get.mi);\n case 'm': return String(get.mi);\n case 'ss': return pad(get.s);\n case 's': return String(get.s);\n case 'SSS': return pad(get.ms, 3);\n case 'A': return get.h < 12 ? 'AM' : 'PM';\n case 'a': return get.h < 12 ? 'am' : 'pm';\n default: return tok;\n }\n });\n}\n\n/**\n * The PERIOD an ISO prefix names, as `[start, end)` in epoch ms \u2014 `2026` is the\n * year, `2026-10` the month, `2026-10-05` the day, `2026-10-05 14` the hour,\n * `2026-10-05 14:30` the minute \u2014 ISO's own two-digit parts, nothing looser. A\n * full ISO instant (with a zone, say) is the one millisecond it names. `null`\n * for anything else: half typed (`2`, `202`, `2026-`, `2026-1`), a date that\n * does not exist (`2026-02-31`), or words (`5 Oct`). That is how a half-typed\n * operand (`>20`) filters nothing yet, and how text with no operator falls\n * through to the drawn words (`matchDateFilter`).\n *\n * @param {string} text\n * @param {{utc?: boolean}} [o]\n * @returns {{start: number, end: number}|null}\n */\nexport function parseDatePeriod(text, { utc = false } = {}) {\n const t = String(text ?? '').trim();\n const m = /^(\\d{4})(?:-(\\d{2})(?:-(\\d{2})(?:[T ](\\d{2})(?::(\\d{2})(?::(\\d{2}))?)?)?)?)?$/i.exec(t);\n if (m) {\n const parts = [Number(m[1]),\n m[2] ? Number(m[2]) - 1 : 0,\n m[3] ? Number(m[3]) : 1,\n m[4] ? Number(m[4]) : 0,\n m[5] ? Number(m[5]) : 0,\n m[6] ? Number(m[6]) : 0];\n if (parts[1] < 0 || parts[1] > 11 || parts[2] < 1 || parts[2] > daysInMonth(parts[0], parts[1])\n || parts[3] > 23 || parts[4] > 59 || parts[5] > 59) return null;\n // The least significant part that was GIVEN is the one the period spans.\n const unit = m[6] ? 5 : m[5] ? 4 : m[4] ? 3 : m[3] ? 2 : m[2] ? 1 : 0;\n const next = parts.slice();\n next[unit] += 1;\n return { start: partsToTime(utc, ...parts), end: partsToTime(utc, ...next) };\n }\n // Not a prefix: a full ISO instant or nothing (`parseDateValue` reads no\n // other text).\n const instant = parseDateValue(t, { utc });\n return Number.isFinite(instant) ? { start: instant, end: instant + 1 } : null;\n}\n\nconst DURATION_UNITS = {\n ms: 1, msec: 1, msecs: 1, millisecond: 1, milliseconds: 1,\n s: 1000, sec: 1000, secs: 1000, second: 1000, seconds: 1000,\n m: 60000, min: 60000, mins: 60000, minute: 60000, minutes: 60000,\n h: 3600000, hr: 3600000, hrs: 3600000, hour: 3600000, hours: 3600000,\n d: 86400000, day: 86400000, days: 86400000,\n};\n\n/**\n * Milliseconds for a duration: a number (taken as ms), or text \u2014 `850 ms`,\n * `3.2 s`, `2m 5s`, `1h 30m`, `2 days`, or a clock `1:02:05` (`h:mm:ss`, with\n * an optional `d.` in front). `NaN` when it is none of those.\n *\n * @param {number|string|null|undefined} value\n * @returns {number}\n */\nexport function parseDuration(value) {\n if (value == null || value === '') return NaN;\n if (typeof value === 'number') return Number.isFinite(value) ? value : NaN;\n let text = String(value).trim().toLowerCase();\n if (!text) return NaN;\n let sign = 1;\n if (text[0] === '-') { sign = -1; text = text.slice(1).trim(); }\n if (/^\\d+(?:\\.\\d+)?$/.test(text)) return sign * Number(text);\n const clock = /^(?:(\\d+)\\.)?(\\d+):(\\d{1,2})(?::(\\d{1,2}(?:\\.\\d+)?))?$/.exec(text);\n if (clock) {\n const [, d, a, b, c] = clock;\n // h:mm:ss, or h:mm when there is no third part.\n const ms = (Number(d || 0) * 86400 + Number(a) * 3600 + Number(b) * 60\n + Number(c || 0)) * 1000;\n return sign * ms;\n }\n const re = /(\\d+(?:\\.\\d+)?)\\s*([a-z]+)\\s*/g;\n let total = 0;\n let consumed = 0;\n let m;\n while ((m = re.exec(text)) !== null) {\n if (m.index !== consumed) return NaN;\n const unit = DURATION_UNITS[m[2]];\n if (unit === undefined) return NaN;\n total += Number(m[1]) * unit;\n consumed = re.lastIndex;\n }\n return consumed === text.length && consumed > 0 ? sign * total : NaN;\n}\n\n/**\n * Draw a duration in milliseconds.\n *\n * 'auto' (default) `850 ms`, `3.2 s`, `2m 5s`, `1h 2m`, `3d 4h` \u2014 the two\n * largest units that matter, which is what a list of run times or\n * query times wants\n * 'clock' `0:00:03`, `1:02:05`, `2.04:00:00` (`d.h:mm:ss`)\n * a function `(ms) => string`\n *\n * Text that is not a duration is drawn as it came, like `formatDate`.\n *\n * @param {number|string|null|undefined} value\n * @param {'auto'|'clock'|Function} [pattern='auto']\n * @returns {string}\n */\nexport function formatDuration(value, pattern = 'auto') {\n if (value == null || value === '') return '';\n const ms = parseDuration(value);\n if (!Number.isFinite(ms)) return String(value);\n if (typeof pattern === 'function') return String(pattern(ms) ?? '');\n const neg = ms < 0;\n const a = Math.abs(ms);\n let out;\n if (pattern === 'clock') {\n const total = Math.round(a / 1000);\n const d = Math.floor(total / 86400);\n const h = Math.floor((total % 86400) / 3600);\n const mi = Math.floor((total % 3600) / 60);\n const s = total % 60;\n out = `${d ? `${d}.${pad(h)}` : h}:${pad(mi)}:${pad(s)}`;\n } else if (a < 1000) {\n out = `${Math.round(a)} ms`;\n } else if (a < 59950) {\n out = `${(a / 1000).toFixed(1)} s`;\n } else if (a < 3600000) {\n let mi = Math.floor(a / 60000);\n let s = Math.round((a % 60000) / 1000);\n if (s === 60) { mi += 1; s = 0; }\n out = `${mi}m ${s}s`;\n } else if (a < 86400000) {\n let h = Math.floor(a / 3600000);\n let mi = Math.round((a % 3600000) / 60000);\n if (mi === 60) { h += 1; mi = 0; }\n out = `${h}h ${mi}m`;\n } else {\n let d = Math.floor(a / 86400000);\n let h = Math.round((a % 86400000) / 3600000);\n if (h === 24) { d += 1; h = 0; }\n out = `${d}d ${h}h`;\n }\n return neg ? `-${out}` : out;\n}\n\n/**\n * Does a time `t` (epoch ms) pass a date filter's text?\n *\n * >2026-10 after October 2026 >=2026-10 from the 1st of October\n * <2026-10-05 before the 5th <=2026-10-05 up to the end of the 5th\n * =2026-10 in October !=2026-10 not in October\n * 2026-01..2026-03 January to the end of March\n * 2026-10 (no operator) in October\n *\n * An operand that is not a date yet (`>20`, half typed) filters nothing. Text\n * with no operator that names no period is matched against the cell's DRAWN\n * words, so `Oct` finds October under an `MMM` pattern, `5 Oct` the 5th under\n * `D MMM YYYY`, and `2026-1` (on the way to `2026-10`) whatever is drawn with\n * it under the ISO default.\n *\n * @param {number} t the cell's time, or NaN\n * @param {string} filterText\n * @param {string} shown the cell as drawn\n * @param {{utc?: boolean}} [o]\n * @returns {boolean}\n */\nexport function matchDateFilter(t, filterText, shown, { utc = false } = {}) {\n const text = String(filterText ?? '').trim();\n if (!text) return true;\n const range = /^(.+?)\\s*\\.\\.\\s*(.+)$/.exec(text);\n if (range) {\n const lo = parseDatePeriod(range[1], { utc });\n const hi = parseDatePeriod(range[2], { utc });\n if (!lo || !hi) return true;\n return Number.isFinite(t) && t >= lo.start && t < hi.end;\n }\n const op = /^(>=|<=|!=|>|<|=)\\s*(.+)$/.exec(text);\n if (op) {\n const p = parseDatePeriod(op[2], { utc });\n if (!p) return true;\n if (!Number.isFinite(t)) return false;\n switch (op[1]) {\n case '>': return t >= p.end;\n case '>=': return t >= p.start;\n case '<': return t < p.start;\n case '<=': return t < p.end;\n case '=': return t >= p.start && t < p.end;\n case '!=': return !(t >= p.start && t < p.end);\n }\n }\n const p = parseDatePeriod(text, { utc });\n if (p) return Number.isFinite(t) && t >= p.start && t < p.end;\n return String(shown ?? '').toLowerCase().includes(text.toLowerCase());\n}\n\n/**\n * Does a duration `ms` pass a duration filter's text? The operators are the\n * numeric ones, and an operand carries its unit (`>1s`, `<500ms`, `2m..5m`); a\n * bare number is milliseconds. Text with no operator is matched against the\n * cell's drawn words.\n *\n * @param {number} ms\n * @param {string} filterText\n * @param {string} shown\n * @returns {boolean}\n */\nexport function matchDurationFilter(ms, filterText, shown) {\n const text = String(filterText ?? '').trim();\n if (!text) return true;\n const range = /^(.+?)\\s*\\.\\.\\s*(.+)$/.exec(text);\n if (range) {\n const lo = parseDuration(range[1]);\n const hi = parseDuration(range[2]);\n if (!Number.isFinite(lo) || !Number.isFinite(hi)) return true;\n return Number.isFinite(ms) && ms >= lo && ms <= hi;\n }\n const op = /^(>=|<=|!=|>|<|=)\\s*(.+)$/.exec(text);\n if (op) {\n const target = parseDuration(op[2]);\n if (!Number.isFinite(target)) return true;\n if (!Number.isFinite(ms)) return false;\n switch (op[1]) {\n case '>': return ms > target;\n case '>=': return ms >= target;\n case '<': return ms < target;\n case '<=': return ms <= target;\n case '=': return ms === target;\n case '!=': return ms !== target;\n }\n }\n return String(shown ?? '').toLowerCase().includes(text.toLowerCase());\n}\n", "/**\n * data_table.js\n *\n * Unified, reusable data table component with support for:\n * - Pagination (first/prev/next/last/jump to row)\n * - Row selection (single, range with Shift, toggle with Ctrl/Cmd)\n * - Keyboard shortcuts (Ctrl+A, Ctrl+C, Shift+Ctrl+C, Esc)\n * - Context menu (copy as TSV/CSV)\n * - Column sorting (internal or external via callback)\n * - Column drag-to-resize, and double-click-to-auto-size on the same grip\n * - Per-column filtering (numeric operators, text substring)\n * - Column type detection (numeric/text alignment)\n * - Header icons\n * - Read-only mode\n * - CSV download through the host port (native save dialog), with a\n * Blob + <a download> fallback when no host is supplied\n *\n * Used by: DataPage, PlotPopoutWindow, StatisticsTable, Import Wizard\n */\n\nimport { createRafResizeObserver } from '../utils/raf_resize_observer.js';\nimport {\n ISO_DATE, ISO_DATETIME, formatDate, formatDuration, matchDateFilter,\n matchDurationFilter, parseDateValue, parseDuration,\n} from './table_values.js';\nimport { isRowActivation, isRowControl } from './row_activation.js';\n\n// 0.5.0: the value helpers a typed column uses, and the one row-activation rule,\n// re-exported so a consumer reaches them where it reaches DataTable.\nexport {\n ISO_DATE, ISO_DATETIME, formatDate, formatDuration, parseDateValue,\n parseDatePeriod, parseDuration, matchDateFilter, matchDurationFilter,\n} from './table_values.js';\nexport {\n ROW_CONTROL_SELECTOR, endsTextSelection, isRowActivation, isRowControl,\n} from './row_activation.js';\n\nconst DEFAULT_PAGE_SIZE = 100;\n\n/** 0.6.1 \u2014 the row statuses `diff` draws. */\nconst DIFF_STATUSES = new Set(['added', 'removed', 'changed', 'same', 'gap']);\n\n// \u2500\u2500 `paging`: a server's rows, in pages or as one scrolling list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// THE TWO LIMITS. A table that scrolls holds every row it has loaded, in one\n// array and (through `virtualize`) one scroll range, so how many rows it may\n// hold is a decision rather than an accident of how far somebody scrolled.\n// The SOFT limit is the consumer's (a person's preference, say): a source\n// with more rows than that is shown in pages, whatever was asked for. The HARD\n// limit is the ceiling no soft limit may exceed, and no scrolling table ever\n// holds more rows than it.\n\n/** The most rows a scrolling table holds, and the ceiling of every soft limit. */\nexport const PAGING_HARD_LIMIT = 100_000;\n/** The soft limit when the consumer names none. */\nexport const PAGING_SOFT_LIMIT = 10_000;\n\n/**\n * WHICH WAY A TABLE IS SHOWN \u2014 pure, so a consumer deciding how to FETCH and\n * the table deciding how to DRAW get the same answer from the same facts.\n *\n * Scroll is allowed only while the source is known to hold no more rows than\n * the soft limit. What is known is the exact `total` when there is one, and\n * otherwise the most the facts prove: a lower bound (`atLeast`, a capped\n * count) or the rows already held plus one when the source says it has more.\n * An unknown total therefore does not force pages until the rows themselves\n * prove the source is larger than the limit.\n *\n * @param {object} [o]\n * @param {'pages'|'scroll'} [o.mode='scroll'] what was asked for\n * @param {number|null} [o.total] the source's exact row count, if known\n * @param {number} [o.atLeast=0] a lower bound on it (a capped count)\n * @param {number} [o.held=0] rows the table holds now\n * @param {boolean} [o.hasMore=false] the source has rows past those held\n * @param {number} [o.softLimit=PAGING_SOFT_LIMIT]\n * @param {number} [o.hardLimit=PAGING_HARD_LIMIT]\n * @returns {{mode: 'pages'|'scroll', requested: 'pages'|'scroll', forced: boolean,\n * softLimit: number, hardLimit: number, known: number, exact: boolean}}\n */\nexport function resolvePaging({\n mode = 'scroll', total = null, atLeast = 0, held = 0, hasMore = false,\n softLimit = PAGING_SOFT_LIMIT, hardLimit = PAGING_HARD_LIMIT,\n} = {}) {\n const requested = mode === 'pages' ? 'pages' : 'scroll';\n const hard = Number.isFinite(hardLimit) && hardLimit >= 1\n ? Math.floor(hardLimit) : PAGING_HARD_LIMIT;\n // A soft limit above the hard one is the hard one: nothing the consumer\n // names can let a table hold more than the ceiling.\n const soft = Math.min(hard, Number.isFinite(softLimit) && softLimit >= 1\n ? Math.floor(softLimit) : PAGING_SOFT_LIMIT);\n const exact = Number.isFinite(total) && total >= 0;\n const known = exact ? total\n : Math.max(Number.isFinite(atLeast) ? atLeast : 0, (held || 0) + (hasMore ? 1 : 0));\n const forced = requested === 'scroll' && known > soft;\n return {\n mode: forced ? 'pages' : requested, requested, forced,\n softLimit: soft, hardLimit: hard, known, exact,\n };\n}\n\n/** How near the bottom (px) a scrolling table asks for its next rows. */\nconst PAGING_LOAD_MORE_PX = 400;\n\n/** 0.5.0 \u2014 the column types that sort and filter by a value rather than by\n * the text drawn for it. */\nconst TYPED_COLUMNS = new Set(['date', 'datetime', 'duration']);\n\n/** 0.5.0. The clicks with which a `selectable: 'single'` table took its row\n * back OFF the selection (Ctrl on the chosen row). `onRowActivate` does not\n * open a row on such a click. Marked on the EVENT, not read back from the\n * selection, because a selection callback that re-draws with new rows clears\n * the selection before the activation listener runs. */\nconst DESELECTING_CLICKS = new WeakSet();\n\n// \u2500\u2500 0.5.0 `autoDispose` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// ONE MutationObserver per document, shared by every table that asked, rather\n// than one per table: a page with forty lists would otherwise run forty\n// callbacks on every mutation anywhere in it. Each callback asks each table one\n// question (`isConnected`), and the observer disconnects itself when the last\n// table is gone.\n//\n// The tables are held WEAKLY. A table rendered into a host that never reaches\n// the page is never \"taken out\" of it, so it is never disposed \u2014 and a strong\n// set here would then keep it, its rows and its DOM alive for the life of the\n// page: the very leak the option exists to stop.\nconst AUTO_DISPOSE = new Map(); // Document -> { observer, tables: Set<{deref()}> }\nconst AUTO_REFS = new WeakMap(); // DataTable -> its entry in that set\nconst weakRef = (table) => (typeof WeakRef === 'function'\n ? new WeakRef(table) : { deref: () => table });\n\nfunction autoDisposeSweep(entry) {\n for (const ref of entry.tables) {\n const table = ref.deref();\n if (!table) { entry.tables.delete(ref); continue; }\n const el = table._wrapperEl;\n if (!el) continue;\n if (el.isConnected) { table._autoSeen = true; continue; }\n if (!table._autoSeen || table._autoPending) continue;\n // NOT AT ONCE. A renderer that takes a subtree out and puts it back in\n // the same task (FlexDesk's own tile renderer re-appends every leaf in\n // tree order) has put it back by the time this microtask runs \u2014 and one\n // that takes a turn longer still gets one task's grace. Only a table\n // that is STILL out after that has been removed from the page.\n table._autoPending = true;\n setTimeout(() => {\n table._autoPending = false;\n if (!entry.tables.has(ref)) return;\n const now = table._wrapperEl;\n // `_disposeOwn`, NOT `dispose()`: by now the host may hold\n // something else \u2014 the next list mounted into it, or the pane's\n // own message \u2014 and `dispose()` empties the host.\n if (now && !now.isConnected) table._disposeOwn();\n }, 0);\n }\n if (entry.tables.size === 0) autoDisposeRelease(entry);\n}\n\nfunction autoDisposeRelease(entry) {\n for (const [doc, e] of AUTO_DISPOSE) {\n if (e !== entry) continue;\n try { e.observer.disconnect(); } catch (_) { /* gone */ }\n AUTO_DISPOSE.delete(doc);\n }\n}\n\nfunction autoDisposeWatch(table) {\n const doc = table.container?.ownerDocument;\n const MO = doc?.defaultView?.MutationObserver || globalThis.MutationObserver;\n if (!doc || typeof MO !== 'function') return;\n let entry = AUTO_DISPOSE.get(doc);\n if (!entry) {\n entry = { observer: null, tables: new Set() };\n entry.observer = new MO(() => autoDisposeSweep(entry));\n entry.observer.observe(doc, { childList: true, subtree: true });\n AUTO_DISPOSE.set(doc, entry);\n }\n let ref = AUTO_REFS.get(table);\n if (!ref) { ref = weakRef(table); AUTO_REFS.set(table, ref); }\n entry.tables.add(ref);\n if (table._wrapperEl?.isConnected) table._autoSeen = true;\n}\n\nfunction autoDisposeUnwatch(table) {\n const ref = AUTO_REFS.get(table);\n if (!ref) return;\n for (const entry of [...AUTO_DISPOSE.values()]) {\n if (entry.tables.delete(ref) && entry.tables.size === 0) autoDisposeRelease(entry);\n }\n}\n\n/** A per-column option: one value for every column, or an array / object\n * keyed by column index. `null` and `undefined` mean \"not set\". */\nfunction perColumn(option, colIdx) {\n if (option == null) return null;\n if (Array.isArray(option)) return option[colIdx] ?? null;\n if (typeof option === 'object') return option[colIdx] ?? null;\n return option;\n}\n\n/** One sort key, comparable with `compareSortKeys`. */\nfunction normaliseSortKey(k) {\n if (k == null) return null;\n if (k instanceof Date) k = k.getTime();\n if (typeof k === 'boolean') return k ? 1 : 0;\n if (typeof k === 'number') return Number.isFinite(k) ? k : null;\n if (typeof k === 'bigint') return Number(k);\n return String(k).toLowerCase();\n}\n\n/** Nulls (and NaN) last in either direction \u2014 as the 0.4 comparator put them \u2014\n * numbers before text, numbers numerically, text as lower-cased text. */\nfunction compareSortKeys(a, b, asc) {\n if (a === null && b === null) return 0;\n if (a === null) return 1;\n if (b === null) return -1;\n const na = typeof a === 'number';\n const nb = typeof b === 'number';\n let cmp;\n if (na !== nb) cmp = na ? -1 : 1;\n else cmp = a < b ? -1 : a > b ? 1 : 0;\n return asc ? cmp : -cmp;\n}\n\n/** How wide auto-sizing a column is allowed to make it.\n *\n * 520px, which is `_fitColumnWidths`' FIRST_CAP \u2014 the most generous ceiling\n * this file already sanctions for a single column. Auto-size is an explicit\n * gesture asking to see a column's content, so it is not held to the tighter\n * 360px the automatic fit pass applies to the columns it is squeezing; but it\n * is held to SOMETHING, because one 4,000-character note in one cell would\n * otherwise produce a column nobody can scroll past. */\nconst AUTOSIZE_MAX_PX = 520;\n\n/**\n * Configuration options for DataTable\n * @typedef {Object} DataTableConfig\n * @property {string[]} headers - Column headers\n * @property {Array<Array>} rows - Row data (array of arrays)\n * @property {number} [pageSize=100] - Rows per page\n * @property {boolean} [pagination=true] - Enable pagination controls\n * @property {boolean|'single'} [selectable=true] - Enable row selection. 'single' (0.5.0): a click selects exactly one row, Shift and Ctrl do not extend it, Ctrl+A selects nothing, and `setSelection` keeps the last index it is given.\n * @property {boolean} [copyable=true] - Enable copy shortcuts and context menu\n * @property {boolean} [sortable=false] - Enable column sorting\n * @property {boolean} [filterable=false] - Enable per-column filter inputs\n * @property {boolean} [readonly=false] - Read-only mode (no selection/hover effects)\n * @property {boolean|'position'} [showRowNumbers=false] - Show row number column. `true` numbers a row by its ORIGINAL index (2, 3, 4, 1 after a sort); 'position' (0.5.0) numbers the rows as SHOWN \u2014 1, 2, 3 after a sort, a filter, or on any page.\n * @property {string} [emptyMessage='No data'] - Message when no data\n * @property {Function} [onSort] - Callback when sort changes: (column, ascending) => void\n * @property {boolean} [resetPageOnSort=false] - A client-paged table goes back to its first page on every `sortBy()` (a header click included), the way a new filter already does: on page 3, a new order otherwise draws rows 201\u2013300 OF THE NEW ORDER under \"Page 3 of 3\", which reads as \"it only sorted this page\". OFF by default: before this key existed a sort kept the page, and a table that does not ask keeps that. Server-side paging is untouched either way \u2014 its page is the consumer's `offset`, which `sortBy` never reads or writes.\n * @property {Function} [onSelectionChange] - Callback when selection changes: (selectedIndices) => void\n * @property {Function} [formatValue] - Custom value formatter: (value, colIndex) => string\n * @property {Function} [getHeaderIcon] - Get icon for header: (header, colIndex) => {icon, title}\n * @property {Function} [getColumnType] - Get column type: (colIndex, rows) => 'num'|'text'. What it returns is the cells' class name, and 'num' also sorts and filters as a number \u2014 exactly as in 0.4. A date, datetime or duration column is declared through `columnTypes` (0.5.0): returned from here, those names are class names only.\n * @property {Object} [services] - App services { eventBus, logger } for notifications\n * @property {number} [totalCount] - Total row count for server-side pagination (when rows only contains current page)\n * @property {number} [offset=0] - Current offset for server-side pagination\n * @property {Function} [onPageChange] - Callback for server-side pagination: (offset, limit) => void\n * @property {Function} [onJumpToRow] - Callback for jump to row: (rowIndex) => void\n * @property {Function} [renderCell] - Custom cell renderer: (td, value, colIdx, rowIdx, row) => boolean (return true if handled)\n * @property {'normal'|'compact'} [mode='normal'] - Rendering density. 'compact' adds `data-table-component--compact` to the wrapper (tighter padding + smaller font for the bottom-panel use case).\n * @property {Function} [onRowClick] - Row click handler: (rowIdx, row, ev) => void. Receives the original (unfiltered) row index.\n * @property {Function} [onRowContextMenu] - Row right-click handler: (rowIdx, row, ev) => void. Fires before the default context menu; call ev.preventDefault() to suppress the default.\n * @property {Function} [onCellContextMenu] - Cell right-click handler: (colIdx, rowIdx, value, td, ev) => void. Fires before onRowContextMenu; same suppression semantics.\n * @property {boolean} [showExportButton=false] - Adds a \"CSV\" download button to the pagination strip that invokes `downloadCSV()`.\n * @property {Object} [host] - A Host (see ui/js/host/host.js). Its `dialogs` capability backs `downloadCSV()`'s native save dialog; without it CSV export falls back to a Blob download.\n * @property {Object} [stateStore] - `{ ready(), get(key), set(key, state) }` \u2014 REQUIRED when `persistKey` is set. Built by `createTableStateStore()`.\n * @property {'container'|'content'} [columnFit='container'] - How the automatic fit pass sizes a column the user has NOT dragged. 'container' squeezes every column into the wrap: a 360px cap, a more generous one for the first column, and water-fill-shrink toward the 40px floor when they do not fit. 'content' sizes each column to its own content through the same `_autoWidth` a grip double-click uses (520px cap) and lets the body scroll sideways rather than squeezing. A pinned column is honoured verbatim under both.\n * @property {boolean|{overscan?: number, rowHeight?: number}} [virtualize=false] - C10. Draw only the rows near the viewport, between a top and a bottom spacer row, and give the body table a `<colgroup>` so its column widths no longer come from whichever row happens to be first. OFF by default: nothing about a table that does not ask changes. `overscan` (rows drawn beyond each edge, default 20) and `rowHeight` (the estimate used until a real row has been measured, default 24) tune it. See `_virtUpdate` for the whole contract.\n * @property {Function} [virtualRowHeight] - `(rowIndex, baseHeight) => number`. Under `virtualize`, the height a row occupies, including anything the embedder injects in front of it (a group header) \u2014 and 0 for a row the embedder hides, which is then not drawn at all. Absent: every row is `baseHeight`, which is measured from a real row.\n * @property {Function} [onRowsRendered] - `({ rows, removed }) => void`. Under `virtualize`, called whenever the window changes after `render()` returned: `rows` are the `<tr>`s the virtualiser ADDED \u2014 the rows an embedder that decorates rows after a render would otherwise never see \u2014 and `removed` the ones it took OUT, already detached (an embedder that injected rows of its own beside them, or holds an editor in one, has to hear that they went). The rows present when `render()` returns are not reported: they are the render's, exactly as without `virtualize`.\n *\n * \u2500\u2500 0.5.0, every one of them off unless asked for \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * @property {boolean} [fitContent=false] - The table is as tall as its rows: the wrapper is `height:auto` instead of `height:100%`, and the body grows with its rows instead of filling the box. For a list in a flowing page, whose parent has no height \u2014 where the default draws a header and NO rows.\n * @property {number|string} [maxHeight] - Implies `fitContent`, and caps the whole table at this height (a number is px); past it the body scrolls under its header.\n * @property {boolean} [autoDispose=false] - Dispose by itself once the table has been taken out of the document (and is still out a task later). Unlike `dispose()`, it removes only the table's own elements and never empties the host, which by then may hold the next list or the pane's own message. Do NOT set it on a table you take out and put back later \u2014 a cached tab \u2014 since a disposed table comes back empty.\n * @property {'time'|'plain'} [firstColumn='time'] - 'plain' draws the first column like every other column: no 120\u2013150px pin, no grey, no weight. The default keeps the time-series styling the component was built around.\n * @property {boolean} [clickable] - Draw body rows as things to press (`twm-dt--clickable`: a pointer and a hover, readonly tables included). Defaults to on exactly when `onRowActivate` is set.\n * @property {Function} [onRowActivate] - `(rowIdx, row, ev) => void`. The row OPENS. Fired after the selection has been updated, on the gestures `activateOn` names, and never on a press on a control inside the row, a click that ends a text selection in the table, the second click of a double-click, or (`selectable: 'single'`) the Ctrl click that took the row off the selection. `ev.type` says which gesture ('click', 'dblclick' or 'keydown'). `rowIdx` is the original index, as for `onRowClick`. A press whose `onSelectionChange` or `onRowClick` re-draws the table still opens the row pressed; `row` is that row as it was drawn.\n * @property {'click'|'dblclick'|'enter'|Array<'click'|'dblclick'|'enter'>} [activateOn='click'] - Which gestures open a row. A list of things to open: 'click'. A pick list, where one click selects: ['dblclick', 'enter']. Enter opens the selected row (the one row selected, or the selection's anchor) \u2014 the row a double-click on it would open; with nothing selected, the active row (`activeRow`).\n * @property {Function} [getRowKey] - `(row, rowIdx) => key`. A row's identity, which `activeRow` is matched by. Compared as text.\n * @property {*} [activeRow] - The key of the row that is OPEN (the master of a master-detail): drawn `twm-dt-row--active` with `aria-current=\"true\"`. It survives `setData`, a sort, a filter and a page, and a right-click does not move it. Without `getRowKey` the key is the row's original index. See `setActiveRow`.\n * @property {Function} [rowClass] - `(row, rowIdx) => string|string[]|null`. Classes for the row's `<tr>`.\n * @property {Function} [rowAttrs] - `(row, rowIdx) => {name: value}`. Attributes for the row's `<tr>` (`null`/`false` leaves one off, `true` sets it empty).\n * @property {Function} [cellClass] - `(value, colIdx, row, rowIdx) => string|string[]|null`. Classes for a cell, after its type class.\n * @property {Function} [diff] - 0.6.1. `(row, rowIdx) => {status, cells?}|null`. One side of a COMPARISON: `status` is 'added', 'removed', 'changed', 'same' or 'gap' and draws the row `twm-dt-diff twm-dt-diff--<status>`; `cells` (an array or Set of column indices) marks the cells that differ `twm-dt-diff__cell--changed`. A 'gap' row is the place a row holds on the OTHER side: its cells are drawn empty, whatever its values and `renderCell`, so two tables drawn from one aligned row list keep their rows level. `null` (or an unknown status) draws the row as without `diff`.\n * @property {object} [scrollLock] - 0.6.1. A group from `createScrollLock()`: the table's body box joins it on every render and leaves it on the next render and on dispose, so tables in the same group scroll as one.\n * @property {Function} [rowIcon] - `(row, rowIdx) => string|{icon, title?, tone?}|null`. A Material Symbols icon at the start of the row's first cell; `tone` adds `twm-dt-row-icon--<tone>`. Drawn by CSS, so it is in neither the cell's text, its tooltip nor a copy.\n * @property {string|Node|Function} [emptyState] - What the box says when there are no rows: text, a node, or a function returning either (called on each render). Replaces `emptyMessage`, and is hidden while `setLoading(true)` \u2014 an empty table that is still loading is not empty.\n * @property {string} [nullDisplay] - Draw `null`/`undefined` as this text (and copy it so), with `twm-dt-cell--null` on the cell, instead of '-'.\n * @property {Array<string|null>} [columnTypes] - Each column's type by position ('num', 'text', 'date', 'datetime', 'duration'); `null` leaves a column to `getColumnType` and detection. Only a type declared HERE makes a column a date, datetime or duration column \u2014 drawn, sorted and filtered by its value; `setData({columnTypes})` applies a new list at once.\n * @property {Function|Object|Array} [sortValue] - `(value, colIdx, row) => comparable` \u2014 what a column sorts by, for every column or (as an object or array keyed by column index) for some. `undefined` falls back to the column's own rule. A `Date` sorts by its time, numbers numerically, text as lower-cased text, `null` last.\n * @property {string|Function|Object|Array} [dateFormat='YYYY-MM-DD'] - How a 'date' column is drawn: a pattern (see `formatDate`) or `(date) => string`, for every date column or per column index.\n * @property {string|Function|Object|Array} [dateTimeFormat='YYYY-MM-DD HH:mm'] - The same for a 'datetime' column.\n * @property {'auto'|'clock'|Function|Object|Array} [durationFormat='auto'] - How a 'duration' column (milliseconds) is drawn: '850 ms', '3.2 s', '2m 5s' (auto) or '0:02:05' (clock).\n * @property {'local'|'UTC'} [dateTimeZone='local'] - The zone typed date columns are read and drawn in.\n *\n * \u2500\u2500 `paging`, off unless asked for \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * @property {Object} [paging] - A server's rows shown IN PAGES or as ONE SCROLLING LIST, and a strip under the body that says which and lets the reader change it. The consumer holds the rows and fetches them; the table decides which way they are shown (`resolvePaging`), asks for more, and draws the strip. Set it and the old pager (`pagination`) is not drawn. Its keys:\n * `mode` ('pages'|'scroll', default 'scroll') \u2014 what was asked for. Scroll is refused, and pages shown, while the source holds more than `softLimit` rows.\n * `pageSize` \u2014 rows per page, and per load while scrolling (default `pageSize`).\n * `softLimit` (default 10,000) and `hardLimit` (default 100,000) \u2014 see `resolvePaging`; the soft one is clamped to the hard one, and a scrolling table never asks for rows past the hard one.\n * `total` \u2014 the source's exact row count, or null. `atLeast` \u2014 a lower bound when the exact count is not known (a capped count). `hasMore` \u2014 the source has rows past those held.\n * `offset` \u2014 in pages, where the first row held stands in the source: the strip's \"Rows 1,001\u20132,000\" and `showRowNumbers: 'position'` read it. The rows' indexes (`__rowIndex`, selection, `onRowClick`) stay those of `rows`.\n * `onPage(offset, limit)` \u2014 pages: show the page at `offset`. `onLoadMore()` \u2014 scroll: called when the body is scrolled within 400px of its end (`loadMorePx`), or does not fill its box, while `hasMore`. `onLoadAll()` \u2014 scroll: the strip's *Load all rows* button. `onModeChange(mode)` \u2014 the strip's Pages / Scroll switch; without it there is no switch. Each may return a Promise; until it settles no second call is made and its button shows the table is busy.\n */\n\n/** C10. When the scroll box has no layout \u2014 mounted hidden, or a DOM with no\n * layout engine \u2014 there is no viewport to measure, so the window is sized as if\n * it were this tall. A ResizeObserver corrects it the moment a real size exists. */\nconst VIRTUAL_FALLBACK_VIEWPORT_PX = 1000;\n\nexport class DataTable {\n /**\n * Create a DataTable instance\n * @param {HTMLElement} container - Container element to render into\n * @param {DataTableConfig} config - Configuration options\n */\n constructor(container, config = {}) {\n this.container = container;\n this.config = {\n headers: [],\n rows: [],\n pageSize: DEFAULT_PAGE_SIZE,\n pagination: true,\n selectable: true,\n copyable: true,\n sortable: false,\n filterable: false,\n readonly: false,\n showRowNumbers: false,\n emptyMessage: 'No data',\n onSort: null,\n // OFF unless asked for, for `columnFit`'s reason below: a sort kept\n // the client-side page before this key existed, so turning the\n // reset on for everybody would change every paged table that never\n // asked. See the typedef.\n resetPageOnSort: false,\n onSelectionChange: null,\n formatValue: null,\n getHeaderIcon: null,\n getColumnType: null,\n services: null,\n // Server-side pagination\n totalCount: null,\n offset: 0,\n onPageChange: null,\n onJumpToRow: null,\n // Custom cell rendering\n renderCell: null,\n // Rendering density + bottom-panel hooks (P2)\n mode: 'normal',\n onRowClick: null,\n onRowContextMenu: null,\n onCellContextMenu: null,\n showExportButton: false,\n // The host port. TOP LEVEL, deliberately \u2014 NOT inside `services`,\n // which most call sites never pass. Supplies the native save\n // dialog for downloadCSV(); absent => Blob fallback.\n host: null,\n // Opt-in persistence: when set, this table's sort, filters, and\n // column widths survive teardown/reload, keyed by this string\n // inside the injected `stateStore`. Omit it and the table stays\n // ephemeral. WHERE the store persists is the embedder's business.\n persistKey: null,\n stateStore: null,\n // How the automatic fit pass sizes an undragged column \u2014 see the\n // typedef. 'container' is exactly what every consumer got before\n // this key existed, so the default is not a preference: it is the\n // promise that adding the key changed no existing layout by a\n // pixel. Only a consumer that asks for 'content' sees anything new.\n columnFit: 'container',\n // Off unless asked for \u2014 see the typedef. With it the old pager is\n // not drawn: the paging strip says the same and more.\n paging: null,\n // C10. Off unless asked for \u2014 see the typedef.\n virtualize: false,\n virtualRowHeight: null,\n onRowsRendered: null,\n // 0.5.0. Every key below is off \u2014 or exactly the 0.4 behaviour \u2014 until\n // a consumer sets it (D6: additive and back-compatible). The typedef\n // says what each does.\n fitContent: false,\n maxHeight: null,\n autoDispose: false,\n firstColumn: 'time',\n clickable: null,\n onRowActivate: null,\n activateOn: 'click',\n getRowKey: null,\n activeRow: null,\n rowClass: null,\n rowAttrs: null,\n cellClass: null,\n diff: null,\n scrollLock: null,\n rowIcon: null,\n emptyState: undefined,\n nullDisplay: null,\n columnTypes: null,\n sortValue: null,\n dateFormat: null,\n dateTimeFormat: null,\n durationFormat: null,\n dateTimeZone: 'local',\n ...config,\n };\n\n // 0.5.0. The open row's key, and the failure on show (`setError`).\n this._activeKey = this.config.activeRow == null ? null : String(this.config.activeRow);\n this._error = null;\n\n // C10. The render window, or null when this table draws every row.\n this._virt = null;\n // The measured row height outlives a render, so a re-render does not\n // start again from the estimate and jump once it has re-measured.\n this._virtBase = null;\n\n // A persistKey with nowhere to persist is a wiring bug, not a\n // degraded mode. Fail loud at construction: a silent no-op here\n // reads as \"my filters randomly stopped sticking\" months later.\n if (this.config.persistKey && !this.config.stateStore) {\n throw new Error(`DataTable: persistKey \"${this.config.persistKey}\" requires { stateStore }`);\n }\n\n // State\n this._state = {\n offset: 0,\n selected: new Set(),\n anchorIndex: null,\n sortColumn: null,\n sortAscending: true,\n filters: new Map(),\n };\n\n // Column types cache\n this._columnTypes = [];\n\n // Processed rows cache (filtered + sorted)\n this._processedRows = null;\n this._processedIndexMap = null;\n this._filterDebounceTimer = null;\n\n // DOM references\n this._wrapperEl = null;\n this._paginationEl = null;\n this._tableEl = null;\n this._tbodyEl = null;\n this._contextMenuEl = null;\n this._filterDropdownEl = null;\n this._filterDropdownCleanup = null;\n\n // User column-resize overrides, keyed by DOM column index (the\n // row-number column, when shown, is index 0). Persists across\n // re-renders; reset when the header signature changes.\n this._colWidths = {};\n this._colWidthsSig = null;\n\n // Event cleanup\n this._disposers = [];\n this._contextMenuGlobals = [];\n // 0.5.0. `onRowActivate`'s listeners are kept apart from `_disposers`:\n // a render does not remove them at once (see `_retireActivation`).\n this._activationOffs = [];\n\n // Persistence: seed from whatever's already cached, then \u2014 once\n // the on-disk blob has loaded \u2014 re-apply and re-render if state\n // arrived after this table first painted.\n if (this.config.persistKey) {\n const store = this.config.stateStore;\n this._restorePersisted(store.get(this.config.persistKey));\n store.ready().then(() => {\n const late = store.get(this.config.persistKey);\n if (late && this._restorePersisted(late) && this._wrapperEl) {\n this._invalidateProcessedCache?.();\n this.render();\n }\n });\n }\n }\n\n /**\n * 0.5.0. Construct AND DRAW, in one call. The constructor draws nothing\n * until `render()`, so every consumer that forgot the second line got an\n * empty box; this is the two lines, once.\n *\n * Called on a class made by `withDefaults`, it builds that class \u2014 so the\n * house defaults apply.\n *\n * @param {HTMLElement} container\n * @param {DataTableConfig} [config]\n * @returns {DataTable}\n */\n static mount(container, config = {}) {\n const table = new this(container, config);\n table.render();\n return table;\n }\n\n /**\n * 0.5.0. A DataTable class with house defaults: `defaults` sit under every\n * config it is constructed (or `mount`ed) with, and the config wins key by\n * key. It is a real subclass \u2014 `instanceof DataTable` holds \u2014 and it can be\n * narrowed again with its own `withDefaults`.\n *\n * const ListTable = DataTable.withDefaults({ mode: 'compact', sortable: true,\n * pagination: false, fitContent: true });\n * const table = ListTable.mount(host, { headers, rows });\n *\n * @param {DataTableConfig} defaults\n * @returns {typeof DataTable}\n */\n static withDefaults(defaults = {}) {\n const house = { ...defaults };\n return class extends this {\n constructor(container, config = {}) {\n super(container, { ...house, ...config });\n }\n };\n }\n\n /** Apply a persisted blob ({sort, asc, filters, widths}) onto this\n * table's live state. Returns true if anything was applied. */\n _restorePersisted(blob) {\n if (!blob) return false;\n let applied = false;\n if (typeof blob.sortColumn === 'number' || blob.sortColumn === null) {\n this._state.sortColumn = blob.sortColumn;\n this._state.sortAscending = blob.sortAscending !== false;\n applied = true;\n }\n if (Array.isArray(blob.filters)) {\n this._state.filters = new Map(blob.filters);\n applied = true;\n }\n if (blob.colWidths && typeof blob.colWidths === 'object') {\n // Stored under string keys (JSON) \u2192 coerce back to ints.\n this._colWidths = {};\n for (const [k, v] of Object.entries(blob.colWidths)) {\n this._colWidths[Number(k)] = v;\n }\n // Stamp the matching signature so the next render keeps these\n // widths instead of treating them as stale.\n this._colWidthsSig = this._colSig();\n applied = true;\n }\n return applied;\n }\n\n /** Identity of the current column set \u2014 restored widths/sort are\n * keyed by position, so a schema change invalidates them. */\n _colSig() {\n return (this.config.headers || []).join('\\x01')\n + (this.config.showRowNumbers ? '|#' : '');\n }\n\n /** Snapshot the persistable slice of state to the project store.\n * No-op unless `persistKey` is set. Debounced inside the store. */\n _savePersisted() {\n if (!this.config.persistKey) return;\n this.config.stateStore.set(this.config.persistKey, {\n sortColumn: this._state.sortColumn,\n sortAscending: this._state.sortAscending,\n filters: [...this._state.filters.entries()],\n colWidths: { ...this._colWidths },\n });\n }\n\n /**\n * Update data and re-render\n * @param {Object} updates - Partial config updates (headers, rows, etc.)\n */\n setData(updates) {\n // Clear filters if headers changed\n if (updates.headers && this._state.filters.size > 0) {\n const oldHeaders = this.config.headers;\n const newHeaders = updates.headers;\n if (oldHeaders.length !== newHeaders.length ||\n oldHeaders.some((h, i) => h !== newHeaders[i])) {\n this._state.filters.clear();\n }\n }\n\n Object.assign(this.config, updates);\n\n // Reset state if rows changed\n if (updates.rows) {\n this._state.selected.clear();\n this._state.anchorIndex = null;\n if (this._state.offset >= updates.rows.length) {\n this._state.offset = 0;\n }\n this._columnTypes = this._detectColumnTypes();\n // 0.5.0. New rows are an ANSWER, so a failure on show is over. The\n // open row is not reset: it is a key, and is found again in these\n // rows (or stays unmarked until it comes back).\n this._error = null;\n }\n if (Object.prototype.hasOwnProperty.call(updates, 'activeRow')) {\n this._activeKey = updates.activeRow == null ? null : String(updates.activeRow);\n }\n // 0.5.0. A new `columnTypes` list (null included) applies at once. A new\n // `getColumnType` alone does NOT re-detect: in 0.4 it took effect with\n // the next rows, and a table that asks for nothing new keeps that.\n if (Object.prototype.hasOwnProperty.call(updates, 'columnTypes') && !updates.rows) {\n this._columnTypes = this._detectColumnTypes();\n }\n\n // Invalidate processed cache\n this._processedRows = null;\n this._processedIndexMap = null;\n\n this.render();\n }\n\n /**\n * Show / hide a translucent loading overlay over the table body.\n * Used by server-side consumers between firing a fetch and\n * receiving the new rows so the UI doesn't appear frozen.\n * Callers either:\n * - call `setLoading(true)` before their fetch, `setLoading(false)` after, OR\n * - return a Promise from `onPageChange` / `onSort` callbacks\n * \u2014 the overlay auto-shows during the await.\n * @param {boolean} on\n */\n setLoading(on) {\n this._loading = !!on;\n if (!this._wrapperEl) return;\n // 0.5.0. A wrapper class as well as the overlay, so an `emptyState` can\n // stay quiet while there is nothing YET (see the CSS) \u2014 and ONLY for a\n // table with an `emptyState`, the one thing that reads it: a table that\n // asks for nothing new keeps 0.4's wrapper to the attribute.\n this._wrapperEl.classList.toggle('twm-data-table-component--loading',\n !!on && this.config.emptyState !== undefined);\n let overlay = this._wrapperEl.querySelector('.twm-data-table__loading');\n if (on) {\n if (!overlay) {\n overlay = document.createElement('div');\n overlay.className = 'twm-data-table__loading';\n overlay.innerHTML =\n '<div class=\"twm-data-table__spinner\"></div>';\n // Ensure positioning context.\n if (!this._wrapperEl.style.position) {\n this._wrapperEl.style.position = 'relative';\n }\n this._wrapperEl.appendChild(overlay);\n }\n } else if (overlay) {\n overlay.remove();\n }\n }\n\n /**\n * Get current selection indices\n * @returns {number[]} Array of selected row indices\n */\n getSelection() {\n return Array.from(this._state.selected).sort((a, b) => a - b);\n }\n\n /**\n * Set selection programmatically\n * @param {number[]} indices - Row indices to select\n */\n setSelection(indices) {\n this._state.selected.clear();\n for (const idx of indices) {\n if (idx >= 0 && idx < this.config.rows.length) {\n // 0.5.0. A single-selection table keeps the LAST index it is\n // given \u2014 the most recent choice \u2014 never several.\n if (this.config.selectable === 'single') this._state.selected.clear();\n this._state.selected.add(idx);\n }\n }\n if (this.config.selectable === 'single') {\n this._state.anchorIndex = this._state.selected.size\n ? [...this._state.selected][0] : null;\n }\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 0.5.0 \u2014 the open row, the failure state, column widths\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Mark the row that is OPEN \u2014 the master of a master-detail \u2014 by its key\n * (`getRowKey`; without it, the row's original index). `null` clears it.\n *\n * The mark is NOT the selection: `setData` keeps it (the key is looked for\n * in the new rows), a right-click does not move it, and a sort, a filter or\n * a page change finds it where the row went. Drawn as `twm-dt-row--active`\n * and `aria-current=\"true\"` on the row, in place \u2014 no re-render.\n *\n * @param {*} key\n */\n setActiveRow(key) {\n this._activeKey = key == null ? null : String(key);\n this.config.activeRow = key ?? null;\n const tbody = this._tbodyEl;\n if (!tbody) return;\n for (const tr of tbody.children) {\n if (tr.__rowIndex === undefined) continue;\n this._paintActive(tr);\n }\n }\n\n /** The open row's key, as text, or null. */\n getActiveRow() {\n return this._activeKey;\n }\n\n /**\n * Show a FAILURE inside the table's own box: text, a node, or an `Error`\n * (its message). The rows already drawn STAY \u2014 a failed refresh does not\n * blank a list a person was reading \u2014 under a banner saying what failed;\n * with no rows, the failure takes the empty row's place. `setError(null)`\n * clears it, and so does `setData({rows})`: new rows are an answer. A\n * failure also ends `setLoading`.\n *\n * @param {string|Node|Error|null} error\n */\n setError(error) {\n this._error = error == null || error === false ? null : error;\n if (this._error) this.setLoading(false);\n if (this._wrapperEl) this.render();\n }\n\n /** What `setError` was last given, or null. */\n getError() {\n return this._error;\n }\n\n /**\n * Forget every column width a person dragged, a double-click fitted or the\n * store restored, and measure the columns again from what is on screen \u2014\n * for an embedder whose content has just changed size under them (a zoom,\n * a font). Persisted widths are cleared too.\n *\n * @returns {boolean} whether there was a table to measure\n */\n resetColumnWidths() {\n this._colWidths = {};\n this._colWidthsSig = this._colSig();\n this._savePersisted();\n if (!this._headerTableEl || !this._tableEl) return false;\n this._syncHeaderWidths();\n return true;\n }\n\n /**\n * Clear selection\n */\n clearSelection() {\n this._state.selected.clear();\n this._state.anchorIndex = null;\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n /**\n * Go to specific page\n * @param {number} page - Page number (0-indexed)\n */\n goToPage(page) {\n const rowCount = this._getProcessedRows().length;\n const maxPage = Math.ceil(rowCount / this.config.pageSize) - 1;\n this._state.offset = Math.max(0, Math.min(page, maxPage)) * this.config.pageSize;\n this.render();\n }\n\n /**\n * Go to specific row\n * @param {number} rowIndex - Row index\n */\n goToRow(rowIndex) {\n const rowCount = this._getProcessedRows().length;\n const idx = Math.max(0, Math.min(rowIndex, rowCount - 1));\n this._state.offset = Math.floor(idx / this.config.pageSize) * this.config.pageSize;\n this.render();\n }\n\n /**\n * Sort by column\n * @param {number} colIndex - Column index\n * @param {boolean} [ascending] - Sort direction (toggles if same column)\n */\n sortBy(colIndex, ascending) {\n if (this._state.sortColumn === colIndex && ascending === undefined) {\n this._state.sortAscending = !this._state.sortAscending;\n } else {\n this._state.sortColumn = colIndex;\n this._state.sortAscending = ascending ?? true;\n }\n\n // Invalidate processed cache\n this._processedRows = null;\n this._processedIndexMap = null;\n // A new order starts at its first page \u2014 when the table asked for it.\n // Staying on page 3 shows rows 201\u2013300 of the NEW order, which reads as\n // \"it only sorted this page\"; but that IS what a sort did before\n // `resetPageOnSort` existed, so a table that does not ask keeps it (D6:\n // additive and back-compatible). `render()` keeps the scroll position\n // only on the same page, so the reset also starts the body at its top.\n if (this.config.resetPageOnSort) this._state.offset = 0;\n\n // Auto-spinner: if the sort handler returns a Promise (i.e.\n // it does a server-side refetch), show the loading overlay\n // until it resolves so the user gets visible feedback.\n const ret = this.config.onSort?.(colIndex, this._state.sortAscending);\n this._awaitWithSpinner(ret);\n this._savePersisted();\n this.render();\n }\n\n /** Internal: if `maybePromise` is a Promise (or thenable),\n * toggle the loading overlay around it. No-op otherwise. */\n _awaitWithSpinner(maybePromise) {\n if (!maybePromise || typeof maybePromise.then !== 'function') return;\n this.setLoading(true);\n Promise.resolve(maybePromise).finally(() => this.setLoading(false));\n }\n\n /**\n * Clear all column filters\n */\n clearFilters() {\n this._state.filters.clear();\n this._processedRows = null;\n this._processedIndexMap = null;\n this._state.offset = 0;\n this._savePersisted();\n this.render();\n }\n\n /**\n * Get the number of rows after filtering\n * @returns {number}\n */\n getFilteredRowCount() {\n return this._getProcessedRows().length;\n }\n\n /**\n * Render the table\n */\n render() {\n // Capture active filter input before re-render\n const activeFilterColIdx = this._getActiveFilterColIdx();\n // KEYBOARD FOCUS SURVIVES A RE-RENDER. Rendering replaces the table\n // element, and a focused element that is removed hands focus to the\n // page body, where the arrow keys reach nobody. A data refresh does\n // exactly that (a record changed on disk, a live reload), so keyboard\n // navigation silently died the first time the store moved.\n const doc = this.container.ownerDocument;\n const hadTableFocus = !!this._tableEl && doc?.activeElement === this._tableEl;\n // SCROLL POSITION SURVIVES A RE-RENDER, for the same reason: the scroll\n // box is rebuilt too, and a new one starts at the top. Folding a tree\n // row, or any refresh, threw a reader scrolled halfway down back to row\n // one. Only on the SAME page \u2014 turning the page should start at its top.\n const prevWrap = this._tableWrapEl;\n const prevScroll = prevWrap?.isConnected && this._renderedOffset === this._state.offset\n ? { top: prevWrap.scrollTop, left: prevWrap.scrollLeft } : null;\n\n this._cleanup();\n this._retireActivation();\n this.container.innerHTML = '';\n // C10. A window belongs to one tbody; `_createTable` builds a new one.\n this._virt = null;\n\n const { rows, pagination, emptyMessage } = this.config;\n\n // Drop stale column-resize overrides when the columns change \u2014\n // widths are keyed by position, so a different schema must start\n // from natural widths rather than inherit the old ones. (Restore\n // stamps the matching signature so persisted widths survive the\n // first render.)\n const colSig = this._colSig();\n if (this._colWidthsSig !== colSig) {\n this._colWidths = {};\n this._colWidthsSig = colSig;\n }\n\n // Detect column types if not cached\n if (this._columnTypes.length === 0) {\n this._columnTypes = this._detectColumnTypes();\n }\n\n // Create wrapper. Compact mode adds a modifier class that the\n // CSS uses to tighten padding + drop font size \u2014 opt-in so\n // existing landing/tab use sites stay identical.\n this._wrapperEl = document.createElement('div');\n this._wrapperEl.className = 'twm-data-table-component'\n + (this.config.mode === 'compact' ? ' twm-data-table-component--compact' : '');\n // 0.5.0 `fitContent` / `maxHeight`. THE DEFAULT IS `height:100%`, which\n // is right for a pane that already has a height and wrong for a list in\n // a flowing page: against an `auto` parent it resolves to nothing, and\n // the body (`flex:1 1 0`) gets ZERO \u2014 a header, a filter row, and every\n // `<tr>` in the DOM with no box to draw in. A fitted table is as tall as\n // its rows instead, up to `maxHeight`, past which its body scrolls.\n const fit = this._fitsContent();\n if (fit) {\n this._wrapperEl.classList.add('twm-data-table-component--fit');\n const max = this._maxHeightCss();\n this._wrapperEl.style.cssText = 'display:flex; flex-direction:column; height:auto; min-height:0;'\n + (max ? ` max-height:${max};` : '');\n } else {\n this._wrapperEl.style.cssText = 'display:flex; flex-direction:column; height:100%; min-height:0;';\n }\n // A render ends a `setLoading` (the overlay goes with the old wrapper,\n // as it always has).\n this._loading = false;\n\n // Pagination (top). `_createPagination` returns null when the\n // strip would be uninformative (single page, no active filter). Not\n // with `paging`, whose own strip (under the body) replaces it.\n if (pagination && rows.length > 0 && !this._pagingConfig()) {\n this._paginationEl = this._createPagination();\n if (this._paginationEl) this._wrapperEl.appendChild(this._paginationEl);\n }\n\n // \u2500\u2500 Structural split: thead and tbody live in separate\n // containers so the scrollbar appears only over the body,\n // never over the header / filter row. Column widths are\n // measured from the body after layout and applied to the\n // header via `table-layout: fixed` + explicit cell widths.\n const tableWrap = document.createElement('div');\n tableWrap.className = this.config.readonly\n ? 'twm-preview-table-wrap twm-preview-table-wrap--wizard'\n : 'twm-preview-table-wrap';\n tableWrap.style.cssText = fit\n // As tall as its content, and the one thing that gives way under a\n // `maxHeight`: the header and the pager keep their height.\n ? 'flex:0 1 auto; min-height:0; min-width:0; overflow:auto;'\n : 'flex:1 1 0; min-height:0; min-width:0; overflow:auto;';\n\n // 0.5.0 `setError` with rows on screen: the rows STAY, under a banner.\n if (this._error && rows.length > 0) {\n this._wrapperEl.appendChild(this._createErrorBanner());\n }\n\n if (rows.length === 0) {\n // Empty state \u2014 render the same chrome as the data table\n // (header row in its own non-scrolling wrap) followed by a\n // single virtual row spanning every column with the empty\n // message in italics. NO filter row: there's nothing to\n // filter, so it'd only mislead the user.\n const { headers, showRowNumbers } = this.config;\n const headerWrap = document.createElement('div');\n headerWrap.className = 'twm-preview-table-header-wrap';\n headerWrap.style.cssText\n = 'flex:0 0 auto; overflow:hidden; min-width:0;';\n const headerTable = document.createElement('table');\n headerTable.className = this._tableClassName();\n const thead = document.createElement('thead');\n const tr = document.createElement('tr');\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'num';\n th.textContent = '#';\n tr.appendChild(th);\n }\n headers.forEach((h, colIdx) => {\n const th = document.createElement('th');\n th.className = this._columnTypes[colIdx] || 'text';\n th.textContent = h;\n tr.appendChild(th);\n });\n thead.appendChild(tr);\n headerTable.appendChild(thead);\n headerWrap.appendChild(headerTable);\n this._wrapperEl.appendChild(headerWrap);\n this._headerWrapEl = headerWrap;\n this._headerTableEl = headerTable;\n\n // Body: one virtual row across every column with the empty\n // message in italics. Wraps in the standard scroll container\n // so the placeholder sits where data rows would.\n const bodyTable = document.createElement('table');\n bodyTable.className = headerTable.className;\n const tbody = document.createElement('tbody');\n const emptyTr = document.createElement('tr');\n emptyTr.className = 'data-preview-row data-table__empty-row';\n const colCount = headers.length + (showRowNumbers ? 1 : 0);\n const emptyTd = document.createElement('td');\n emptyTd.colSpan = colCount;\n if (this._error) {\n // 0.5.0. Nothing to keep: the failure takes the empty row.\n emptyTd.className = 'twm-data-table__empty-cell twm-data-table__empty-cell--error';\n emptyTd.setAttribute('role', 'alert');\n this._appendStateContent(emptyTd, this._errorContent());\n } else if (this.config.emptyState !== undefined) {\n // 0.5.0. The consumer's own words (or node), styled by class\n // rather than inline, and quiet while the table is loading.\n emptyTd.className = 'twm-data-table__empty-cell twm-data-table__empty-cell--state';\n const state = typeof this.config.emptyState === 'function'\n ? this.config.emptyState() : this.config.emptyState;\n this._appendStateContent(emptyTd, state);\n } else {\n emptyTd.style.cssText\n = 'text-align:center; font-style:italic; color:#888; padding:16px;';\n emptyTd.textContent = emptyMessage;\n }\n emptyTr.appendChild(emptyTd);\n tbody.appendChild(emptyTr);\n bodyTable.appendChild(tbody);\n tableWrap.appendChild(bodyTable);\n this._wrapperEl.appendChild(tableWrap);\n this._tableEl = bodyTable;\n this._tableWrapEl = tableWrap;\n // No column-width sync needed \u2014 the body row has colspan=N\n // so there's nothing per-column to align against.\n } else {\n const fullTable = this._createTable();\n this._tableEl = fullTable;\n // Extract thead \u2192 header table in its own non-scrolling\n // container. The body table keeps tbody only.\n const thead = fullTable.querySelector('thead');\n if (thead) {\n const headerWrap = document.createElement('div');\n headerWrap.className = 'twm-preview-table-header-wrap';\n headerWrap.style.cssText\n = 'flex:0 0 auto; overflow:hidden; min-width:0;';\n const headerTable = document.createElement('table');\n headerTable.className = fullTable.className;\n headerTable.appendChild(thead);\n headerWrap.appendChild(headerTable);\n this._wrapperEl.appendChild(headerWrap);\n this._headerTableEl = headerTable;\n this._headerWrapEl = headerWrap;\n } else {\n this._headerTableEl = null;\n }\n tableWrap.appendChild(fullTable);\n this._wrapperEl.appendChild(tableWrap);\n }\n\n this._tableWrapEl = tableWrap;\n // `paging`: the strip goes UNDER the body, where the reader's eye is\n // when they reach the end of what is held.\n this._pagingEl = null;\n if (this._pagingConfig()) {\n this._pagingEl = this._createPagingStrip();\n if (this._pagingEl) this._wrapperEl.appendChild(this._pagingEl);\n }\n this.container.appendChild(this._wrapperEl);\n // 0.6.1 `scrollLock`: THIS render's body box joins the group, and leaves\n // it with the next render's cleanup or the dispose.\n if (this.config.scrollLock && typeof this.config.scrollLock.attach === 'function') {\n this._disposers.push(this.config.scrollLock.attach(tableWrap));\n }\n // 0.5.0. Watched from here, so a table rendered again after an automatic\n // dispose (a `setData` into a re-attached host) is watched again.\n if (this.config.autoDispose) autoDisposeWatch(this);\n if (prevScroll && this._state.offset === this._renderedOffset) {\n tableWrap.scrollTop = prevScroll.top;\n tableWrap.scrollLeft = prevScroll.left;\n }\n this._renderedOffset = this._state.offset;\n\n // C10. NOW THERE IS A VIEWPORT. `_createTable` drew a window sized from\n // an estimate, before the scroll box existed; measure a real row, and\n // redraw the window for the real height and the restored scroll offset.\n // Synchronously, and not reported through `onRowsRendered`: a row present\n // when `render()` returns is the render's, as it is without `virtualize`.\n if (this._virt) {\n const onScroll = () => this._virtUpdate();\n tableWrap.addEventListener('scroll', onScroll, { passive: true });\n this._disposers.push(() => tableWrap.removeEventListener('scroll', onScroll));\n this._virtMeasure();\n this._virtUpdate({ force: true, notify: false });\n }\n\n // `paging`, scrolling: ask for the next rows near the end \u2014 and once\n // the layout has settled, when the rows held do not fill the box at all,\n // since then nothing can ever be scrolled to ask for them.\n if (this._pagingConfig()) {\n const onScroll = () => this._pagingMaybeLoadMore();\n tableWrap.addEventListener('scroll', onScroll, { passive: true });\n this._disposers.push(() => tableWrap.removeEventListener('scroll', onScroll));\n requestAnimationFrame(() => {\n if (this._tableWrapEl === tableWrap) this._pagingMaybeLoadMore();\n });\n }\n\n // Sync header column widths to body after layout. Two-pass: the\n // first frame lets the browser settle natural widths from the\n // body's auto layout, then we lock both tables to those widths\n // via table-layout:fixed + explicit cell widths.\n if (this._headerTableEl && this._tableEl) {\n requestAnimationFrame(() => this._syncHeaderWidths());\n // Re-sync on container resize so columns stay aligned when\n // the parent flex / grid layout changes (window resize,\n // splitter drag, etc.).\n if (this._resizeObserver) {\n try { this._resizeObserver.disconnect(); } catch (_) {}\n }\n if (typeof ResizeObserver !== 'undefined') {\n // C10: a new height is a new window, as well as new widths.\n this._resizeObserver = createRafResizeObserver(() => {\n this._syncHeaderWidths();\n this._virtUpdate();\n });\n this._resizeObserver.observe(this._wrapperEl);\n }\n // The header lives in its own non-scrolling wrap (so it can't\n // escape vertically), but that means it also won't follow the\n // body's HORIZONTAL scroll on its own \u2014 translate it to match.\n this._installHeaderScrollSync();\n // Drag-to-resize handles on each header cell. Only meaningful\n // when there are body rows to size against.\n if (rows.length > 0) this._installColumnResizers();\n }\n\n // Install interactions (readonly only prevents editing, not selection/copy)\n if (rows.length > 0 && (this.config.selectable || this.config.copyable || !this.config.readonly\n || typeof this.config.onRowActivate === 'function')) {\n this._installInteractions();\n }\n\n // Restore focus to filter input if it was active\n if (activeFilterColIdx !== null) {\n this._restoreFilterFocus(activeFilterColIdx);\n }\n else if (hadTableFocus && this._tableEl) {\n try { this._tableEl.focus({ preventScroll: true }); } catch (_) { /* detached */ }\n }\n }\n\n /**\n * Copy selected rows to clipboard\n * @param {'tsv'|'csv'} [format='tsv'] - Output format\n */\n async copyToClipboard(format = 'tsv') {\n const indices = this.getSelection();\n if (indices.length === 0) {\n this._notify('Copy', 'No rows selected.', 'warn');\n return;\n }\n\n const { headers, rows } = this.config;\n const matrix = [headers];\n\n for (const idx of indices) {\n const row = rows[idx];\n if (row) {\n matrix.push(row.map((val, colIdx) => this._formatValue(val, colIdx)));\n }\n }\n\n const separator = format === 'csv' ? ',' : '\\t';\n const text = format === 'csv'\n ? matrix.map(row => row.map(cell => this._csvEscape(cell)).join(separator)).join('\\n')\n : matrix.map(row => row.join(separator)).join('\\n');\n\n let ok = false;\n try {\n await navigator.clipboard.writeText(text);\n ok = true;\n } catch (_) {\n ok = this._fallbackCopy(text);\n }\n\n if (ok) {\n const desc = indices.length === 1 ? 'row' : 'rows';\n const suffix = format === 'csv' ? ' as CSV' : '';\n this._notify('Copy', `Copied ${indices.length} ${desc}${suffix}.`, 'info');\n } else {\n this._notify('Copy', 'Clipboard unavailable.', 'warn');\n }\n\n this._hideContextMenu();\n }\n\n /**\n * Download all data as CSV\n * @param {string} [filename='data.csv'] - Filename for download\n */\n async downloadCSV(filename = 'data.csv') {\n const { headers, rows } = this.config;\n if (rows.length === 0) {\n this._notify('Download', 'No data to download.', 'warn');\n return;\n }\n\n const lines = [headers.join(',')];\n for (const row of rows) {\n lines.push(row.map((val, colIdx) =>\n this._csvEscape(this._formatValue(val, colIdx))\n ).join(','));\n }\n\n const csv = lines.join('\\n');\n\n // Native save dialog when the embedder supplies one.\n //\n // `saveFile` resolves to null when a host advertises `dialogs` but its\n // transport has no save dialog behind it (host.js: null <=> unavailable).\n // That is NOT a failed save \u2014 it means \"I can't do this, use your own\n // way\", so it must reach the Blob fallback below, not the error toast.\n const dialogs = this.config.host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n // Send plain text CSV - Python handles text files directly (no base64)\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[DataTable] CSV download failed:', err);\n this._notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) {\n this._notify('Download', `Saved ${rows.length} rows to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this._notify('Download', result.error || 'Failed to save file', 'error');\n }\n return;\n }\n\n // Fallback: no `dialogs` capability at all, or a host that has one but\n // cannot actually save. Both mean \"download it yourself\".\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n this._notify('Download', 'Download started', 'info');\n }\n\n /**\n * Dispose and cleanup. Empties the host, as it always has.\n */\n dispose() {\n this._teardown(true);\n }\n\n /**\n * 0.5.0 `autoDispose`'s dispose: everything `dispose()` lets go of \u2014 but of\n * the host, only the table's OWN wrapper. A table that has been taken out\n * of the page no longer owns its host: in the task before this runs, the\n * consumer may have mounted the next list into it, or written its own\n * message there, and emptying the host would wipe that.\n */\n _disposeOwn() {\n this._teardown(false);\n }\n\n _teardown(emptyHost) {\n autoDisposeUnwatch(this);\n this._autoSeen = false;\n this._runOffs(this._activationOffs);\n this._activationOffs = [];\n this._cleanup();\n this._closeFilterDropdown();\n this._teardownContextMenu();\n if (this._resizeObserver) {\n try { this._resizeObserver.disconnect(); } catch (_) {}\n this._resizeObserver = null;\n }\n if (this._onBodyScroll && this._scrollSyncEl) {\n try {\n this._scrollSyncEl.removeEventListener('scroll', this._onBodyScroll);\n } catch (_) {}\n this._onBodyScroll = null;\n this._scrollSyncEl = null;\n }\n if (emptyHost) this.container.innerHTML = '';\n else this._wrapperEl?.remove();\n this._wrapperEl = null;\n this._paginationEl = null;\n this._tableEl = null;\n this._tbodyEl = null;\n this._headerTableEl = null;\n this._headerWrapEl = null;\n this._tableWrapEl = null;\n this._processedRows = null;\n this._processedIndexMap = null;\n this._virt = null;\n this._colgroupEl = null;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Processed rows pipeline (filter \u2192 sort \u2192 cache)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _getProcessedRows() {\n if (this._processedRows !== null) return this._processedRows;\n\n const isServerSide = typeof this.config.onPageChange === 'function';\n let rows = this.config.rows;\n let indexMap = rows.map((_, i) => i);\n\n // Apply filters (client-side only)\n if (!isServerSide && this._state.filters.size > 0) {\n const result = this._applyFilters(rows, indexMap);\n rows = result.rows;\n indexMap = result.indexMap;\n }\n\n // Apply sort (client-side, only when no external onSort handler)\n if (!isServerSide && this.config.sortable && this._state.sortColumn !== null && !this.config.onSort) {\n const result = this._applySorting(rows, indexMap);\n rows = result.rows;\n indexMap = result.indexMap;\n }\n\n this._processedRows = rows;\n this._processedIndexMap = indexMap;\n return rows;\n }\n\n _applyFilters(rows, indexMap) {\n const filters = this._state.filters;\n const filteredRows = [];\n const filteredMap = [];\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n let pass = true;\n\n for (const [colIdx, filterText] of filters) {\n if (!filterText) continue;\n const value = row[colIdx];\n const colType = this._valueKind(colIdx);\n\n if (colType === 'num') {\n if (!this._matchNumericFilter(value, filterText)) { pass = false; break; }\n } else if (colType === 'date' || colType === 'datetime') {\n // 0.5.0. By the TIME, with the drawn words as the fallback\n // for text that names no period.\n const utc = this._utc();\n if (!matchDateFilter(parseDateValue(value, { utc }), filterText,\n this._formatValue(value, colIdx), { utc })) {\n pass = false; break;\n }\n } else if (colType === 'duration') {\n if (!matchDurationFilter(parseDuration(value), filterText,\n this._formatValue(value, colIdx))) {\n pass = false; break;\n }\n } else {\n if (!this._matchTextFilter(value, filterText)) { pass = false; break; }\n }\n }\n\n if (pass) {\n filteredRows.push(row);\n filteredMap.push(indexMap[i]);\n }\n }\n\n return { rows: filteredRows, indexMap: filteredMap };\n }\n\n _applySorting(rows, indexMap) {\n const colIdx = this._state.sortColumn;\n const asc = this._state.sortAscending;\n\n // 0.5.0. A `sortValue` hook, or a column typed by its VALUE, sorts by a\n // key computed ONCE per row (a date is parsed once, not once per\n // comparison). Every other column takes the 0.4 comparator below,\n // untouched.\n const hook = this._sortValueFor(colIdx);\n const kind = this._valueKind(colIdx);\n if (hook || TYPED_COLUMNS.has(kind)) {\n const utc = this._utc();\n const keyOf = (row) => {\n const value = row[colIdx];\n if (hook) {\n const k = hook(value, colIdx, row);\n if (k !== undefined) return normaliseSortKey(k);\n }\n if (kind === 'date' || kind === 'datetime') {\n return normaliseSortKey(parseDateValue(value, { utc }));\n }\n if (kind === 'duration') return normaliseSortKey(parseDuration(value));\n if (kind === 'num') {\n return normaliseSortKey(typeof value === 'number' ? value : parseFloat(value));\n }\n return value == null ? null : String(value).toLowerCase();\n };\n const keyed = rows.map((row, i) => ({ row, origIdx: indexMap[i], key: keyOf(row) }));\n keyed.sort((a, b) => compareSortKeys(a.key, b.key, asc));\n return {\n rows: keyed.map((p) => p.row),\n indexMap: keyed.map((p) => p.origIdx),\n };\n }\n\n // Build paired array for stable sort with index tracking\n const paired = rows.map((row, i) => ({ row, origIdx: indexMap[i] }));\n const isNumeric = this._columnTypes[colIdx] === 'num';\n\n paired.sort((a, b) => {\n let valA = a.row[colIdx];\n let valB = b.row[colIdx];\n\n if (valA == null && valB == null) return 0;\n if (valA == null) return 1;\n if (valB == null) return -1;\n\n if (isNumeric) {\n valA = typeof valA === 'number' ? valA : parseFloat(valA);\n valB = typeof valB === 'number' ? valB : parseFloat(valB);\n if (!Number.isFinite(valA)) return 1;\n if (!Number.isFinite(valB)) return -1;\n } else {\n valA = String(valA).toLowerCase();\n valB = String(valB).toLowerCase();\n }\n\n let cmp = 0;\n if (valA < valB) cmp = -1;\n else if (valA > valB) cmp = 1;\n\n return asc ? cmp : -cmp;\n });\n\n return {\n rows: paired.map(p => p.row),\n indexMap: paired.map(p => p.origIdx),\n };\n }\n\n _matchNumericFilter(value, filterText) {\n const text = filterText.trim();\n if (!text) return true;\n\n const numVal = (typeof value === 'number') ? value : parseFloat(value);\n if (!Number.isFinite(numVal)) return false;\n\n // Range: \"10..100\"\n const rangeMatch = text.match(/^(-?[\\d.]+)\\.\\.(-?[\\d.]+)$/);\n if (rangeMatch) {\n const lo = parseFloat(rangeMatch[1]);\n const hi = parseFloat(rangeMatch[2]);\n return numVal >= lo && numVal <= hi;\n }\n\n // Operator prefix: >=, <=, !=, >, <, =\n const opMatch = text.match(/^(>=|<=|!=|>|<|=)\\s*(-?[\\d.]+)$/);\n if (opMatch) {\n const op = opMatch[1];\n const target = parseFloat(opMatch[2]);\n if (!Number.isFinite(target)) return true;\n switch (op) {\n case '>': return numVal > target;\n case '<': return numVal < target;\n case '>=': return numVal >= target;\n case '<=': return numVal <= target;\n case '!=': return Math.abs(numVal - target) > 1e-9;\n case '=': return Math.abs(numVal - target) <= 1e-9;\n }\n }\n\n // Plain number: equality\n const plain = parseFloat(text);\n if (Number.isFinite(plain)) {\n return Math.abs(numVal - plain) <= 1e-9;\n }\n\n return true;\n }\n\n _matchTextFilter(value, filterText) {\n if (!filterText) return true;\n const haystack = (value == null ? '' : String(value)).toLowerCase();\n const text = filterText.trim();\n\n // Exact match: =\"value\"\n if (text.startsWith('=\"') && text.endsWith('\"')) {\n return haystack === text.slice(2, -1).toLowerCase();\n }\n // Not contains: !value\n if (text.startsWith('!')) {\n return !haystack.includes(text.slice(1).toLowerCase());\n }\n // Starts with: ^value\n if (text.startsWith('^')) {\n return haystack.startsWith(text.slice(1).toLowerCase());\n }\n // Ends with: value$\n if (text.endsWith('$')) {\n return haystack.endsWith(text.slice(0, -1).toLowerCase());\n }\n // Contains (default)\n return haystack.includes(text.toLowerCase());\n }\n\n _invalidateProcessedCache() {\n this._processedRows = null;\n this._processedIndexMap = null;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Filter row\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _createFilterRow(headers) {\n const { showRowNumbers } = this.config;\n const tr = document.createElement('tr');\n tr.className = 'twm-data-table__filter-row';\n\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'data-table__filter-cell data-table__filter-cell--empty';\n tr.appendChild(th);\n }\n\n headers.forEach((header, colIdx) => {\n const th = document.createElement('th');\n th.className = 'data-table__filter-cell';\n\n const wrapper = document.createElement('div');\n wrapper.className = 'twm-data-table__filter-wrapper';\n\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'twm-data-table__filter-input';\n const kind = this._valueKind(colIdx);\n input.placeholder = kind === 'num' ? 'e.g. >100'\n : kind === 'date' || kind === 'datetime' ? 'e.g. >2026-01-01'\n : kind === 'duration' ? 'e.g. >1s'\n : 'Filter...';\n\n // Restore existing filter value\n const existingFilter = this._state.filters.get(colIdx);\n if (existingFilter) {\n input.value = existingFilter;\n }\n\n // Dropdown trigger button\n const dropdownBtn = document.createElement('button');\n dropdownBtn.type = 'button';\n dropdownBtn.className = 'twm-data-table__filter-dropdown-btn';\n dropdownBtn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:14px;\">tune</span>';\n dropdownBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._openFilterDropdown(colIdx, th, input);\n });\n\n // Clear button\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.className = 'twm-data-table__filter-clear';\n clearBtn.innerHTML = '<span class=\"material-symbols-outlined\" style=\"font-size:12px;\">close</span>';\n clearBtn.style.display = existingFilter ? '' : 'none';\n clearBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n input.value = '';\n this._onFilterInput(colIdx, '');\n clearBtn.style.display = 'none';\n input.focus();\n });\n\n input.addEventListener('input', () => {\n clearBtn.style.display = input.value ? '' : 'none';\n this._onFilterInputDebounced(colIdx, input.value);\n });\n\n // Prevent sort from triggering when clicking in filter cell\n th.addEventListener('click', (e) => e.stopPropagation());\n\n wrapper.appendChild(input);\n wrapper.appendChild(dropdownBtn);\n wrapper.appendChild(clearBtn);\n th.appendChild(wrapper);\n tr.appendChild(th);\n });\n\n return tr;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Filter dropdown\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n _openFilterDropdown(colIdx, anchorEl, filterInput) {\n // Close any existing dropdown\n this._closeFilterDropdown();\n\n const kind = this._valueKind(colIdx);\n const isNumeric = kind === 'num';\n // 0.5.0. A date or a duration takes the numeric OPERATORS \u2014 before,\n // after, between \u2014 over operands typed as text (`2026-10`, `1.5s`).\n const isDate = kind === 'date' || kind === 'datetime';\n const isOrdered = isNumeric || isDate || kind === 'duration';\n const currentFilter = this._state.filters.get(colIdx) || '';\n const parsed = this._parseFilterForDropdown(currentFilter, isOrdered ? (isNumeric ? true : kind) : false);\n\n // Build dropdown panel\n const panel = document.createElement('div');\n panel.className = 'twm-data-table__filter-dropdown';\n\n // Operator/mode select\n const selectLabel = document.createElement('label');\n selectLabel.className = 'twm-data-table__filter-dropdown-label';\n selectLabel.textContent = isOrdered ? 'Operator' : 'Mode';\n\n const select = document.createElement('select');\n select.className = 'twm-data-table__filter-dropdown-select';\n\n const options = isDate\n ? [\n { value: '=', label: 'On / in' },\n { value: '!=', label: 'Not on / in' },\n { value: '>', label: 'After' },\n { value: '>=', label: 'On or after' },\n { value: '<', label: 'Before' },\n { value: '<=', label: 'On or before' },\n { value: '..', label: 'Between' },\n ]\n : isOrdered\n ? [\n { value: '=', label: 'Equals' },\n { value: '!=', label: 'Not equals' },\n { value: '>', label: 'Greater than' },\n { value: '>=', label: 'Greater or equal' },\n { value: '<', label: 'Less than' },\n { value: '<=', label: 'Less or equal' },\n { value: '..', label: 'Between' },\n ]\n : [\n { value: 'contains', label: 'Contains' },\n { value: 'equals', label: 'Equals' },\n { value: 'starts', label: 'Starts with' },\n { value: 'ends', label: 'Ends with' },\n { value: 'not', label: 'Not contains' },\n ];\n\n for (const opt of options) {\n const optEl = document.createElement('option');\n optEl.value = opt.value;\n optEl.textContent = opt.label;\n if (opt.value === parsed.operator) optEl.selected = true;\n select.appendChild(optEl);\n }\n\n // Value input\n const valueLabel = document.createElement('label');\n valueLabel.className = 'twm-data-table__filter-dropdown-label';\n valueLabel.textContent = 'Value';\n\n const operandPlaceholder = isNumeric ? 'Number...'\n : isDate ? 'YYYY-MM-DD' : isOrdered ? 'e.g. 1.5s' : 'Text...';\n const valueInput = document.createElement('input');\n valueInput.type = isNumeric ? 'number' : 'text';\n valueInput.className = 'twm-data-table__filter-dropdown-input';\n valueInput.placeholder = operandPlaceholder;\n valueInput.value = parsed.value;\n\n // Second value input (for \"between\")\n const value2Label = document.createElement('label');\n value2Label.className = 'twm-data-table__filter-dropdown-label';\n value2Label.textContent = 'And';\n\n const value2Input = document.createElement('input');\n value2Input.type = isOrdered && !isNumeric ? 'text' : 'number';\n value2Input.className = 'twm-data-table__filter-dropdown-input';\n value2Input.placeholder = isOrdered && !isNumeric ? operandPlaceholder : 'Number...';\n value2Input.value = parsed.value2;\n\n const value2Container = document.createElement('div');\n value2Container.className = 'twm-data-table__filter-dropdown-between';\n value2Container.style.display = (isOrdered && parsed.operator === '..') ? '' : 'none';\n value2Container.appendChild(value2Label);\n value2Container.appendChild(value2Input);\n\n // Toggle between fields when operator changes\n select.addEventListener('change', () => {\n value2Container.style.display = (isOrdered && select.value === '..') ? '' : 'none';\n });\n // What `_composeFilterString` is told: true for a number (0.4), the\n // kind for a date or a duration, false for text.\n const composeMode = isNumeric ? true : isOrdered ? kind : false;\n\n // Actions\n const actions = document.createElement('div');\n actions.className = 'twm-data-table__filter-dropdown-actions';\n\n const clearBtn = document.createElement('button');\n clearBtn.type = 'button';\n clearBtn.className = 'twm-data-table__filter-dropdown-btn-action twm-data-table__filter-dropdown-btn-action--clear';\n clearBtn.textContent = 'Clear';\n clearBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n filterInput.value = '';\n this._onFilterInput(colIdx, '');\n this._closeFilterDropdown();\n });\n\n const applyBtn = document.createElement('button');\n applyBtn.type = 'button';\n applyBtn.className = 'twm-data-table__filter-dropdown-btn-action twm-data-table__filter-dropdown-btn-action--apply';\n applyBtn.textContent = 'Apply';\n applyBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const composed = this._composeFilterString(select.value, valueInput.value, value2Input.value, composeMode);\n filterInput.value = composed;\n this._onFilterInput(colIdx, composed);\n this._closeFilterDropdown();\n });\n\n actions.appendChild(clearBtn);\n actions.appendChild(applyBtn);\n\n // Assemble panel\n panel.appendChild(selectLabel);\n panel.appendChild(select);\n panel.appendChild(valueLabel);\n panel.appendChild(valueInput);\n panel.appendChild(value2Container);\n panel.appendChild(actions);\n\n // Add to document and position\n document.body.appendChild(panel);\n\n const anchorRect = anchorEl.getBoundingClientRect();\n let left = anchorRect.left;\n let top = anchorRect.bottom + 4;\n\n // Viewport boundary check\n const panelRect = panel.getBoundingClientRect();\n if (left + panelRect.width > window.innerWidth) {\n left = window.innerWidth - panelRect.width - 8;\n }\n if (top + panelRect.height > window.innerHeight) {\n top = anchorRect.top - panelRect.height - 4;\n }\n\n panel.style.left = `${left}px`;\n panel.style.top = `${top}px`;\n\n // Focus the value input\n requestAnimationFrame(() => valueInput.focus());\n\n // Close on outside click (capture phase)\n const handleOutsideClick = (e) => {\n if (!panel.contains(e.target)) {\n this._closeFilterDropdown();\n }\n };\n const handleEscape = (e) => {\n if (e.key === 'Escape') {\n this._closeFilterDropdown();\n }\n };\n // Enter key applies the filter\n const handleEnter = (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n const composed = this._composeFilterString(select.value, valueInput.value, value2Input.value, composeMode);\n filterInput.value = composed;\n this._onFilterInput(colIdx, composed);\n this._closeFilterDropdown();\n }\n };\n\n // Delay attaching outside-click to avoid catching the trigger click\n setTimeout(() => {\n document.addEventListener('click', handleOutsideClick, true);\n }, 0);\n document.addEventListener('keydown', handleEscape);\n panel.addEventListener('keydown', handleEnter);\n\n this._filterDropdownEl = panel;\n this._filterDropdownCleanup = () => {\n document.removeEventListener('click', handleOutsideClick, true);\n document.removeEventListener('keydown', handleEscape);\n };\n }\n\n _closeFilterDropdown() {\n if (this._filterDropdownEl?.parentNode) {\n this._filterDropdownEl.parentNode.removeChild(this._filterDropdownEl);\n }\n this._filterDropdownCleanup?.();\n this._filterDropdownEl = null;\n this._filterDropdownCleanup = null;\n }\n\n _parseFilterForDropdown(filterText, isNumeric) {\n const text = (filterText || '').trim();\n if (!text) {\n return { operator: isNumeric ? '=' : 'contains', value: '', value2: '' };\n }\n\n // 0.5.0. A date or a duration (`isNumeric` is then the kind): the\n // numeric operators, over operands that are text.\n if (typeof isNumeric === 'string') {\n const range = text.match(/^(.+?)\\s*\\.\\.\\s*(.+)$/);\n if (range) return { operator: '..', value: range[1], value2: range[2] };\n const op = text.match(/^(>=|<=|!=|>|<|=)\\s*(.+)$/);\n if (op) return { operator: op[1], value: op[2], value2: '' };\n return { operator: '=', value: text, value2: '' };\n }\n\n if (isNumeric) {\n // Range: \"10..100\"\n const rangeMatch = text.match(/^(-?[\\d.]+)\\.\\.(-?[\\d.]+)$/);\n if (rangeMatch) {\n return { operator: '..', value: rangeMatch[1], value2: rangeMatch[2] };\n }\n // Operator prefix: >=, <=, !=, >, <, =\n const opMatch = text.match(/^(>=|<=|!=|>|<|=)\\s*(-?[\\d.]+)$/);\n if (opMatch) {\n return { operator: opMatch[1], value: opMatch[2], value2: '' };\n }\n // Plain number\n return { operator: '=', value: text, value2: '' };\n }\n\n // Text modes\n if (text.startsWith('=\"') && text.endsWith('\"')) {\n return { operator: 'equals', value: text.slice(2, -1), value2: '' };\n }\n if (text.startsWith('!')) {\n return { operator: 'not', value: text.slice(1), value2: '' };\n }\n if (text.startsWith('^')) {\n return { operator: 'starts', value: text.slice(1), value2: '' };\n }\n if (text.endsWith('$')) {\n return { operator: 'ends', value: text.slice(0, -1), value2: '' };\n }\n return { operator: 'contains', value: text, value2: '' };\n }\n\n _composeFilterString(operator, value, value2, isNumeric) {\n if (!value && operator !== '..') return '';\n\n // 0.5.0. A date or a duration keeps its `=`: an operand with no\n // operator is matched against the drawn words, not compared.\n if (typeof isNumeric === 'string') {\n if (operator === '..') return (value && value2) ? `${value}..${value2}` : '';\n return `${operator}${value}`;\n }\n\n if (isNumeric) {\n if (operator === '..') {\n return (value && value2) ? `${value}..${value2}` : '';\n }\n if (operator === '=') return value;\n return `${operator}${value}`;\n }\n\n // Text modes\n switch (operator) {\n case 'contains': return value;\n case 'equals': return value ? `=\"${value}\"` : '';\n case 'starts': return value ? `^${value}` : '';\n case 'ends': return value ? `${value}$` : '';\n case 'not': return value ? `!${value}` : '';\n default: return value;\n }\n }\n\n _onFilterInputDebounced(colIdx, value) {\n if (this._filterDebounceTimer) {\n clearTimeout(this._filterDebounceTimer);\n }\n this._filterDebounceTimer = setTimeout(() => {\n this._onFilterInput(colIdx, value);\n }, 200);\n }\n\n _onFilterInput(colIdx, value) {\n if (value) {\n this._state.filters.set(colIdx, value);\n } else {\n this._state.filters.delete(colIdx);\n }\n\n this._invalidateProcessedCache();\n this._state.offset = 0;\n this._state.selected.clear();\n this._state.anchorIndex = null;\n\n this._savePersisted();\n this.render();\n }\n\n _getActiveFilterColIdx() {\n const active = document.activeElement;\n if (!active || !active.classList.contains('twm-data-table__filter-input')) return null;\n const cell = active.closest('.data-table__filter-cell');\n if (!cell) return null;\n const row = cell.parentElement;\n if (!row) return null;\n const cells = Array.from(row.children);\n const idx = cells.indexOf(cell);\n return this.config.showRowNumbers ? idx - 1 : idx;\n }\n\n _restoreFilterFocus(colIdx) {\n const filterRow = this._wrapperEl?.querySelector('.twm-data-table__filter-row');\n if (!filterRow) return;\n const cellIdx = this.config.showRowNumbers ? colIdx + 1 : colIdx;\n const cell = filterRow.children[cellIdx];\n const input = cell?.querySelector('.twm-data-table__filter-input');\n if (input) {\n input.focus();\n input.setSelectionRange(input.value.length, input.value.length);\n }\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Private methods\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Run (and forget) a list of removers. */\n _runOffs(offs) {\n for (const off of offs || []) {\n try { off?.(); } catch (_) { /* already gone */ }\n }\n }\n\n /**\n * 0.5.0. A render takes `onRowActivate`'s listeners off the body it is\n * replacing ONE TASK LATER, not now. The render may be running INSIDE the\n * very click that is about to open a row \u2014 an `onSelectionChange` that calls\n * `setData`, an `onRowClick` that calls `render` \u2014 and a listener removed\n * during its own event's dispatch is skipped: the row silently did not\n * open. The event's path was fixed when it was dispatched, so it still\n * reaches the old body, whose listener opens the row that was pressed. The\n * old body is out of the page, so nothing else can reach it meanwhile.\n */\n _retireActivation() {\n const offs = this._activationOffs;\n this._activationOffs = [];\n if (offs.length) setTimeout(() => this._runOffs(offs), 0);\n }\n\n _cleanup() {\n this._disposers.forEach(dispose => {\n try { dispose?.(); } catch (_) {}\n });\n this._disposers = [];\n this._closeFilterDropdown();\n if (this._filterDebounceTimer) {\n clearTimeout(this._filterDebounceTimer);\n this._filterDebounceTimer = null;\n }\n }\n\n _detectColumnTypes() {\n const { headers, rows, getColumnType, columnTypes } = this.config;\n const types = [];\n\n for (let colIdx = 0; colIdx < headers.length; colIdx++) {\n // 0.5.0. A type declared by position wins over the callback and\n // over detection \u2014 which never guesses a date: typing one is a\n // decision about how it is drawn.\n const declared = Array.isArray(columnTypes) ? columnTypes[colIdx] : null;\n if (declared) {\n types.push(declared);\n continue;\n }\n if (getColumnType) {\n types.push(getColumnType(colIdx, rows));\n continue;\n }\n\n // Auto-detect by sampling first 10 rows\n let numericCount = 0;\n let sampleCount = 0;\n const maxSamples = Math.min(10, rows.length);\n\n for (let i = 0; i < maxSamples; i++) {\n const value = rows[i]?.[colIdx];\n if (value != null && value !== '') {\n sampleCount++;\n if (typeof value === 'number' || /^-?[\\d,.]+%?$/.test(String(value).trim())) {\n numericCount++;\n }\n }\n }\n\n types.push(sampleCount > 0 && numericCount / sampleCount > 0.5 ? 'num' : 'text');\n }\n\n return types;\n }\n\n _createPagination() {\n const { rows, pageSize, totalCount: configTotalCount, offset: configOffset, onPageChange, onJumpToRow } = this.config;\n\n // Server-side pagination uses config offset, client-side uses state offset\n const isServerSide = typeof onPageChange === 'function';\n const offset = isServerSide ? (configOffset || 0) : this._state.offset;\n\n // For client-side, use processed (filtered+sorted) row count\n const processedRows = isServerSide ? rows : this._getProcessedRows();\n const effectiveTotal = isServerSide ? (configTotalCount || rows.length) : processedRows.length;\n const unfilteredTotal = isServerSide ? (configTotalCount || rows.length) : rows.length;\n const isFiltered = !isServerSide && this._state.filters.size > 0;\n\n const displayedRows = isServerSide ? rows.length : Math.min(pageSize, effectiveTotal - offset);\n const endRow = Math.min(offset + displayedRows, effectiveTotal);\n const totalPages = Math.max(1, Math.ceil(effectiveTotal / pageSize));\n // Don't render the strip when there's only one page \u2014 the row\n // count is uninformative (the table itself shows every row) and\n // the nav buttons would all be disabled.\n if (totalPages <= 1 && !isFiltered) return null;\n const currentPage = Math.floor(offset / pageSize) + 1;\n const hasPrev = offset > 0;\n const hasNext = offset + pageSize < effectiveTotal;\n\n const el = document.createElement('div');\n el.className = 'twm-pagination-controls';\n el.style.cssText = 'display:flex; align-items:center; gap:6px; padding:2px 8px; border-bottom:1px solid #2a2a2a; font-size:11px;';\n\n // Info\n const info = document.createElement('span');\n info.style.cssText = 'color:#aaa; white-space:nowrap;';\n if (effectiveTotal === 0) {\n info.textContent = isFiltered\n ? `0 of ${unfilteredTotal.toLocaleString()} rows match`\n : 'No rows';\n } else if (isFiltered) {\n info.textContent = `Rows ${offset + 1}\\u2013${endRow} of ${effectiveTotal.toLocaleString()} (${unfilteredTotal.toLocaleString()} total)`;\n } else {\n info.textContent = `Rows ${offset + 1}\\u2013${endRow} of ${effectiveTotal.toLocaleString()}`;\n }\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n\n // Page change handler - supports both client-side and server-side pagination\n const handlePageChange = (newOffset) => {\n if (isServerSide) {\n // Auto-spinner if the consumer returns a Promise.\n this._awaitWithSpinner(onPageChange(newOffset, pageSize));\n } else {\n this._state.offset = newOffset;\n this.render();\n }\n };\n\n // Navigation buttons\n const firstBtn = this._createPaginationBtn('first_page', 'First page', !hasPrev, () => {\n handlePageChange(0);\n });\n\n const prevBtn = this._createPaginationBtn('chevron_left', 'Previous page', !hasPrev, () => {\n handlePageChange(Math.max(0, offset - pageSize));\n });\n\n const pageInfo = document.createElement('span');\n pageInfo.style.cssText = 'color:#aaa; font-size:10px; min-width:72px; text-align:center;';\n pageInfo.textContent = `Page ${currentPage} of ${totalPages}`;\n\n const nextBtn = this._createPaginationBtn('chevron_right', 'Next page', !hasNext, () => {\n handlePageChange(offset + pageSize);\n });\n\n const lastBtn = this._createPaginationBtn('last_page', 'Last page', !hasNext, () => {\n handlePageChange(Math.floor((effectiveTotal - 1) / pageSize) * pageSize);\n });\n\n // Jump to row\n const jumpInput = document.createElement('input');\n jumpInput.type = 'number';\n jumpInput.className = 'twm-pagination-input';\n jumpInput.style.cssText = 'width:54px; padding:1px 4px; border:1px solid #444; background:#2a2a2a; color:#ccc; font-size:10px;';\n jumpInput.min = '1';\n jumpInput.max = String(effectiveTotal);\n jumpInput.placeholder = 'Row #';\n\n const jumpBtn = this._createPaginationBtn(null, 'Go to row', false, () => {\n const target = Number(jumpInput.value);\n if (Number.isFinite(target) && target >= 1) {\n if (isServerSide && onJumpToRow) {\n onJumpToRow(target - 1);\n } else if (isServerSide) {\n // Default: calculate page offset for the target row\n const newOffset = Math.floor((target - 1) / pageSize) * pageSize;\n handlePageChange(newOffset);\n } else {\n this.goToRow(target - 1);\n }\n }\n }, 'Go');\n\n el.appendChild(info);\n el.appendChild(spacer);\n el.appendChild(firstBtn);\n el.appendChild(prevBtn);\n el.appendChild(pageInfo);\n el.appendChild(nextBtn);\n el.appendChild(lastBtn);\n el.appendChild(jumpInput);\n el.appendChild(jumpBtn);\n\n // CSV export button (opt-in). Re-uses the existing downloadCSV\n // method which already handles the host save dialog + browser\n // fallback.\n if (this.config.showExportButton) {\n const exportBtn = this._createPaginationBtn(\n 'download', 'Download visible rows as CSV', false,\n () => this.downloadCSV('data.csv'));\n el.appendChild(exportBtn);\n }\n\n return el;\n }\n\n _createPaginationBtn(icon, tooltip, disabled, onClick, textLabel = null) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'hoverbutton twm-pagination-btn twm-has-tooltip';\n btn.setAttribute('data-tooltip', tooltip);\n btn.disabled = disabled;\n btn.style.cssText = 'padding:1px 3px; background:transparent; border:1px solid #444; color:#aaa; cursor:pointer; display:flex; align-items:center; justify-content:center; line-height:1;';\n\n if (disabled) {\n btn.style.opacity = '0.4';\n btn.style.cursor = 'not-allowed';\n }\n\n if (icon) {\n const iconEl = document.createElement('span');\n iconEl.className = 'material-symbols-outlined';\n iconEl.style.fontSize = '14px';\n iconEl.textContent = icon;\n btn.appendChild(iconEl);\n } else if (textLabel) {\n btn.textContent = textLabel;\n btn.style.fontSize = '10px';\n btn.style.padding = '1px 6px';\n }\n\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n // \u2500\u2500 `paging` \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** The `paging` config with its defaults, or null when it is not set. */\n _pagingConfig() {\n const p = this.config.paging;\n if (!p || typeof p !== 'object') return null;\n const size = Number.isFinite(p.pageSize) && p.pageSize >= 1\n ? Math.floor(p.pageSize) : this.config.pageSize;\n return {\n ...p,\n pageSize: size,\n offset: Number.isFinite(p.offset) && p.offset > 0 ? Math.floor(p.offset) : 0,\n // What the table holds of the source. A consumer whose `rows` carry\n // a row the source does not (a blank line to type into) says so.\n held: Number.isFinite(p.held) ? p.held : (this.config.rows?.length || 0),\n hasMore: !!p.hasMore,\n loadMorePx: Number.isFinite(p.loadMorePx) ? p.loadMorePx : PAGING_LOAD_MORE_PX,\n };\n }\n\n /**\n * Which way the rows are shown, and why \u2014 `resolvePaging` over this\n * table's facts. `null` without `paging`.\n */\n get pagingState() {\n const p = this._pagingConfig();\n if (!p) return null;\n // A page's rows prove the source holds every row before them too, so\n // what is PROVEN is the offset plus the rows held.\n return resolvePaging({\n mode: p.mode, total: p.total, atLeast: p.atLeast, held: p.offset + p.held,\n hasMore: p.hasMore, softLimit: p.softLimit, hardLimit: p.hardLimit,\n });\n }\n\n /**\n * Change some `paging` facts \u2014 a count that arrived, a mode \u2014 and redraw\n * the STRIP only. The rows are not touched: a consumer with new rows\n * renders the table as it always has.\n */\n setPaging(patch = {}) {\n if (!this.config.paging) return;\n this.config.paging = { ...this.config.paging, ...patch };\n this._refreshPagingStrip();\n this._pagingMaybeLoadMore();\n }\n\n _refreshPagingStrip() {\n if (!this._wrapperEl) return;\n const next = this._pagingConfig() ? this._createPagingStrip() : null;\n const prev = this._pagingEl;\n if (prev && prev.parentNode === this._wrapperEl) {\n if (next) prev.replaceWith(next); else prev.remove();\n } else if (next) {\n this._wrapperEl.appendChild(next);\n }\n this._pagingEl = next;\n }\n\n /**\n * Call one of the consumer's paging callbacks. A Promise holds every other\n * paging call back until it settles, and the strip shows the table busy \u2014\n * a second `onLoadMore` fired by the next scroll event would fetch the same\n * page twice.\n */\n _pagingCall(kind, fn, ...args) {\n if (typeof fn !== 'function' || this._pagingBusy) return;\n let result;\n try {\n result = fn(...args);\n } catch (err) {\n console.error(`[DataTable] paging ${kind} threw`, err);\n return;\n }\n if (result && typeof result.then === 'function') {\n this._pagingBusy = kind;\n this._refreshPagingStrip();\n const settle = () => {\n if (this._pagingBusy !== kind) return;\n this._pagingBusy = null;\n if (this._pagingEl?.isConnected) this._refreshPagingStrip();\n };\n result.then(settle, (err) => {\n console.error(`[DataTable] paging ${kind} failed`, err);\n settle();\n });\n }\n }\n\n /**\n * Scrolling: ask for the next rows when the body is near its end \u2014 or does\n * not fill its box, which no scroll can ever change. Never past the hard\n * limit, never in pages, never with no layout (a hidden table's box is 0px\n * tall, and \"0 \u2264 0\" would ask for the whole source).\n */\n _pagingMaybeLoadMore() {\n const p = this._pagingConfig();\n if (!p || !p.hasMore || this._pagingBusy) return;\n const state = this.pagingState;\n if (state.mode !== 'scroll' || p.held >= state.hardLimit) return;\n const wrap = this._tableWrapEl;\n if (!wrap?.isConnected || !(wrap.clientHeight > 0)) return;\n const remaining = wrap.scrollHeight - wrap.scrollTop - wrap.clientHeight;\n if (remaining >= p.loadMorePx) return;\n this._pagingCall('more', p.onLoadMore);\n }\n\n /** The strip under the body, or null when it would say nothing. */\n _createPagingStrip() {\n const p = this._pagingConfig();\n const state = this.pagingState;\n const { mode, forced, exact, known } = state;\n const busy = this._pagingBusy;\n const n = (x) => Number(x).toLocaleString();\n const pageSize = p.pageSize;\n const held = p.held;\n const total = exact ? p.total : null;\n\n const morePages = p.offset > 0 || p.hasMore || (exact && total > held);\n if (!forced && mode === 'scroll' && !p.hasMore && held <= pageSize) return null;\n if (!forced && mode === 'pages' && !morePages) return null;\n\n const el = document.createElement('div');\n el.className = `twm-dt-paging twm-dt-paging--${mode}`;\n el.setAttribute('role', 'navigation');\n el.setAttribute('aria-label', 'Rows');\n if (busy) el.classList.add('twm-dt-paging--busy');\n\n const info = document.createElement('span');\n info.className = 'twm-dt-paging__info';\n el.appendChild(info);\n\n if (mode === 'pages') {\n const from = held ? p.offset + 1 : p.offset;\n const to = p.offset + held;\n let of = '';\n if (exact) of = ` of ${n(total)}`;\n else if (known > to) of = ` of more than ${n(known - 1)}`;\n info.textContent = held ? `Rows ${n(from)}\u2013${n(to)}${of}` : 'No rows on this page';\n\n const hasPrev = p.offset > 0;\n const hasNext = exact ? p.offset + held < total : p.hasMore;\n const lastOffset = exact && total > 0\n ? Math.floor((total - 1) / pageSize) * pageSize : null;\n // A disabled button's click is ignored here too: a browser sends none,\n // but a synthetic one (a test, a script) still reaches the listener.\n const go = (offset) => (ev) => {\n if (!ev?.currentTarget?.disabled) this._pagingCall('page', p.onPage, offset, pageSize);\n };\n const nav = document.createElement('span');\n nav.className = 'twm-dt-paging__nav';\n const off = !!busy || typeof p.onPage !== 'function';\n nav.append(\n this._createPaginationBtn('first_page', 'First page', off || !hasPrev, go(0)),\n this._createPaginationBtn('chevron_left', 'Previous page', off || !hasPrev,\n go(Math.max(0, p.offset - pageSize))),\n );\n const page = document.createElement('span');\n page.className = 'twm-dt-paging__page';\n const current = Math.floor(p.offset / pageSize) + 1;\n page.textContent = exact\n ? `Page ${n(current)} of ${n(Math.max(1, Math.ceil(total / pageSize)))}`\n : `Page ${n(current)}`;\n nav.append(\n page,\n this._createPaginationBtn('chevron_right', 'Next page', off || !hasNext,\n go(p.offset + pageSize)),\n // The last page needs the exact count: without it there is no\n // offset to go to, and the button says so by being off.\n this._createPaginationBtn('last_page',\n lastOffset === null ? 'Last page (the total is not known)' : 'Last page',\n off || !hasNext || lastOffset === null, go(lastOffset)),\n );\n el.appendChild(nav);\n } else {\n if (exact && total > held) info.textContent = `${n(held)} of ${n(total)} rows`;\n else if (p.hasMore) info.textContent = `${n(held)} rows, more to come`;\n else info.textContent = `${n(held)} rows`;\n if (p.hasMore && typeof p.onLoadAll === 'function') {\n const all = document.createElement('button');\n all.type = 'button';\n all.className = 'twm-dt-paging__all';\n all.textContent = busy === 'all' ? 'Loading\u2026'\n : exact ? `Load all ${n(total)} rows` : 'Load all rows';\n all.disabled = !!busy;\n all.addEventListener('click', () => {\n if (!all.disabled) this._pagingCall('all', p.onLoadAll);\n });\n el.appendChild(all);\n }\n }\n\n const spacer = document.createElement('span');\n spacer.className = 'twm-dt-paging__spacer';\n el.appendChild(spacer);\n\n // WHY IT IS PAGED, said on the strip \u2014 a disabled Scroll alone reads as\n // a switch that does not work.\n const why = forced\n ? `More than ${n(state.softLimit)} rows, so they are shown in pages.` : null;\n if (why) {\n const note = document.createElement('span');\n note.className = 'twm-dt-paging__note';\n note.textContent = why;\n el.appendChild(note);\n }\n\n if (typeof p.onModeChange === 'function') {\n const group = document.createElement('span');\n group.className = 'twm-dt-paging__modes';\n group.setAttribute('role', 'group');\n group.setAttribute('aria-label', 'Show rows');\n for (const [value, label] of [['pages', 'Pages'], ['scroll', 'Scroll']]) {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'twm-dt-paging__mode';\n b.dataset.mode = value;\n b.textContent = label;\n const pressed = mode === value;\n b.setAttribute('aria-pressed', String(pressed));\n b.disabled = !!busy || (value === 'scroll' && forced);\n if (value === 'scroll' && forced) b.title = why;\n b.addEventListener('click', () => {\n if (!b.disabled && mode !== value) this._pagingCall('mode', p.onModeChange, value);\n });\n group.appendChild(b);\n }\n el.appendChild(group);\n }\n return el;\n }\n\n _createTable() {\n const { headers, rows, pageSize, sortable, filterable, showRowNumbers, readonly, getHeaderIcon, onPageChange, offset: configOffset } = this.config;\n const { sortColumn, sortAscending } = this._state;\n\n // Server-side pagination: rows already represent current page, use config offset for row numbering\n // Client-side pagination: use processed (filtered+sorted) rows, then slice for current page\n const isServerSide = typeof onPageChange === 'function';\n const processedRows = isServerSide ? rows : this._getProcessedRows();\n const offset = isServerSide ? (configOffset || 0) : this._state.offset;\n // NO PAGINATION MEANS NO PAGES. This used to slice to `pageSize` either\n // way, so a table built with `pagination: false` silently showed its\n // first hundred rows and offered no control to reach the rest.\n // And `paging` rows ARE the page (or everything scrolled to so far):\n // the consumer fetched them, and slicing them again would draw a\n // hundred of a thousand.\n const pageRows = isServerSide || !this.config.pagination || this._pagingConfig()\n ? processedRows : processedRows.slice(offset, offset + pageSize);\n\n const table = document.createElement('table');\n table.className = this._tableClassName();\n table.tabIndex = 0;\n\n // Header\n const thead = document.createElement('thead');\n const headerRow = document.createElement('tr');\n\n if (showRowNumbers) {\n const th = document.createElement('th');\n th.className = 'num';\n th.textContent = '#';\n headerRow.appendChild(th);\n }\n\n headers.forEach((header, colIdx) => {\n const th = document.createElement('th');\n th.className = this._columnTypes[colIdx] || 'text';\n\n if (sortable) {\n th.classList.add('sortable');\n th.style.cursor = 'pointer';\n }\n\n // Header icon\n if (getHeaderIcon) {\n const iconInfo = getHeaderIcon(header, colIdx);\n if (iconInfo) {\n const iconSpan = document.createElement('span');\n iconSpan.className = 'material-symbols-outlined twm-header-icon twm-has-tooltip';\n iconSpan.setAttribute('data-tooltip', iconInfo.title || '');\n iconSpan.style.cssText = 'font-size:16px; vertical-align:middle; margin-right:4px; opacity:0.7;';\n iconSpan.textContent = iconInfo.icon;\n th.appendChild(iconSpan);\n }\n }\n\n th.appendChild(document.createTextNode(header));\n\n // Sort indicator\n if (sortable) {\n const sortIcon = document.createElement('span');\n sortIcon.className = 'material-symbols-outlined twm-sort-icon';\n sortIcon.style.cssText = 'font-size:14px; margin-left:4px; opacity:0.5;';\n if (sortColumn === colIdx) {\n sortIcon.textContent = sortAscending ? 'arrow_upward' : 'arrow_downward';\n sortIcon.style.opacity = '1';\n } else {\n sortIcon.textContent = 'unfold_more';\n }\n th.appendChild(sortIcon);\n\n th.addEventListener('click', () => this.sortBy(colIdx));\n }\n\n th.title = header;\n headerRow.appendChild(th);\n });\n\n thead.appendChild(headerRow);\n\n // Filter row (below header)\n if (filterable) {\n const filterRow = this._createFilterRow(headers);\n thead.appendChild(filterRow);\n }\n\n // C10. THE COLUMN TRACK IS A `<colgroup>`, NOT THE FIRST ROW. Under\n // `table-layout: fixed` a `<col>` with a width decides its column, and a\n // first-row cell only decides one whose `<col>` is `auto` \u2014 so once the\n // widths live here, it stops mattering which row is first. A recycling\n // window changes that row on every scroll; without this the columns\n // would jitter each time it did. Before the `thead`, where the content\n // model puts it; the `thead` leaves for the header table in `render()`\n // and the colgroup stays with the body.\n const virtual = this._isVirtual();\n if (virtual) {\n table.classList.add('twm-dt--virtual');\n table.appendChild(this._createColgroup());\n }\n\n table.appendChild(thead);\n\n // Map back to original config.rows index for selection tracking\n const globalOf = (localIdx) => {\n const processedIdx = offset + localIdx;\n return isServerSide\n ? (configOffset || 0) + localIdx\n : (this._processedIndexMap?.[processedIdx] ?? processedIdx);\n };\n\n // 0.5.0 `showRowNumbers: 'position'`: where the first row drawn here\n // stands in the order SHOWN (the page's first row on a later page).\n this._positionBase = isServerSide ? (configOffset || 0)\n : (this.config.pagination ? offset : 0);\n // `paging`: a page's rows stand at its offset in the SOURCE, which only\n // the numbering reads \u2014 their indexes stay those of `rows`.\n const paged = this._pagingConfig();\n if (paged && Number.isFinite(paged.offset)) this._positionBase += paged.offset;\n\n // Body\n const tbody = document.createElement('tbody');\n table.appendChild(tbody);\n this._tbodyEl = tbody;\n\n if (virtual) {\n this._virtInit(tbody, pageRows, globalOf, {\n serverSide: isServerSide, offset, configOffset: configOffset || 0,\n });\n } else {\n pageRows.forEach((row, localIdx) => {\n tbody.appendChild(this._buildBodyRow(row, globalOf(localIdx), localIdx));\n });\n }\n\n return table;\n }\n\n /** One body row, fully built. The ONE place a `<tr>` for a row is made, so\n * the full render and the virtual window cannot drift apart: a row drawn\n * on scroll is the same row a render would have drawn. */\n _buildBodyRow(row, globalIdx, localIdx) {\n const { showRowNumbers } = this.config;\n const tr = document.createElement('tr');\n tr.__rowIndex = globalIdx;\n // 0.5.0. The row's place in the order shown (for 'position' numbers).\n tr.__position = (this._positionBase || 0) + localIdx;\n tr.className = 'data-preview-row';\n\n if (this._state.selected.has(globalIdx)) {\n tr.classList.add('selected');\n }\n // 0.5.0. The consumer's row classes and attributes, and the open mark.\n this._decorateRow(tr, row, globalIdx);\n // C10. The stripe is `tr:nth-child(even)`, which is a question about a\n // row's POSITION among its siblings \u2014 and a window that drops rows off\n // its top changes every answer. `_virtSpacers` keeps the position's\n // parity equal to the row's own, so the stripe needs nothing here; the\n // class is for an embedder that wants to ask about the row itself.\n if (this._virt) tr.classList.toggle('twm-dt-row--alt', localIdx % 2 === 1);\n\n this._fillRowCells(tr, row, globalIdx, showRowNumbers);\n\n // Row-level click + right-click hooks (P2). Bound after\n // cells so per-cell handlers run first.\n if (this.config.onRowClick) {\n tr.addEventListener('click', (ev) => {\n this.config.onRowClick(globalIdx, row, ev);\n });\n }\n if (this.config.onRowContextMenu) {\n tr.addEventListener('contextmenu', (ev) => {\n this.config.onRowContextMenu(globalIdx, row, ev);\n });\n }\n return tr;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // C10 \u2014 the virtual window\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // \u2550\u2550 WHAT IT IS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // Only the rows near the viewport are in the DOM: a TOP SPACER row whose\n // height is every row above the window, the window's rows, and a BOTTOM\n // SPACER for everything below it. The scrollbar is therefore sized to the\n // whole table and every row is reachable, while the DOM stays bounded by\n // the viewport \u2014 a thousand-row page (or fifty of them) costs the same\n // few dozen `<tr>`s as one screenful.\n //\n // \u2550\u2550 WHAT IT PROMISES \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // - A row that stays in the window is NEVER MOVED OR REBUILT when the\n // window slides. Rows leave from the edges and arrive at the edges; the\n // ones in the middle are the same nodes. An open editor, a focused\n // cell, a hover \u2014 anything living in a row that is still on screen \u2014\n // survives a scroll. (Moving a node that holds focus blurs it, which in\n // an editable grid is a commit nobody asked for.)\n // - Column widths come from a `<colgroup>`, so the first row changing\n // moves nothing (see `_createTable`).\n // - A spacer is in the DOM only while it has a height. A table that fits\n // in its window has exactly the DOM it had without `virtualize`.\n // - `onRowsRendered` hears about every row added after `render()`, and\n // every row taken out.\n //\n // \u2550\u2550 WHAT IT ASSUMES \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // That a row's height is knowable without drawing it: `baseHeight`,\n // measured from a real row, or what `virtualRowHeight` says. A row that\n // wraps to two lines is drawn correctly and is simply mis-counted in the\n // spacer arithmetic by the difference \u2014 the overscan absorbs that.\n\n _isVirtual() {\n return !!this.config.virtualize;\n }\n\n _virtOptions() {\n const v = this.config.virtualize;\n const o = v && typeof v === 'object' ? v : {};\n return {\n overscan: Number.isFinite(o.overscan) && o.overscan >= 0 ? Math.floor(o.overscan) : 20,\n rowHeight: Number.isFinite(o.rowHeight) && o.rowHeight > 0 ? o.rowHeight : 24,\n };\n }\n\n /** One `<col>` per DOM column (the row-number column included), carrying\n * any width already pinned for it, so a re-render starts at the widths it\n * had rather than at a content-sized frame that then snaps. */\n _createColgroup() {\n const n = (this.config.headers?.length || 0) + (this.config.showRowNumbers ? 1 : 0);\n const colgroup = document.createElement('colgroup');\n for (let i = 0; i < n; i++) {\n const col = document.createElement('col');\n const w = this._colWidths?.[i];\n if (w != null && this._colWidthsSig === this._colSig()) col.style.width = `${w}px`;\n colgroup.appendChild(col);\n }\n this._colgroupEl = colgroup;\n return colgroup;\n }\n\n /** The `<col>`s, when this table has them. */\n _cols() {\n return this._virt && this._colgroupEl ? this._colgroupEl.children : null;\n }\n\n _virtInit(tbody, rows, globalOf, { serverSide, offset, configOffset }) {\n const { overscan, rowHeight } = this._virtOptions();\n const spacer = (edge) => {\n const tr = document.createElement('tr');\n tr.className = `twm-dt-spacer twm-dt-spacer--${edge}`;\n tr.setAttribute('aria-hidden', 'true');\n const td = document.createElement('td');\n td.colSpan = Math.max(1, (this.config.headers?.length || 0)\n + (this.config.showRowNumbers ? 1 : 0));\n // INLINE, because it must beat every consumer's cell padding and\n // border at any specificity: a spacer that is 1px taller than its\n // arithmetic moves every row below it by that pixel.\n td.style.cssText = 'padding:0;border:0;height:0;min-width:0;max-width:none;';\n tr.appendChild(td);\n return tr;\n };\n // The parity filler: see `_virtSpacers`.\n const filler = document.createElement('tr');\n filler.className = 'twm-dt-spacer twm-dt-spacer--parity';\n filler.setAttribute('aria-hidden', 'true');\n filler.hidden = true;\n this._virt = {\n tbody, rows, globalOf, serverSide, offset, configOffset,\n overscan,\n base: this._virtBase || rowHeight,\n heights: null, offsets: null,\n start: 0, end: 0,\n map: new Map(),\n top: spacer('top'), bottom: spacer('bottom'), filler,\n };\n this._virtComputeOffsets();\n // A first window from an ESTIMATED viewport: the scroll box does not\n // exist yet. `render()` redraws it for the real one once it does.\n const guess = this.container?.clientHeight || 0;\n this._virtUpdate({ force: true, notify: false, viewport: guess || undefined, top: 0 });\n }\n\n /** Heights and their running sum. `offsets[i]` is where row `i` starts;\n * `offsets[n]` is the whole table. O(n), and rerun only when a height can\n * have changed \u2014 a new measurement, or `refreshVirtualLayout()`. */\n _virtComputeOffsets() {\n const v = this._virt;\n if (!v) return;\n const n = v.rows.length;\n const heights = new Float64Array(n);\n const offsets = new Float64Array(n + 1);\n const fn = typeof this.config.virtualRowHeight === 'function'\n ? this.config.virtualRowHeight : null;\n let y = 0;\n for (let i = 0; i < n; i++) {\n let h = v.base;\n if (fn) {\n const asked = fn(v.globalOf(i), v.base);\n h = Number.isFinite(asked) && asked > 0 ? asked : 0;\n }\n heights[i] = h;\n offsets[i] = y;\n y += h;\n }\n offsets[n] = y;\n v.heights = heights;\n v.offsets = offsets;\n }\n\n /** The row whose span contains `y`: the LAST `i` with `offsets[i] <= y`,\n * which steps over rows of zero height at the same offset. */\n _virtIndexAt(y) {\n const v = this._virt;\n const n = v.rows.length;\n if (n === 0) return 0;\n let lo = 0;\n let hi = n - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (v.offsets[mid] <= y) lo = mid; else hi = mid - 1;\n }\n return lo;\n }\n\n /** Measure one real row. Client pixels, so the zoom is divided back out \u2014\n * `_measureNaturalWidths` explains why \u2014 and NOT `offsetHeight`, which is\n * rounded: 21 for a 21.19px row is a 1,100px error over 6,000 rows. */\n _virtMeasure() {\n const v = this._virt;\n if (!v) return false;\n for (const tr of v.map.values()) {\n if (!tr.isConnected || tr.hidden) continue;\n const zoom = this._tableEl?.currentCSSZoom || 1;\n const h = tr.getBoundingClientRect().height / zoom;\n if (!(h > 0)) return false;\n if (Math.abs(h - v.base) > 0.01) {\n v.base = h;\n this._virtBase = h;\n this._virtComputeOffsets();\n return true;\n }\n return false;\n }\n return false;\n }\n\n /**\n * Slide the window to wherever the scroll box now is.\n *\n * HYSTERESIS, so a scroll of one pixel does not rebuild anything: the\n * window is redrawn only when the visible rows come within a quarter of the\n * overscan of either end of what is drawn, and it is then redrawn with the\n * full overscan on both sides.\n *\n * @param {object} [o]\n * @param {boolean} [o.force] redraw even inside the hysteresis band.\n * @param {boolean} [o.notify] report added and removed rows to `onRowsRendered`.\n * @param {number} [o.top] the scroll offset to draw for, instead of\n * reading one back \u2014 `scrollToRow` passes the offset it has just set,\n * which a DOM with no layout would read back as 0.\n * @param {number} [o.viewport] the viewport height, likewise.\n * @returns {HTMLElement[]} the rows added.\n */\n _virtUpdate({ force = false, notify = true, top = null, viewport = null } = {}) {\n const v = this._virt;\n if (!v || !v.offsets) return [];\n const n = v.rows.length;\n const wrap = this._tableWrapEl;\n const view = viewport || wrap?.clientHeight || VIRTUAL_FALLBACK_VIEWPORT_PX;\n const scrollTop = top ?? (wrap?.scrollTop || 0);\n const vs = this._virtIndexAt(scrollTop);\n const ve = Math.min(n, this._virtIndexAt(scrollTop + view) + 1);\n if (!force && v.end > v.start) {\n const margin = Math.max(1, Math.floor(v.overscan / 4));\n const lowOk = v.start === 0 || vs >= v.start + margin;\n const highOk = v.end === n || ve <= v.end - margin;\n if (lowOk && highOk) return [];\n }\n const start = Math.max(0, vs - v.overscan);\n const end = Math.min(n, ve + v.overscan);\n const removed = [];\n const added = this._virtRender(start, end, removed);\n if (added.length || removed.length) {\n // Only once the columns are fixed: before that the first sync has\n // not run, and it tooltips every cell itself.\n if (added[0]?.isConnected && this._tableEl?.style.tableLayout === 'fixed') {\n this._updateCellTooltips(added);\n }\n if (notify) {\n try { this.config.onRowsRendered?.({ rows: added, removed }); } catch (err) {\n console.error('[DataTable] onRowsRendered threw', err);\n }\n }\n }\n return added;\n }\n\n /** Make the DOM hold exactly the drawable rows of `[start, end)`, without\n * moving a row that is already there. See the promises above. */\n _virtRender(start, end, removed = null) {\n const v = this._virt;\n const tbody = v.tbody;\n const want = [];\n for (let i = start; i < end; i++) if (v.heights[i] > 0) want.push(i);\n const wanted = new Set(want);\n for (const [i, tr] of v.map) {\n if (!wanted.has(i)) { tr.remove(); v.map.delete(i); removed?.push(tr); }\n }\n v.start = start;\n v.end = end;\n this._virtSpacers();\n const added = [];\n // Right to left, so each new row goes in front of the one after it \u2014\n // which is either a row that stayed (and is not moved) or the bottom\n // spacer (or the end of the body).\n let ref = v.bottom.isConnected ? v.bottom : null;\n for (let k = want.length - 1; k >= 0; k--) {\n const i = want[k];\n const have = v.map.get(i);\n if (have) { ref = have; continue; }\n const tr = this._buildBodyRow(v.rows[i], v.globalOf(i), i);\n v.map.set(i, tr);\n tbody.insertBefore(tr, ref);\n ref = tr;\n added.push(tr);\n }\n added.reverse();\n return added;\n }\n\n /**\n * Size the two spacers, and put each in the DOM only while it has a height.\n *\n * AND KEEP THE STRIPE. `tr:nth-child(even)` stripes by POSITION, and in a\n * full render row `i` is child `i + 1`. Here the first drawn row is preceded\n * by the top spacer, so its position is off by one \u2014 and by a different one\n * each time the window's start changes parity, which strobes every stripe\n * on the screen as you scroll. A hidden filler row after the spacer, present\n * exactly when `start` is even, puts the parity back: a `display: none` row\n * is still a child, and so still counted by `nth-child`.\n */\n _virtSpacers() {\n const v = this._virt;\n const n = v.rows.length;\n const above = v.offsets[v.start];\n const below = v.offsets[n] - v.offsets[v.end];\n const tbody = v.tbody;\n if (above > 0) {\n v.top.firstChild.style.height = `${above}px`;\n if (tbody.firstChild !== v.top) tbody.insertBefore(v.top, tbody.firstChild);\n const needFiller = v.start % 2 === 0;\n if (needFiller && v.top.nextSibling !== v.filler) v.top.after(v.filler);\n else if (!needFiller) v.filler.remove();\n } else {\n v.top.remove();\n v.filler.remove();\n }\n if (below > 0) {\n v.bottom.firstChild.style.height = `${below}px`;\n if (tbody.lastChild !== v.bottom) tbody.appendChild(v.bottom);\n } else {\n v.bottom.remove();\n }\n }\n\n /**\n * Recompute every row's height and redraw the window. For an embedder whose\n * `virtualRowHeight` answer has changed \u2014 a group folded, a header added.\n * A no-op on a table that is not virtual.\n */\n refreshVirtualLayout() {\n if (!this._virt) return;\n this._virtMeasure();\n this._virtComputeOffsets();\n this._virtUpdate({ force: true });\n }\n\n /** The element that scrolls the body. Read-only; the table owns it. */\n get scrollElement() {\n return this._tableWrapEl || null;\n }\n\n /** The `<tr>` drawing row `rowIndex` (the `__rowIndex` space), or null when\n * it is not in the DOM \u2014 outside the window, on another page, or hidden. */\n getRowElement(rowIndex) {\n const v = this._virt;\n if (v) {\n const local = this._virtLocalOf(rowIndex);\n return local < 0 ? null : (v.map.get(local) || null);\n }\n const tbody = this._tbodyEl;\n if (!tbody) return null;\n for (const tr of tbody.children) if (tr.__rowIndex === rowIndex) return tr;\n return null;\n }\n\n /** Keep the window's row list and `config.rows` in step for one row. They\n * are the same array in server-side mode; in client mode the window reads\n * the filtered-and-sorted copy, which holds its own reference. */\n _virtSetRow(rowIndex, row) {\n const v = this._virt;\n if (!v) return;\n if (Array.isArray(this.config.rows) && rowIndex >= 0\n && rowIndex < this.config.rows.length) {\n this.config.rows[rowIndex] = row;\n }\n const local = this._virtLocalOf(rowIndex);\n if (local >= 0) v.rows[local] = row;\n }\n\n /** `__rowIndex` \u2192 position in the window's row list, or -1. */\n _virtLocalOf(rowIndex) {\n const v = this._virt;\n if (!v) return -1;\n let local;\n if (v.serverSide) local = rowIndex - v.configOffset;\n else {\n const map = this._processedIndexMap;\n const processed = map ? map.indexOf(rowIndex) : rowIndex;\n local = processed < 0 ? -1 : processed - v.offset;\n }\n return local >= 0 && local < v.rows.length ? local : -1;\n }\n\n /**\n * Scroll the body so row `rowIndex` is on screen, drawing it if it was not,\n * and return its `<tr>` (null when it cannot be shown: another page, or a\n * row the embedder hides). Works with or without `virtualize`.\n *\n * @param {number} rowIndex in the `__rowIndex` space.\n * @param {{block?: 'nearest'|'center'|'start'}} [opts]\n */\n scrollToRow(rowIndex, { block = 'nearest' } = {}) {\n const wrap = this._tableWrapEl;\n const v = this._virt;\n if (!v) {\n const tr = this.getRowElement(rowIndex);\n if (!tr || !wrap) return tr;\n const zoom = this._tableEl?.currentCSSZoom || 1;\n const box = wrap.getBoundingClientRect();\n const r = tr.getBoundingClientRect();\n const rowTop = (r.top - box.top) / zoom + wrap.scrollTop;\n const rowH = r.height / zoom;\n const target = this._scrollTarget(rowTop, rowH, wrap.scrollTop,\n wrap.clientHeight, block);\n if (target !== wrap.scrollTop) wrap.scrollTop = target;\n return tr;\n }\n const local = this._virtLocalOf(rowIndex);\n if (local < 0 || !(v.heights[local] > 0)) return null;\n const view = wrap?.clientHeight || VIRTUAL_FALLBACK_VIEWPORT_PX;\n const current = wrap?.scrollTop || 0;\n let target = this._scrollTarget(v.offsets[local], v.heights[local],\n current, view, block);\n target = Math.max(0, Math.min(target, Math.max(0, v.offsets[v.rows.length] - view)));\n if (wrap && Math.abs(target - current) >= 1) wrap.scrollTop = target;\n this._virtUpdate({ top: Math.abs(target - current) >= 1 ? target : current });\n return v.map.get(local) || null;\n }\n\n _scrollTarget(rowTop, rowH, current, view, block) {\n if (block === 'start') return rowTop;\n if (block === 'center') return rowTop - Math.max(0, (view - rowH) / 2);\n if (rowTop < current) return rowTop;\n if (rowTop + rowH > current + view) return rowTop + rowH - view;\n return current;\n }\n\n /** The first body row that draws a row of data \u2014 never a spacer, and never\n * a row an embedder injected (a group header spans every column with ONE\n * cell, so measuring it would report one column). */\n _firstBodyRow() {\n const tbody = this._tableEl?.querySelector?.('tbody');\n if (!tbody) return null;\n for (const tr of tbody.children) {\n if (tr.__rowIndex !== undefined) return tr;\n }\n return null;\n }\n\n /** Build (or rebuild) one row's cells in place.\n *\n * Extracted from the body loop so that `updateRow` and the initial\n * render share ONE cell-building path. Two paths would drift, and the\n * drift would show as a cell that renders differently after a live\n * update than it did on load. */\n _fillRowCells(tr, row, globalIdx, showRowNumbers) {\n tr.replaceChildren();\n\n if (showRowNumbers) {\n const td = document.createElement('td');\n td.className = 'num';\n // 0.5.0. 'position' counts the rows as SHOWN; `true` keeps the 0.4\n // number, the row's original index.\n const byPosition = this.config.showRowNumbers === 'position'\n && Number.isInteger(tr.__position);\n td.textContent = String((byPosition ? tr.__position : globalIdx) + 1);\n tr.appendChild(td);\n }\n\n const { cellClass, nullDisplay } = this.config;\n // 0.6.1 `diff`.\n const diff = this._diffOf(row, globalIdx);\n const gap = diff?.status === 'gap';\n const changedCells = diff?.cells\n ? (diff.cells instanceof Set ? diff.cells : new Set(diff.cells))\n : null;\n for (let colIdx = 0; colIdx < row.length; colIdx++) {\n const td = document.createElement('td');\n td.className = this._columnTypes[colIdx] || 'text';\n\n // Use custom cell renderer if provided\n const value = row[colIdx];\n let handled = false;\n if (gap) {\n // The other side's row: a place, not a value.\n td.classList.add('twm-dt-diff__gap');\n tr.appendChild(td);\n continue;\n }\n if (changedCells?.has(colIdx)) td.classList.add('twm-dt-diff__cell--changed');\n if (this.config.renderCell) {\n handled = !!this.config.renderCell(td, value, colIdx, globalIdx, row);\n if (!handled) {\n td.textContent = this._formatValue(value, colIdx);\n }\n } else {\n td.textContent = this._formatValue(value, colIdx);\n }\n // 0.5.0 `nullDisplay`: a NULL is marked as one, so it can be drawn\n // unlike the text \"NULL\" \u2014 unless `renderCell` drew the cell.\n if (!handled && value == null && nullDisplay != null) {\n td.classList.add('twm-dt-cell--null');\n }\n // 0.5.0 `cellClass`.\n if (typeof cellClass === 'function') {\n this._addClasses(td, cellClass(value, colIdx, row, globalIdx));\n }\n // 0.5.0 `rowIcon`, at the start of the first data cell.\n if (colIdx === 0 && typeof this.config.rowIcon === 'function') {\n this._prependRowIcon(td, this.config.rowIcon(row, globalIdx));\n }\n\n // Cell-level right-click hook (P2). Fires before the row-level\n // hook and the built-in context menu \u2014 the caller can\n // ev.preventDefault() to suppress the default copy menu on this\n // cell only.\n if (this.config.onCellContextMenu) {\n const cellColIdx = colIdx;\n td.addEventListener('contextmenu', (ev) => {\n this.config.onCellContextMenu(\n cellColIdx, globalIdx, value, td, ev);\n });\n }\n\n tr.appendChild(td);\n }\n }\n\n /** Re-render ONE row in place, preserving everything around it.\n *\n * `render()` rebuilds the entire `<tbody>`, which takes the scroll\n * position, any open editor, the keyboard focus and the measured column\n * widths with it. That is fine for a sort or a page change and wrong for\n * a single-cell commit or a live update arriving over a socket \u2014 the\n * common case in an editable grid, where a full rebuild once per keystroke\n * is both visible and destructive.\n *\n * What survives, by construction:\n * - scroll position, because the tbody is not replaced;\n * - the separately-rendered thead/tbody column widths, because the\n * explicit widths live on the header cells and on the FIRST body row,\n * and all three of the properties `_setCellWidth` writes are re-applied\n * here when that first row is the one being replaced;\n * - selection, because the `selected` class is recomputed from the\n * selection set rather than carried on the old element;\n * - keyboard focus, because the focused element's position is recorded\n * before the replace and restored after.\n *\n * @param {number} index row index as tracked by `tr.__rowIndex`\n * @param {any[]} row the new cell values\n * @returns {boolean} false when the row is not currently rendered\n * (it is on another page, or outside the render\n * window) \u2014 which is NOT an error: the caller has\n * nothing to update on screen.\n */\n updateRow(index, row) {\n const tbody = this._tbodyEl;\n if (!tbody) return false;\n\n let tr = null;\n for (const candidate of tbody.children) {\n if (candidate.__rowIndex === index) { tr = candidate; break; }\n }\n // C10. OUTSIDE THE WINDOW IS NOT OFF THE PAGE. The row will be drawn the\n // moment it scrolls back in, from the window's own row list \u2014 so the\n // data has to change now, or it comes back showing the value it had\n // before this update. Without `virtualize` a row that is not in the DOM\n // is on another page, and that path is unchanged.\n if (!tr) {\n if (this._virt) this._virtSetRow(index, row);\n return false;\n }\n\n // Keep the caller's data in step, so a later full render agrees with\n // what is on screen. Server-side paging means config.rows may hold only\n // the current page; the index map is what resolves that.\n if (Array.isArray(this.config.rows) && this.config.rows[index]) {\n this.config.rows[index] = row;\n }\n if (this._virt) this._virtSetRow(index, row);\n\n // Record focus BEFORE the replace: `replaceChildren` detaches the\n // focused cell and the browser moves focus to <body>.\n const active = document.activeElement;\n let focusedCol = -1;\n if (active && tr.contains(active)) {\n focusedCol = Array.prototype.indexOf.call(tr.children, active.closest('td'));\n }\n\n // ALL THREE PROPERTIES, not just `width`. `_setCellWidth` writes\n // `width` together with `min-width: 0` and `max-width: none`, precisely\n // to escape the CSS floors on these cells (base.css pins the first\n // column at 120px/min 100px and gives every other column a 80px min).\n // Carrying the width across the rebuild and leaving the other two behind\n // let those floors back in \u2014 so a column measured narrower than its\n // floor SNAPPED WIDER the moment one of its cells was repainted, and\n // under `table-layout: fixed` this row is the column track, so the whole\n // column moved. In an editable grid that is one visible jump per saved\n // cell, which is what it looked like to the person doing the saving.\n const isFirstRow = tr === tbody.firstElementChild;\n const widths = isFirstRow\n ? Array.prototype.map.call(tr.children, (td) => ({\n width: td.style.width,\n minWidth: td.style.minWidth,\n maxWidth: td.style.maxWidth,\n }))\n : null;\n\n const showRowNumbers = this.config.showRowNumbers !== false\n && tr.firstElementChild?.classList.contains('num');\n this._fillRowCells(tr, row, index, showRowNumbers);\n\n // `_syncHeaderWidths` derives column widths from the FIRST body row.\n // Under a recycling virtualiser that row changes on every scroll \u2014 and\n // here it changes on every update \u2014 so the explicit widths have to be\n // carried across the rebuild or the columns jitter.\n if (widths) {\n widths.forEach((saved, i) => {\n const cell = tr.children[i];\n if (!saved.width || !cell) return;\n cell.style.width = saved.width;\n cell.style.minWidth = saved.minWidth;\n cell.style.maxWidth = saved.maxWidth;\n });\n }\n\n tr.classList.toggle('selected', this._state?.selected?.has(index) === true);\n // 0.5.0. The row's data changed, so its classes, attributes, key and\n // open mark are asked again (a key paused, a delivery that died).\n this._decorateRow(tr, row, index);\n\n if (focusedCol >= 0 && tr.children[focusedCol]) {\n tr.children[focusedCol].focus?.();\n }\n return true;\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // 0.5.0 \u2014 decoration, states and the typed columns\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** The class list both halves of the table carry: the 0.4 pair, plus the\n * 0.5.0 modifiers a consumer asked for. */\n _tableClassName() {\n const names = this.config.readonly\n ? ['twm-preview-table', 'twm-preview-table--readonly']\n : ['twm-preview-table'];\n if (this.config.firstColumn === 'plain') names.push('twm-dt--first-plain');\n if (this._isClickable()) names.push('twm-dt--clickable');\n return names.join(' ');\n }\n\n /** `clickable` when it is said; otherwise exactly when rows open. */\n _isClickable() {\n const c = this.config.clickable;\n if (c === true || c === false) return c;\n return typeof this.config.onRowActivate === 'function';\n }\n\n _fitsContent() {\n return !!this.config.fitContent || this._maxHeightCss() !== null;\n }\n\n _maxHeightCss() {\n const m = this.config.maxHeight;\n if (m == null || m === '' || m === false) return null;\n if (typeof m === 'number') return Number.isFinite(m) && m > 0 ? `${m}px` : null;\n return String(m);\n }\n\n _utc() {\n return String(this.config.dateTimeZone || '').toUpperCase() === 'UTC';\n }\n\n /**\n * What a column is drawn, sorted and filtered BY: its type, except that a\n * 'date', 'datetime' or 'duration' counts only when it was DECLARED through\n * `columnTypes`. In 0.4, whatever `getColumnType` returned was the cells'\n * class name and nothing more (only 'num' changed the sort and the\n * filter), so a consumer that returned 'date' there to style its cells gets\n * exactly 0.4 \u2014 its `formatValue`, its text sort, its text filter \u2014 and\n * the class name it asked for.\n */\n _valueKind(colIdx) {\n const t = this._columnTypes?.[colIdx];\n if (!TYPED_COLUMNS.has(t)) return t;\n const declared = Array.isArray(this.config.columnTypes) ? this.config.columnTypes[colIdx] : null;\n return declared === t ? t : 'text';\n }\n\n /** `classList.add` for whatever a hook returned: a string (space-separated\n * names allowed), an array of them, or nothing. */\n _addClasses(el, names) {\n if (!names) return [];\n const list = (Array.isArray(names) ? names : String(names).split(/\\s+/))\n .map((n) => String(n || '').trim()).filter(Boolean);\n if (list.length) el.classList.add(...list);\n return list;\n }\n\n /** A row's key, as text, or null: `getRowKey`, else its original index. */\n _rowKey(row, rowIdx) {\n const fn = this.config.getRowKey;\n let key;\n if (typeof fn === 'function') {\n try { key = fn(row, rowIdx); } catch (err) {\n console.error('[DataTable] getRowKey threw', err);\n key = null;\n }\n } else {\n key = rowIdx;\n }\n return key == null ? null : String(key);\n }\n\n /** The gestures `activateOn` names, as a set. */\n _activateOn() {\n const a = this.config.activateOn;\n const list = Array.isArray(a) ? a : [a || 'click'];\n return new Set(list.map((g) => String(g).toLowerCase()));\n }\n\n /**\n * Open a row on the gestures `activateOn` names, by the one rule in\n * `row_activation.js` (a control is its own gesture, a drag that selects\n * text is not a click, the second click of a double-click opens nothing).\n * Delegated on the body, bound after the selection handler.\n *\n * The listeners go in `_activationOffs`, not `_disposers`, and a render\n * retires them a task late (`_retireActivation`): a press whose selection\n * callback re-draws the table still opens the row it pressed \u2014 the row\n * as it was drawn (`tr.__row`), with its original index.\n */\n _installActivation(tbody, table) {\n const on = this._activateOn();\n const scope = this._wrapperEl;\n // A table that selects several rows reads Shift and Ctrl as SELECTION\n // gestures; one that does not leaves them to the consumer (ev.ctrlKey:\n // \"open it somewhere else\").\n const sel = this.config.selectable;\n const multi = !!sel && sel !== 'single';\n const fire = (tr, ev) => {\n // A table disposed by the press (its selection callback threw the\n // list away) opens nothing.\n if (!this._wrapperEl || typeof this.config.onRowActivate !== 'function') return;\n try { this.config.onRowActivate(tr.__rowIndex, tr.__row, ev); } catch (err) {\n console.error('[DataTable] onRowActivate threw', err);\n }\n };\n const rowFor = (ev) => {\n const tr = ev.target?.closest?.('tr');\n return tr && tr.__rowIndex !== undefined && tbody.contains(tr) ? tr : null;\n };\n const listen = (el, type, fn) => {\n el.addEventListener(type, fn);\n this._activationOffs.push(() => el.removeEventListener(type, fn));\n };\n if (on.has('click')) {\n listen(tbody, 'click', (ev) => {\n if (ev.button != null && ev.button !== 0) return;\n const tr = rowFor(ev);\n if (!tr || !isRowActivation(ev, 'click', { scope })) return;\n if (multi && (ev.shiftKey || ev.ctrlKey || ev.metaKey)) return;\n // 'single': a Ctrl click that took the row back OFF the\n // selection does not also open it (the selection handler, bound\n // first, said so on the event).\n if (DESELECTING_CLICKS.has(ev)) return;\n fire(tr, ev);\n });\n }\n if (on.has('dblclick')) {\n listen(tbody, 'dblclick', (ev) => {\n const tr = rowFor(ev);\n if (!tr || !isRowActivation(ev, 'dblclick', { scope })) return;\n fire(tr, ev);\n });\n }\n if (on.has('enter')) {\n listen(table, 'keydown', (ev) => {\n if (ev.key !== 'Enter' || ev.isComposing) return;\n if (ev.ctrlKey || ev.metaKey || ev.altKey || ev.shiftKey) return;\n if (isRowControl(ev.target, table)) return;\n const tr = this._currentRowEl();\n if (!tr) return;\n ev.preventDefault();\n fire(tr, ev);\n });\n }\n }\n\n /**\n * The row Enter opens: the SELECTED one \u2014 the one row selected, or the\n * selection's anchor \u2014 because that is the row a person just chose (a\n * double-click opens the row it lands on, and Enter must agree with it);\n * the open row (`activeRow`) only when nothing is selected. A selected row\n * that is not drawn (another page) opens nothing rather than a different\n * row.\n */\n _currentRowEl() {\n const tbody = this._tbodyEl;\n if (!tbody) return null;\n const selected = this._state.selected;\n let idx = null;\n if (selected.size === 1) idx = [...selected][0];\n else if (this._state.anchorIndex != null && selected.has(this._state.anchorIndex)) {\n idx = this._state.anchorIndex;\n }\n if (idx != null) return this.getRowElement(idx);\n if (this._activeKey !== null) {\n for (const tr of tbody.children) {\n if (tr.__rowIndex !== undefined && tr.classList.contains('twm-dt-row--active')) return tr;\n }\n }\n return null;\n }\n\n /** 0.6.1. The `diff` answer for one row, or `null` when there is none or\n * its status is not one this component draws. */\n _diffOf(row, rowIdx) {\n if (typeof this.config.diff !== 'function') return null;\n const answer = this.config.diff(row, rowIdx);\n if (!answer || !DIFF_STATUSES.has(answer.status)) return null;\n return answer;\n }\n\n /** Everything `rowClass`, `rowAttrs` and the open mark put on a `<tr>`,\n * taken off again first \u2014 so `updateRow` cannot leave last state's class\n * behind. */\n _decorateRow(tr, row, rowIdx) {\n // The row's data, for a delegated handler (`onRowActivate`).\n tr.__row = row;\n const { rowClass, rowAttrs } = this.config;\n if (tr.__twmClasses) {\n for (const c of tr.__twmClasses) tr.classList.remove(c);\n tr.__twmClasses = null;\n }\n if (typeof rowClass === 'function') {\n const added = this._addClasses(tr, rowClass(row, rowIdx));\n // Never take away a class this component owns.\n tr.__twmClasses = added.filter((c) => c !== 'data-preview-row' && c !== 'selected');\n }\n // 0.6.1 `diff`: the row's status, taken off again first like `rowClass`.\n for (const c of [...tr.classList]) {\n if (c === 'twm-dt-diff' || c.startsWith('twm-dt-diff--')) tr.classList.remove(c);\n }\n const diff = this._diffOf(row, rowIdx);\n if (diff) tr.classList.add('twm-dt-diff', `twm-dt-diff--${diff.status}`);\n if (tr.__twmAttrs) {\n for (const name of tr.__twmAttrs) tr.removeAttribute(name);\n tr.__twmAttrs = null;\n }\n if (typeof rowAttrs === 'function') {\n const attrs = rowAttrs(row, rowIdx) || {};\n const set = [];\n for (const [name, value] of Object.entries(attrs)) {\n if (value == null || value === false) continue;\n try {\n tr.setAttribute(name, value === true ? '' : String(value));\n set.push(name);\n } catch (err) {\n console.error(`[DataTable] rowAttrs: bad attribute \"${name}\"`, err);\n }\n }\n tr.__twmAttrs = set;\n }\n if (typeof this.config.getRowKey === 'function' || this._activeKey !== null) {\n tr.__rowKey = this._rowKey(row, rowIdx);\n }\n this._paintActive(tr);\n }\n\n /** The open mark on one row, from `_activeKey`. */\n _paintActive(tr) {\n if (tr.__rowKey === undefined && this._activeKey !== null && tr.__rowIndex !== undefined) {\n // A row drawn before a key was asked for (setActiveRow after render).\n const rows = this.config.rows;\n const local = this._virt ? this._virtLocalOf(tr.__rowIndex) : -1;\n const row = local >= 0 ? this._virt.rows[local] : rows?.[tr.__rowIndex];\n tr.__rowKey = this._rowKey(row, tr.__rowIndex);\n }\n const on = this._activeKey !== null && tr.__rowKey === this._activeKey;\n tr.classList.toggle('twm-dt-row--active', on);\n // `aria-current` is taken off only where THIS component wrote it. A\n // consumer that marks its open row itself (0.4 had no mark of its own,\n // and `updateRow` re-decorates a row) keeps the attribute it set.\n if (on) {\n if (tr.getAttribute('aria-current') !== 'true') {\n tr.setAttribute('aria-current', 'true');\n tr.__twmAriaCurrent = true;\n }\n } else if (tr.__twmAriaCurrent) {\n tr.__twmAriaCurrent = false;\n if (!(tr.__twmAttrs || []).includes('aria-current')) tr.removeAttribute('aria-current');\n }\n }\n\n /** The row icon, drawn by CSS from `data-twm-icon` so that its name is in\n * neither `textContent`, the clipped-cell tooltip nor a copy. */\n _prependRowIcon(td, spec) {\n if (!spec) return;\n const s = typeof spec === 'string' ? { icon: spec } : spec;\n if (!s.icon) return;\n const icon = document.createElement('span');\n icon.className = 'material-symbols-outlined twm-dt-row-icon'\n + (s.tone ? ` twm-dt-row-icon--${String(s.tone).replace(/[^\\w-]/g, '')}` : '');\n icon.dataset.twmIcon = String(s.icon);\n if (s.title) {\n icon.title = String(s.title);\n icon.setAttribute('role', 'img');\n icon.setAttribute('aria-label', String(s.title));\n } else {\n icon.setAttribute('aria-hidden', 'true');\n }\n td.insertBefore(icon, td.firstChild);\n td.classList.add('twm-dt-cell--has-icon');\n }\n\n /** Text, a node, or nothing, into an empty-state cell. */\n _appendStateContent(td, content) {\n if (content == null || content === false) return;\n if (typeof Node !== 'undefined' && content instanceof Node) td.appendChild(content);\n else td.textContent = String(content);\n }\n\n /** What `setError` holds, as something `_appendStateContent` can draw. */\n _errorContent() {\n const e = this._error;\n if (e == null) return null;\n if (typeof Node !== 'undefined' && e instanceof Node) return e;\n if (e instanceof Error) return e.message || String(e);\n if (typeof e === 'object' && e.message) return String(e.message);\n return String(e);\n }\n\n /** The failure banner over rows that are kept. */\n _createErrorBanner() {\n const banner = document.createElement('div');\n banner.className = 'twm-data-table__error';\n banner.setAttribute('role', 'alert');\n const icon = document.createElement('span');\n icon.className = 'material-symbols-outlined twm-data-table__error-icon';\n icon.setAttribute('aria-hidden', 'true');\n icon.textContent = 'error';\n const text = document.createElement('span');\n text.className = 'twm-data-table__error-text';\n const content = this._errorContent();\n // A node is the consumer's (and is MOVED here); a copy would lose its\n // listeners.\n if (typeof Node !== 'undefined' && content instanceof Node) text.appendChild(content);\n else text.textContent = String(content ?? '');\n banner.append(icon, text);\n return banner;\n }\n\n /** The `sortValue` hook for one column, or null. */\n _sortValueFor(colIdx) {\n const sv = this.config.sortValue;\n if (typeof sv === 'function') return sv;\n const fn = perColumn(sv, colIdx);\n return typeof fn === 'function' ? fn : null;\n }\n\n /** The words for a value in a typed column, or `undefined` when the\n * column is not typed (or the value is empty). */\n _formatTyped(value, colIdx) {\n const kind = this._valueKind(colIdx);\n if (!TYPED_COLUMNS.has(kind) || value == null || value === '') return undefined;\n if (kind === 'duration') {\n return formatDuration(value, perColumn(this.config.durationFormat, colIdx) || 'auto');\n }\n const pattern = kind === 'datetime'\n ? perColumn(this.config.dateTimeFormat, colIdx) || ISO_DATETIME\n : perColumn(this.config.dateFormat, colIdx) || ISO_DATE;\n if (typeof pattern === 'function') {\n const t = parseDateValue(value, { utc: this._utc() });\n return Number.isFinite(t) ? String(pattern(new Date(t), colIdx, value) ?? '') : String(value);\n }\n return formatDate(value, pattern, { utc: this._utc() });\n }\n\n /** Sync the (separate) header table's column widths to the body\n * table's measured widths. Without this, the two tables compute\n * widths independently and the columns drift apart. Locks both\n * tables to `table-layout: fixed` and writes explicit width onto\n * each header cell of every header row (header + filter row). */\n /**\n * Measure every column's NATURAL content width, in one transient reflow.\n *\n * Extracted from `_syncHeaderWidths` so that auto-size can ask the same\n * question the fit pass asks, and get the same answer. Two measurement\n * passes would drift, and the drift would show as a double-click that\n * sized a column differently from the render that follows it.\n *\n * The pass ignores the CSS caps (the 150px-pinned first column, the 80px\n * min on the rest) and the filter-row inputs: `twm-dt-measuring` flips both\n * tables to `table-layout:auto; width:max-content` with those caps off (via\n * `!important`) for a single reflow, then reverts before paint \u2014 it is\n * never visible. Clearing inline widths first stops the last sync's forced\n * widths from constraining the measure.\n *\n * C10 \u2014 UNDER `virtualize` ONLY THE WINDOW IS IN THE DOM, so `max-content`\n * spans the eighty-odd rows drawn rather than every row loaded. The fit\n * pass that runs on every render is content with that (it is fitting what\n * is on screen). An EXPLICIT auto-size is not: it is a promise to fit the\n * column's content, and the longest value in a 6,000-row table is usually\n * not in the window. So `sample` adds, for the length of this one reflow,\n * the row holding each column's longest value \u2014 see `_virtSampleRows`.\n *\n * @param {{sample?: boolean}} [o]\n * @returns {number[]|null} width per DOM column index, or null when there\n * is nothing laid out to measure.\n */\n _measureNaturalWidths({ sample = false } = {}) {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable || !bodyTable) return null;\n // A ROW OF DATA, not merely the first `<tr>`: under C10 that is a\n // spacer, and an embedder may inject rows of its own (a group header is\n // one cell spanning every column, which would measure as ONE column).\n const firstRow = this._firstBodyRow();\n if (!firstRow) return null;\n const bodyCells = firstRow.children;\n if (!bodyCells.length) return null;\n\n headerTable.querySelectorAll('thead > tr').forEach((tr) => {\n for (const th of tr.children) this._clearCellWidth(th);\n });\n for (const td of bodyCells) this._clearCellWidth(td);\n // C10: the `<col>`s are what hold the widths, so they are what has to\n // let go for the measure (`.twm-dt-measuring col` also overrides them).\n for (const col of this._cols() || []) col.style.width = '';\n headerTable.style.width = '';\n bodyTable.style.width = '';\n headerTable.classList.add('twm-dt-measuring');\n bodyTable.classList.add('twm-dt-measuring');\n // Appended at the end, where they move no drawn row, and taken out\n // again below before anything paints.\n const sampled = sample ? this._virtSampleRows() : [];\n for (const tr of sampled) this._virt.tbody.appendChild(tr);\n // Force layout flush so measurements are current.\n // eslint-disable-next-line no-unused-expressions\n bodyTable.offsetWidth;\n\n // Natural width per column = the wider of its header label and its\n // body content. `max-content` already spans every rendered body\n // row, so the body cell of the first row reports the whole column.\n const labelRow = headerTable.querySelector('thead > tr');\n const cols = bodyCells.length;\n const natural = new Array(cols);\n // \u2500\u2500 AND CSS `zoom` IS DIVIDED BACK OUT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n //\n // `getBoundingClientRect()` reports CLIENT pixels, so under a `zoom`\n // anywhere above this table every width read here comes back multiplied\n // by that zoom \u2014 while `_setCellWidth` writes a plain `width` in the\n // cell's OWN pixels, which the same zoom then multiplies again. The two\n // halves of one measure-and-apply loop would be in different units:\n // measured at 200% a column is pinned twice as wide as its text needs,\n // and at 50% it is pinned half as wide and every value ellipsises. The\n // fit pass has the same split, because its `avail` is `clientWidth`,\n // which is NOT zoom-adjusted.\n //\n // `currentCSSZoom` is the effective zoom on this element \u2014 1 when\n // nothing above it zooms, and `undefined` in an engine that predates\n // the property \u2014 so this is exactly a no-op for every consumer that\n // does not zoom, which is all of them but the Tables grid.\n const zoom = bodyTable.currentCSSZoom || 1;\n for (let i = 0; i < cols; i++) {\n const body = bodyCells[i].getBoundingClientRect().width / zoom;\n const head = labelRow && labelRow.children[i]\n ? labelRow.children[i].getBoundingClientRect().width / zoom\n : 0;\n natural[i] = Math.max(body, head);\n }\n\n for (const tr of sampled) tr.remove();\n headerTable.classList.remove('twm-dt-measuring');\n bodyTable.classList.remove('twm-dt-measuring');\n return natural;\n }\n\n /**\n * The rows an explicit auto-size must measure that the window has not\n * drawn: for each column, the drawable row whose value is LONGEST as a\n * string, plus the last row (the widest row number). Built with\n * `_buildBodyRow` \u2014 so a consumer's `renderCell` draws them exactly as it\n * would on screen \u2014 and handed back detached, for `_measureNaturalWidths`\n * to put in and take out around its one reflow.\n *\n * The string length is a proxy, not a measurement: in a proportional font\n * forty `i`s are narrower than thirty `W`s. It is the proxy a spreadsheet's\n * own autofit falls short by, and it is right about the case that matters\n * here \u2014 a value five times longer than anything in the window. One pass\n * over the loaded rows, on a click and never on a scroll or a resize.\n *\n * @returns {HTMLTableRowElement[]}\n */\n _virtSampleRows() {\n const v = this._virt;\n if (!v || !v.rows.length) return [];\n const longest = [];\n const at = [];\n let last = -1;\n for (let i = 0; i < v.rows.length; i++) {\n if (!(v.heights[i] > 0)) continue; // hidden: not drawn, not fitted\n last = i;\n const row = v.rows[i];\n if (!Array.isArray(row)) continue;\n for (let c = 0; c < row.length; c++) {\n const value = row[c];\n const len = value == null ? 0 : String(value).length;\n if (len > (longest[c] ?? -1)) { longest[c] = len; at[c] = i; }\n }\n }\n const want = new Set(at.filter((i) => i !== undefined));\n if (last >= 0) want.add(last);\n const rows = [];\n for (const i of want) {\n if (v.map.has(i)) continue; // drawn already; measured anyway\n const tr = this._buildBodyRow(v.rows[i], v.globalOf(i), i);\n tr.setAttribute('aria-hidden', 'true');\n rows.push(tr);\n }\n return rows;\n }\n\n /**\n * Fit one column to its widest value and pin it there \u2014 every loaded\n * row's, under `virtualize` (see `_virtSampleRows`), not only the window's.\n *\n * The gesture is a double-click on the column's resize grip, which is where\n * every spreadsheet has put it \u2014 and the grip is this component's, which is\n * why the behaviour is too. A consumer that wanted this had no hook to hang\n * it on: `_installColumnResizers` bound `mousedown` and a `click` that only\n * suppressed the sort, and the measurement, the pin, the table-width\n * invariant and the write-through to `stateStore` are all private here.\n *\n * @param {number} domIdx column index INCLUDING the row-number column when\n * `showRowNumbers` is on \u2014 the same index space as `_colWidths`.\n * @param {{maxWidth?: number}} [opts] ceiling; defaults to AUTOSIZE_MAX_PX.\n * @returns {boolean} whether it had a layout to measure.\n */\n autoSizeColumn(domIdx, opts = {}) {\n const natural = this._measureNaturalWidths({ sample: true });\n if (!natural || domIdx < 0 || domIdx >= natural.length) return false;\n this._colWidths[domIdx] = this._autoWidth(natural[domIdx], opts);\n this._colWidthsSig = this._colSig();\n this._savePersisted();\n this._syncHeaderWidths();\n return true;\n }\n\n /**\n * The same for every column at once.\n *\n * It REPLACES existing drag overrides rather than sizing around them: \"fit\n * every column to its content\" that quietly excepted the three columns you\n * had dragged would be a button whose result depends on history nobody can\n * see.\n *\n * The result may well be wider than the container \u2014 forty columns of real\n * content usually are \u2014 and that is the intended answer, not a failure:\n * `_syncHeaderWidths` honours overrides verbatim, sizes both tables to their\n * total and the body wrap scrolls sideways with the header following it.\n * Squeezing them to fit is what the automatic fit pass does on every render\n * already, so a button that did that would be a button that does nothing.\n */\n autoSizeColumns(opts = {}) {\n const natural = this._measureNaturalWidths({ sample: true });\n if (!natural) return false;\n this._colWidths = {};\n for (let i = 0; i < natural.length; i++) {\n this._colWidths[i] = this._autoWidth(natural[i], opts);\n }\n this._colWidthsSig = this._colSig();\n this._savePersisted();\n this._syncHeaderWidths();\n return true;\n }\n\n /** One measured width, floored at the drag-resize minimum and capped, with\n * the same sub-pixel pad `_fitColumnWidths` adds against ellipsis. */\n _autoWidth(natural, opts = {}) {\n const max = opts.maxWidth ?? AUTOSIZE_MAX_PX;\n return Math.min(max, Math.max(40, Math.ceil((natural || 0) + 2)));\n }\n\n /**\n * Does every one of the `n` DOM columns already carry an override taken\n * against the column set that is on screen right now?\n *\n * The signature half is not belt-and-braces. `render()` drops `_colWidths`\n * when `_colSig` changes, but `_syncHeaderWidths` is also reached straight\n * from the ResizeObserver, which never goes through `render()` \u2014 so a set\n * of overrides measured against the PREVIOUS headers can still be sitting\n * in `_colWidths` when this is asked. Answering \"pinned\" then would skip\n * the measure and hand `_fitColumnWidths` widths keyed to columns that are\n * no longer there, each one landing on its neighbour.\n *\n * `== null` rather than a falsy test, to match `_fitColumnWidths`' own\n * `overrides[i] != null`: a legitimately-stored 0 must be read the same way\n * in both places or the two disagree about which columns are flexible.\n */\n _allColumnsPinned(n) {\n if (!n || this._colWidthsSig !== this._colSig()) return false;\n for (let i = 0; i < n; i++) {\n if (this._colWidths[i] == null) return false;\n }\n return true;\n }\n\n /** Sync the (separate) header table's column widths to the body\n * table's measured widths. Without this, the two tables compute\n * widths independently and the columns drift apart. Locks both\n * tables to `table-layout: fixed` and writes explicit width onto\n * each header cell of every header row (header + filter row). */\n _syncHeaderWidths() {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable || !bodyTable) return;\n // C10. UNDER `virtualize` THE COLUMN TRACK IS THE `<colgroup>`, and the\n // column count is ITS length \u2014 not the first row's, which is whatever\n // row the window happens to start at (or a spacer). Without it, the\n // first ROW OF DATA; see `_firstBodyRow` for why not merely the first `<tr>`.\n const cols = this._cols();\n const firstRow = this._firstBodyRow();\n const bodyCells = cols ? [] : firstRow?.children;\n const n = cols ? cols.length : (bodyCells?.length || 0);\n if (!n) return;\n\n const headerRows = headerTable.querySelectorAll('thead > tr');\n // DO NOT MEASURE WHAT NOTHING WILL READ.\n //\n // `_measureNaturalWidths` flips BOTH tables to\n // `table-layout:auto; width:max-content` with the CSS caps lifted, for\n // a full synchronous reflow (`.twm-dt-measuring`, css/base.css). This\n // method is the ResizeObserver's callback, so that reflow fires once\n // per animation frame for the whole of a splitter drag \u2014 and an\n // embedder that pages a thousand rows at a time across twenty columns\n // re-lays-out ~20,000 cells per frame for it.\n //\n // When every column is pinned, `_fitColumnWidths` reads `natural[i]`\n // for no `i` at all: each column takes its override verbatim, and the\n // only thing left that the array supplies is `n`, which is its length.\n // So zeroes of the right length are not an approximation of the\n // measurement, they are indistinguishable from it.\n const natural = this._allColumnsPinned(n)\n ? new Array(n).fill(0)\n : this._measureNaturalWidths();\n if (!natural) return;\n\n // \u2500\u2500 Fit pass: turn natural widths into final widths that respect\n // the available space, favour the first column, and cap runaways.\n // User-dragged columns (`_colWidths`) are honored as-is inside.\n const wrap = this._tableWrapEl;\n const headerWrap = this._headerWrapEl;\n const avail = wrap ? wrap.clientWidth : 0;\n const firstIdx = this.config.showRowNumbers && n > 1 ? 1 : 0;\n const widths = this._fitColumnWidths(natural, avail, {\n firstIdx,\n overrides: this._colWidths,\n fit: this.config.columnFit,\n });\n const total = widths.reduce((a, b) => a + b, 0);\n\n // Apply measured widths to every header row at the matching\n // column index AND the body's first row, so both tables compute\n // the SAME column track. `_setCellWidth` also clears any CSS\n // min/max-width (e.g. the 150px-pinned first \"time\" column) so\n // the explicit width is actually honored.\n headerRows.forEach((tr) => {\n for (let i = 0; i < tr.children.length && i < widths.length; i++) {\n this._setCellWidth(tr.children[i], widths[i]);\n }\n });\n if (cols) {\n for (let i = 0; i < cols.length && i < widths.length; i++) {\n cols[i].style.width = `${widths[i]}px`;\n }\n } else {\n for (let i = 0; i < bodyCells.length && i < widths.length; i++) {\n this._setCellWidth(bodyCells[i], widths[i]);\n }\n }\n\n // Lock both tables so the widths stick even when content changes.\n headerTable.style.tableLayout = 'fixed';\n bodyTable.style.tableLayout = 'fixed';\n\n // Size both tables to the explicit column TOTAL (not the CSS\n // `width: 100%`) so a widened column GROWS the table and the\n // body wrap scrolls horizontally, instead of squeezing into a\n // fixed budget and stealing from its neighbours. When the\n // columns fit and the user hasn't dragged, stay at 100% to fill\n // the container exactly with no phantom scrollbar.\n const hasOverride = Object.keys(this._colWidths).length > 0;\n if (hasOverride || total > avail + 1) {\n headerTable.style.width = `${total}px`;\n bodyTable.style.width = `${total}px`;\n } else {\n headerTable.style.width = '';\n bodyTable.style.width = '';\n }\n\n // Scrollbar gutter: when the body shows a vertical scrollbar, its\n // content is narrower than the wrap by `scrollbarW`. The header\n // wrap has no scrollbar, so pad it on the right to match.\n //\n // C29b. AND THE SAME NUMBER IS PUBLISHED AS A CUSTOM PROPERTY, because\n // padding does not help the one thing C29 was for. A `position: sticky`\n // cell pins to its scroll container's SCROLLPORT, and the scrollport of\n // a box with a classic scrollbar excludes that scrollbar while padding\n // is inside it \u2014 so `right: 0` in the body pins `sbw` px to the LEFT of\n // `right: 0` in the header, and a pinned trailing column would sit\n // visibly out of line with its own heading. There is nothing a\n // stylesheet can measure this from: it is the platform's scrollbar\n // width, known here and nowhere else. Written on the WRAPPER rather\n // than either box so a consumer's rule can read it from whichever of\n // the two it is styling, and written on every sync because a scrollbar\n // appears and disappears with the row count.\n if (wrap && headerWrap) {\n const sbw = Math.max(0, wrap.offsetWidth - wrap.clientWidth);\n headerWrap.style.paddingRight = sbw ? `${sbw}px` : '';\n this._wrapperEl?.style?.setProperty('--twm-dt-gutter', `${sbw}px`);\n }\n\n // Keep the header aligned with the body's current horizontal\n // scroll (a resize can clamp scrollLeft).\n this._syncHeaderScroll();\n\n // Columns are now fixed-width: any cell whose text was clipped\n // gets a hover tooltip carrying the full value.\n this._updateCellTooltips();\n }\n\n /**\n * Convert measured natural content widths into final column widths.\n *\n * Goals (the \"intelligent\" sizing):\n * - every column wants its content width (+a hair), clamped to a\n * sane [floor, cap]; the FIRST content column gets a more generous\n * cap so it shows its full value;\n * - user-dragged columns (`overrides`) are pinned, never grown/shrunk;\n * - if everything fits, grow the flexible columns evenly to fill the\n * width (no dead gap on the right);\n * - if it doesn't fit, protect the first column and water-fill-shrink\n * the rest (trim the widest first) until it fits; only if even the\n * floors overflow do we give up and let the body scroll sideways.\n *\n * Under `fit: 'content'` the first and last of those goals invert: each\n * unpinned column asks for its own content width through the same\n * `_autoWidth` the grip double-click uses, and an overflow is the answer\n * rather than a problem \u2014 the caller wanted a table that scrolls sideways,\n * not one squeezed toward the floor. The grow-to-fill branch is shared by\n * both, because a table narrower than its container leaves a dead gap on\n * the right under either reading.\n *\n * @param {number[]} natural measured content width per column (px)\n * @param {number} avail usable width of the body wrap (px)\n * @param {{firstIdx?:number, overrides?:Object, fit?:'container'|'content'}} [opts]\n * @returns {number[]} final width per column (px)\n */\n _fitColumnWidths(natural, avail, opts = {}) {\n const FLOOR = 40; // matches the drag-resize minimum\n const CAP = 360; // general per-column ceiling\n const FIRST_CAP = 520; // the first column may run wider\n const PAD = 2; // sub-pixel safety against ellipsis\n\n const n = natural.length;\n const firstIdx = opts.firstIdx ?? 0;\n const overrides = opts.overrides || {};\n // Anything that is not the literal opt-in is the historical behaviour.\n // Read once, so an embedder that passes a typo gets the old layout\n // rather than half of each.\n const toContent = opts.fit === 'content';\n\n // Desired (pre-fit) width per column. Pinned columns take their\n // override verbatim and sit out the grow/shrink redistribution.\n const desired = new Array(n);\n const pinned = new Array(n).fill(false);\n for (let i = 0; i < n; i++) {\n if (overrides[i] != null) {\n desired[i] = Math.max(FLOOR, Math.round(overrides[i]));\n pinned[i] = true;\n continue;\n }\n if (toContent) {\n // THE SAME CALL THE GRIP DOUBLE-CLICK MAKES \u2014 `autoSizeColumn`\n // \u2192 `_autoWidth` \u2014 and deliberately not a second arithmetic\n // that happens to agree with it today. Two width formulas\n // drift, and the drift shows up as a column that jumps the\n // first time anyone double-clicks its grip.\n //\n // FIRST_CAP has nothing to say here. It exists to favour one\n // column while the others are being squeezed; under a content\n // fit nothing is being squeezed, so there is no column to\n // favour and every one of them is held to the same ceiling.\n desired[i] = this._autoWidth(natural[i]);\n continue;\n }\n const cap = i === firstIdx ? FIRST_CAP : CAP;\n desired[i] = Math.min(cap, Math.max(FLOOR, Math.ceil(natural[i] + PAD)));\n }\n\n const widths = desired.slice();\n const sum = widths.reduce((a, b) => a + b, 0);\n\n // Not laid out yet (or content already exactly fits): hand back the\n // desired widths; the caller decides fill vs horizontal scroll.\n if (avail <= 1) return widths;\n\n if (sum <= avail) {\n // Grow flexible columns evenly to fill the remaining space so\n // the table doesn't leave a dead gap on the right. When EVERY\n // column is pinned (e.g. after the user has dragged a column \u2014\n // the resize freezes all columns as overrides), fall back to\n // the last column so the table still spans the full container:\n // the width invariant \u2014 a table never renders narrower than\n // 100% of its wrap.\n const flex = [];\n for (let i = 0; i < n; i++) if (!pinned[i]) flex.push(i);\n const slack = avail - sum;\n if (slack > 0) {\n const targets = flex.length ? flex : [n - 1];\n const per = Math.floor(slack / targets.length);\n for (const i of targets) widths[i] += per;\n widths[targets[targets.length - 1]] += slack - per * targets.length;\n }\n return widths;\n }\n\n // OVERFLOW IS THE ANSWER UNDER A CONTENT FIT, not a case to recover\n // from. Everything below squeezes the unprotected columns toward the\n // 40px floor so that forty columns can be made to fit a pane \u2014 which is\n // precisely the outcome `columnFit: 'content'` opted out of. Handing\n // back the content widths lets the caller's `total > avail + 1` test\n // size both tables to the total, and the body wrap then scrolls\n // sideways with the header following it.\n if (toContent) return widths;\n\n // Overflow: protect the first column + pinned columns, water-fill\n // the rest down toward the floor.\n let protectedSum = 0;\n const shrinkable = [];\n for (let i = 0; i < n; i++) {\n if (pinned[i] || i === firstIdx) protectedSum += widths[i];\n else shrinkable.push(i);\n }\n const budget = avail - protectedSum;\n if (budget < shrinkable.length * FLOOR) {\n // Even at the floor we overflow \u2192 let the body scroll sideways.\n for (const i of shrinkable) widths[i] = FLOOR;\n return widths;\n }\n // Max-min fair allocation: the narrow columns keep their content,\n // the widest share the remaining budget equally.\n shrinkable.sort((a, b) => desired[a] - desired[b]);\n let remaining = budget;\n for (let k = 0; k < shrinkable.length; k++) {\n const colsLeft = shrinkable.length - k;\n const fair = Math.floor(remaining / colsLeft);\n const i = shrinkable[k];\n if (desired[i] <= fair) {\n widths[i] = desired[i];\n remaining -= desired[i];\n } else {\n const level = Math.max(FLOOR, fair);\n for (let j = k; j < shrinkable.length; j++) {\n widths[shrinkable[j]] = level;\n }\n // Dump any rounding remainder onto the widest column.\n const leftover = remaining - colsLeft * level;\n if (leftover > 0) widths[shrinkable[shrinkable.length - 1]] += leftover;\n break;\n }\n }\n return widths;\n }\n\n /** Set an explicit width on a table cell, clearing any CSS min/max\n * width constraint so the width is honored exactly. The first\n * (\"time\") column is pinned to 150px by `min/max-width` in CSS;\n * without this, dragging it does nothing and the slack leaks to the\n * other columns. */\n _setCellWidth(cell, w) {\n cell.style.width = `${w}px`;\n cell.style.minWidth = '0';\n cell.style.maxWidth = 'none';\n }\n\n /** Undo `_setCellWidth` so a re-measure sees the cell's natural,\n * CSS-constrained width again. */\n _clearCellWidth(cell) {\n cell.style.width = '';\n cell.style.minWidth = '';\n cell.style.maxWidth = '';\n }\n\n /** Wire the body wrap's horizontal scroll to the header. The header\n * sits in an overflow:hidden wrap, so it can't scroll sideways on\n * its own \u2014 `_syncHeaderScroll` scrolls it programmatically to the\n * body's `scrollLeft`. Re-installed each render against the freshly-built\n * wrap. */\n _installHeaderScrollSync() {\n const wrap = this._tableWrapEl;\n if (!wrap) return;\n if (this._onBodyScroll && this._scrollSyncEl) {\n this._scrollSyncEl.removeEventListener('scroll', this._onBodyScroll);\n }\n this._onBodyScroll = () => this._syncHeaderScroll();\n this._scrollSyncEl = wrap;\n wrap.addEventListener('scroll', this._onBodyScroll, { passive: true });\n this._syncHeaderScroll();\n }\n\n /**\n * Scroll the header wrap to match the body's horizontal scroll so the\n * columns stay aligned when the table overflows sideways.\n *\n * \u2550\u2550 C29. A TRANSFORM IS WHAT MAKES A STICKY COLUMN IMPOSSIBLE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * This wrote `headerTable.style.transform = translateX(-scrollLeft)`. It\n * aligns the two tables perfectly and it forecloses `position: sticky`\n * entirely, because the two halves of the table then pin against different\n * things: a sticky cell in the BODY pins to the body wrap's scrollport,\n * while its header counterpart is moved by a transform inside a box that\n * never scrolls at all. Scroll sideways and the pinned body column stands\n * still while its header slides away with everything else \u2014 so a table\n * with a trailing verb column (the row-actions column Tables needs pinned\n * to the right edge) can have a sticky body or an aligned header, never\n * both. A transform also establishes a containing block for fixed/sticky\n * descendants, which breaks the header cell independently of the offset.\n *\n * AN `overflow: hidden` BOX IS STILL A SCROLL CONTAINER. It has no\n * scrollbar and no user affordance, and `scrollLeft` moves it exactly like\n * any other. Scrolling the wrap rather than transforming its child gives\n * the header a real scrollport at the same offset as the body's, which is\n * the one arrangement in which a sticky cell on each side pins to the same\n * place. Identical for ordinary content: same pixels, no transform, no new\n * containing block.\n *\n * THE CLAMP IS ALREADY PAID FOR. A scroll container clamps `scrollLeft` to\n * `scrollWidth - clientWidth`, and the body wrap carries a vertical\n * scrollbar the header wrap does not \u2014 so the header would clamp short by\n * the scrollbar width and desync at the far right. `_syncHeaderWidths`\n * already pads the header wrap by exactly that gutter (`paddingRight`,\n * :1905), and end padding counts toward `scrollWidth`, so the two maxima\n * coincide. The residual below is the honest belt for the day some engine\n * disagrees about that: it is zero in the ordinary case, so the transform\n * is not set and sticky keeps working, and it is the difference rather\n * than the whole offset if it is ever not.\n */\n _syncHeaderScroll() {\n const wrap = this._tableWrapEl;\n const headerTable = this._headerTableEl;\n if (!wrap || !headerTable) return;\n const x = wrap.scrollLeft;\n const headerWrap = this._headerWrapEl;\n if (!headerWrap) {\n // No wrap to scroll \u2014 a consumer that built the header some other\n // way still gets the behaviour it always had.\n headerTable.style.transform = x ? `translateX(${-x}px)` : '';\n return;\n }\n headerWrap.scrollLeft = x;\n const residual = x - headerWrap.scrollLeft;\n headerTable.style.transform = residual ? `translateX(${-residual}px)` : '';\n }\n\n /** Drag-to-resize: hang a thin grab handle off the right edge of\n * every header cell. Dragging it writes a per-column width override\n * (keyed by DOM index) that `_syncHeaderWidths` then honors. */\n _installColumnResizers() {\n const headerTable = this._headerTableEl;\n if (!headerTable) return;\n const headRow = headerTable.querySelector('thead > tr');\n if (!headRow) return;\n [...headRow.children].forEach((th, domIdx) => {\n if (th.querySelector('.twm-dt-col-resizer')) return;\n th.classList.add('twm-dt-col');\n const grip = document.createElement('div');\n grip.className = 'twm-dt-col-resizer';\n grip.addEventListener('mousedown',\n (ev) => this._beginColResize(ev, domIdx));\n // Keep a resize gesture from registering as a sort click.\n grip.addEventListener('click', (ev) => ev.stopPropagation());\n // Double-click the grip: fit the column to its content. The gesture\n // every spreadsheet has, on the affordance it has always been on.\n // Stopped as well as prevented, or a consumer that opens a column\n // menu from the header (Tables does) opens it on the way past.\n grip.addEventListener('dblclick', (ev) => {\n ev.preventDefault();\n ev.stopPropagation();\n this.autoSizeColumn(domIdx);\n });\n th.appendChild(grip);\n });\n }\n\n /**\n * CSS px per screen px. Content inside a zoomed tile reports rects and\n * pointer coordinates in screen pixels, while `style.width` is CSS pixels;\n * mixing them widened every column by the zoom factor on a mere click.\n */\n _zoomFactor() {\n const el = this._tableWrapEl || this._tableEl;\n const css = el?.offsetWidth || 0;\n const screen = el?.getBoundingClientRect?.().width || 0;\n return css > 0 && screen > 0 ? screen / css : 1;\n }\n\n _beginColResize(ev, domIdx) {\n if (ev.button != null && ev.button !== 0) return;\n ev.preventDefault();\n ev.stopPropagation();\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n const headRow = headerTable && headerTable.querySelector('thead > tr');\n if (!headRow) return;\n\n // NOTHING HAPPENS UNTIL THE POINTER MOVES. Freezing on mousedown pinned\n // every column on a plain click, and the first click of a double-click,\n // so a click on a grip was already a resize and switched auto-fit off\n // for every column for good.\n //\n // Once the drag is real: freeze EVERY column at its current width on\n // BOTH tables and lock fixed layout, so the drag moves only the grabbed\n // column and a neighbour can never absorb it. Widths come from the\n // header row (the column source of truth), in CSS pixels.\n const startX = ev.clientX;\n const THRESHOLD = 3;\n const MIN = 40;\n let startWidths = null;\n const begin = () => {\n const z = this._zoomFactor();\n startWidths = [...headRow.children].map((c) => {\n const set = parseFloat(c.style.width);\n return Number.isFinite(set) ? set : c.getBoundingClientRect().width / z;\n });\n headerTable.style.tableLayout = 'fixed';\n if (bodyTable) bodyTable.style.tableLayout = 'fixed';\n startWidths.forEach((w, i) => this._pinColumnWidth(i, w));\n this._applyTableWidth();\n document.body.classList.add('twm-dt-col-resizing');\n };\n const onMove = (mv) => {\n const dx = mv.clientX - startX;\n if (!startWidths) {\n if (Math.abs(dx) < THRESHOLD) return;\n begin();\n }\n const w = Math.max(MIN, Math.round(startWidths[domIdx] + dx / this._zoomFactor()));\n this._pinColumnWidth(domIdx, w);\n // Pass the dragged column so the fill invariant reclaims any\n // freed width into a DIFFERENT (flexible/last) column, never\n // shrinking the table below the container.\n this._applyTableWidth(domIdx);\n this._syncHeaderScroll();\n };\n const onUp = () => {\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n if (!startWidths) return; // a click: nothing changed\n document.body.classList.remove('twm-dt-col-resizing');\n this._updateCellTooltips();\n this._savePersisted();\n };\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n }\n\n /** Pin one column to an explicit width across BOTH tables (every\n * header row + the body's first row) and record it as a user\n * override so `_syncHeaderWidths` honors it on later renders. The\n * single place that writes a column width during a drag / fill. */\n _pinColumnWidth(i, w) {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n if (!headerTable) return;\n this._colWidths[i] = w;\n headerTable.querySelectorAll('thead > tr').forEach((tr) => {\n if (tr.children[i]) this._setCellWidth(tr.children[i], w);\n });\n // C10: the `<col>` is the track; without one, the first row of data.\n const cols = this._cols();\n if (cols) {\n if (cols[i]) cols[i].style.width = `${w}px`;\n return;\n }\n const bodyRow = bodyTable && this._firstBodyRow();\n if (bodyRow && bodyRow.children[i]) this._setCellWidth(bodyRow.children[i], w);\n }\n\n /** Size both tables so a widened column grows the table (\u2192 horizontal\n * scroll) rather than stealing from its neighbours \u2014 while enforcing\n * the TABLE WIDTH INVARIANT: the table is never narrower than its\n * container. Any width freed by dragging a column in stretches a\n * flexible column (the last one, stepping off the column being\n * dragged) so the table always spans \u2265100% of the wrap.\n *\n * @param {number|null} dragIdx column the user is actively dragging,\n * so the fill lands on a DIFFERENT column and doesn't fight the\n * drag. Null (non-drag callers) lets the last column flex. */\n _applyTableWidth(dragIdx = null) {\n const headerTable = this._headerTableEl;\n const bodyTable = this._tableEl;\n const headRow = headerTable && headerTable.querySelector('thead > tr');\n if (!headRow) return;\n const cells = [...headRow.children];\n const cols = cells.length;\n if (cols === 0) return;\n\n const FLOOR = 40; // matches the drag-resize minimum\n const widthOf = (th) => {\n const px = parseFloat(th.style.width);\n return Number.isFinite(px) ? px : th.getBoundingClientRect().width;\n };\n const cur = cells.map(widthOf);\n\n // Fill invariant: pick a flexible column and stretch it to soak up\n // any freed width so the summed total is never below the container.\n const wrap = this._tableWrapEl;\n const avail = wrap ? wrap.clientWidth : 0;\n let flexIdx = cols - 1;\n if (dragIdx != null && flexIdx === dragIdx) flexIdx -= 1; // step off the dragged col\n if (avail > 1 && flexIdx >= 0 && flexIdx !== dragIdx) {\n let rest = 0;\n for (let i = 0; i < cols; i++) if (i !== flexIdx) rest += cur[i];\n const fill = Math.max(FLOOR, Math.round(avail - rest));\n if (Math.round(fill) !== Math.round(cur[flexIdx])) {\n this._pinColumnWidth(flexIdx, fill);\n cur[flexIdx] = fill;\n }\n }\n\n let total = 0;\n for (const w of cur) total += w;\n total = Math.ceil(total);\n headerTable.style.width = `${total}px`;\n if (bodyTable) bodyTable.style.width = `${total}px`;\n }\n\n /** Add a native `title` tooltip to any body cell whose text is\n * clipped by its column width; remove ours once it fits again.\n * Leaves caller-supplied titles (e.g. from renderCell) untouched. */\n _updateCellTooltips(rows = null) {\n const bodyTable = this._tableEl;\n if (!bodyTable) return;\n // `rows`: only these (C10 \u2014 the rows a window slide just added).\n const cells = rows\n ? rows.flatMap((tr) => [...tr.children])\n : bodyTable.querySelectorAll('tbody td');\n cells.forEach((td) => {\n if (td.parentElement?.classList.contains('twm-dt-spacer')) return;\n const clipped = td.scrollWidth > td.clientWidth + 1;\n if (clipped) {\n if (!td.title) td.title = td.textContent;\n } else if (td.title && td.title === td.textContent) {\n td.removeAttribute('title');\n }\n });\n }\n\n _installInteractions() {\n if (!this._tbodyEl || !this._tableEl) return;\n\n const { selectable, copyable } = this.config;\n const tbody = this._tbodyEl;\n const table = this._tableEl;\n\n if (selectable) {\n const handleRowClick = (event) => {\n const rowEl = event.target.closest('tr');\n if (!rowEl || rowEl.__rowIndex === undefined) return;\n\n const idx = rowEl.__rowIndex;\n const selected = this._state.selected;\n\n if (selectable === 'single') {\n // 0.5.0. One row, whatever the modifiers say: Ctrl takes\n // the one row back off, nothing extends it.\n const was = selected.has(idx);\n selected.clear();\n if (!(was && (event.metaKey || event.ctrlKey))) selected.add(idx);\n else DESELECTING_CLICKS.add(event); // so it does not ALSO open it\n this._state.anchorIndex = selected.size ? idx : null;\n } else if (event.shiftKey && this._state.anchorIndex != null) {\n const start = Math.min(this._state.anchorIndex, idx);\n const end = Math.max(this._state.anchorIndex, idx);\n selected.clear();\n for (let i = start; i <= end; i++) selected.add(i);\n } else if (event.metaKey || event.ctrlKey) {\n if (selected.has(idx)) selected.delete(idx);\n else selected.add(idx);\n this._state.anchorIndex = idx;\n } else {\n selected.clear();\n selected.add(idx);\n this._state.anchorIndex = idx;\n }\n\n this._updateRowSelection();\n this._notifySelectionChange();\n try { table.focus({ preventScroll: true }); } catch (_) {}\n };\n\n tbody.addEventListener('click', handleRowClick);\n this._disposers.push(() => tbody.removeEventListener('click', handleRowClick));\n }\n\n // 0.5.0 `onRowActivate`. Bound AFTER the selection handler on the same\n // element, so a row is selected before it is opened \u2014 the listener\n // order is the guarantee. `onRowClick` stays exactly where it was (on\n // the `<tr>`, before the selection), for whoever already relies on that.\n if (typeof this.config.onRowActivate === 'function') {\n this._installActivation(tbody, table);\n }\n\n if (copyable) {\n const handleContextMenu = (event) => {\n const rowEl = event.target.closest('tr');\n if (!rowEl) {\n this._hideContextMenu();\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n const idx = rowEl.__rowIndex;\n if (idx !== undefined && !this._state.selected.has(idx)) {\n this._state.selected.clear();\n this._state.selected.add(idx);\n this._state.anchorIndex = idx;\n this._updateRowSelection();\n this._notifySelectionChange();\n }\n\n try { table.focus({ preventScroll: true }); } catch (_) {}\n setTimeout(() => this._showContextMenu(event.clientX, event.clientY), 0);\n };\n\n tbody.addEventListener('contextmenu', handleContextMenu);\n this._disposers.push(() => tbody.removeEventListener('contextmenu', handleContextMenu));\n\n const handleKeyDown = (event) => {\n const ctrlLike = event.ctrlKey || event.metaKey;\n if (ctrlLike && !event.altKey) {\n const key = String(event.key || '').toLowerCase();\n if (key === 'a' && selectable === 'single') {\n // 0.5.0. Nothing to select all of \u2014 and not the page's\n // text either.\n event.preventDefault();\n } else if (key === 'a' && selectable) {\n event.preventDefault();\n this._state.selected.clear();\n // Select only visible (filtered) rows via index map\n const indexMap = this._processedIndexMap;\n if (indexMap) {\n for (const originalIdx of indexMap) {\n this._state.selected.add(originalIdx);\n }\n } else {\n for (let i = 0; i < this.config.rows.length; i++) {\n this._state.selected.add(i);\n }\n }\n this._state.anchorIndex = this.config.rows.length - 1;\n this._updateRowSelection();\n this._notifySelectionChange();\n } else if (key === 'c') {\n event.preventDefault();\n this.copyToClipboard(event.shiftKey ? 'csv' : 'tsv');\n }\n } else if (event.key === 'Escape') {\n if (this._state.selected.size) {\n this.clearSelection();\n }\n this._hideContextMenu();\n }\n };\n\n table.addEventListener('keydown', handleKeyDown);\n this._disposers.push(() => table.removeEventListener('keydown', handleKeyDown));\n }\n }\n\n _updateRowSelection() {\n if (!this._tbodyEl) return;\n this._tbodyEl.querySelectorAll('tr').forEach(tr => {\n const idx = tr.__rowIndex;\n if (idx !== undefined) {\n tr.classList.toggle('selected', this._state.selected.has(idx));\n }\n });\n }\n\n _notifySelectionChange() {\n this.config.onSelectionChange?.(this.getSelection());\n }\n\n _ensureContextMenu() {\n if (this._contextMenuEl) return this._contextMenuEl;\n\n const menu = document.createElement('div');\n menu.className = 'twm-context-menu data-context-menu';\n menu.style.display = 'none';\n menu.style.position = 'fixed';\n menu.style.zIndex = '10001';\n menu.innerHTML = `\n <div class=\"twm-context-menu-item\" data-action=\"copy-tsv\">\n <span class=\"material-symbols-outlined\">content_copy</span>\n <span class=\"label\">Copy Row(s)</span>\n </div>\n <div class=\"twm-context-menu-item\" data-action=\"copy-csv\">\n <span class=\"material-symbols-outlined\">table</span>\n <span class=\"label\">Copy as CSV</span>\n </div>\n `;\n document.body.appendChild(menu);\n\n menu.addEventListener('click', (event) => {\n const item = event.target.closest('.twm-context-menu-item');\n if (!item || item.classList.contains('disabled')) return;\n const action = item.getAttribute('data-action');\n if (action === 'copy-tsv') this.copyToClipboard('tsv');\n else if (action === 'copy-csv') this.copyToClipboard('csv');\n event.stopPropagation();\n event.preventDefault();\n }, { capture: true });\n\n menu.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n });\n\n this._contextMenuEl = menu;\n return menu;\n }\n\n /**\n * The document-level listeners that close the copy menu \u2014 a click\n * elsewhere, a scroll, Escape, a resize \u2014 held ONLY WHILE IT IS OPEN\n * (0.5.0). They were installed the first time the menu was built and kept\n * until `dispose()`, so every table anybody had ever right-clicked kept four\n * listeners on the document for as long as the instance lived, and an\n * instance whose host was thrown away without a `dispose()` kept them for\n * the life of the page. A closed menu has nothing for them to do.\n */\n _armContextMenuGlobals() {\n if (this._contextMenuGlobals.length) return;\n const menu = this._contextMenuEl;\n const hideOnGlobal = (event) => {\n if (event?.target && menu?.contains(event.target)) return;\n this._hideContextMenu();\n };\n const hideOnEscape = (event) => {\n if (event.key === 'Escape') this._hideContextMenu();\n };\n const hideOnResize = () => this._hideContextMenu();\n\n document.addEventListener('click', hideOnGlobal, true);\n document.addEventListener('scroll', hideOnGlobal, true);\n window.addEventListener('resize', hideOnResize);\n document.addEventListener('keydown', hideOnEscape);\n\n this._contextMenuGlobals.push(() => document.removeEventListener('click', hideOnGlobal, true));\n this._contextMenuGlobals.push(() => document.removeEventListener('scroll', hideOnGlobal, true));\n this._contextMenuGlobals.push(() => document.removeEventListener('keydown', hideOnEscape));\n this._contextMenuGlobals.push(() => window.removeEventListener('resize', hideOnResize));\n }\n\n _disarmContextMenuGlobals() {\n this._contextMenuGlobals.forEach((off) => {\n try { off?.(); } catch (_) { /* already gone */ }\n });\n this._contextMenuGlobals = [];\n }\n\n _hideContextMenu() {\n if (this._contextMenuEl) {\n this._contextMenuEl.style.display = 'none';\n }\n this._disarmContextMenuGlobals();\n }\n\n _showContextMenu(clientX, clientY) {\n const menu = this._ensureContextMenu();\n this._armContextMenuGlobals();\n const hasSelection = this._state.selected.size > 0;\n\n menu.querySelectorAll('.twm-context-menu-item').forEach(item => {\n item.classList.toggle('disabled', !hasSelection);\n item.style.pointerEvents = hasSelection ? '' : 'none';\n });\n\n menu.style.display = 'block';\n const rect = menu.getBoundingClientRect();\n let left = clientX;\n let top = clientY;\n\n if (left + rect.width > window.innerWidth) {\n left = window.innerWidth - rect.width - 8;\n }\n if (top + rect.height > window.innerHeight) {\n top = window.innerHeight - rect.height - 8;\n }\n\n menu.style.left = `${left}px`;\n menu.style.top = `${top}px`;\n }\n\n _teardownContextMenu() {\n this._contextMenuGlobals.forEach(dispose => {\n try { dispose?.(); } catch (_) {}\n });\n this._contextMenuGlobals = [];\n if (this._contextMenuEl?.parentNode) {\n this._contextMenuEl.parentNode.removeChild(this._contextMenuEl);\n }\n this._contextMenuEl = null;\n }\n\n _formatValue(value, colIndex) {\n // 0.5.0 `nullDisplay`, then a typed column's own words \u2014 each only when\n // asked for, so a table without them formats exactly as 0.4 did.\n if (value == null && this.config.nullDisplay != null) {\n return String(this.config.nullDisplay);\n }\n const typed = this._formatTyped(value, colIndex);\n if (typed !== undefined) return typed;\n if (this.config.formatValue) {\n return this.config.formatValue(value, colIndex);\n }\n if (value === undefined || value === null) return '-';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) return '-';\n return Number(value.toFixed(4)).toString();\n }\n return String(value);\n }\n\n _csvEscape(value) {\n if (value == null) return '';\n const str = String(value);\n if (/[\",\\n]/.test(str)) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n }\n\n _fallbackCopy(text) {\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'absolute';\n textarea.style.left = '-9999px';\n document.body.appendChild(textarea);\n textarea.select();\n const ok = document.execCommand('copy');\n document.body.removeChild(textarea);\n return ok;\n } catch (_) {\n return false;\n }\n }\n\n _notify(title, message, type = 'info') {\n this.config.services?.eventBus?.emit?.('toast:show', { title, message, type });\n }\n}\n\nexport default DataTable;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["p", "target"]
|
|
7
|
+
}
|