tblAddRow(tbl, rowData = {}, options = {}) {
    const tblType = Object.prototype.toString.apply(tbl);
    if (Object.prototype.toString.apply(options) !== "[object Object]") throw new Error(`[tblAddDataRow] options must be an object`);
    const dataType = Object.prototype.toString.apply(rowData);
    if (dataType !== "[object Object]" && dataType !== "[object Array]") throw new Error(`[tblAddDataRow] rowData MUST be an object or an array containing column/cell data for each column`);
    let tblEl;
    if (tblType === "[object HTMLTableElement]") {
      tblEl = tbl;
    } else {
      tblEl = _a.doc.querySelector(tbl);
      if (!tblEl) throw new Error(`[tblAddDataRow] Table with CSS Selector "${tbl}" not found`);
    }
    if (!options.body) options.body = 0;
    if (!("allowHTML" in options)) options.allowHTML = false;
    const tbodyEl = tblEl.getElementsByTagName("tbody")[options.body];
    if (!tbodyEl) throw new Error(`[tblAddDataRow] Table must have a tbody tag, tbody section ${options.body} does not exist`);
    if (!options.cols) options.cols = this.tblGetColMeta(tblEl);
    const colMeta = options.cols;
    const rowEl = _a.doc.createElement("tr");
    if (options.rowId) rowEl.id = options.rowId;
    const cols = [];
    for (const col of colMeta) {
      const cellEl = _a.doc.createElement("td");
      cellEl.colMeta = col;
      if (col.hasName) cellEl.dataset.colName = col.name;
      cols.push(cellEl);
    }
    Object.keys(rowData).forEach((colKey, i, row) => {
      let foundEl = cols.find((col) => col?.colMeta?.name === colKey);
      let foundRowData;
      if (foundEl) {
        foundRowData = rowData[colKey];
      } else {
        let numColKey = Number(colKey);
        if (isNaN(numColKey)) numColKey = i;
        if (numColKey <= cols.length - 1) {
          foundEl = cols[numColKey];
          foundRowData = Object.values(rowData)[numColKey];
        }
      }
      if (foundEl) {
        if (options.allowHTML) foundEl.innerHTML = this.sanitiseHTML(foundRowData);
        else foundEl.textContent = foundRowData;
      }
    });
    rowEl.append(...cols);
    if ("afterRow" in options) {
      const afterRow = tbodyEl.rows[options.afterRow];
      if (afterRow) return afterRow.after(rowEl);
    } else if ("beforeRow" in options) {
      const beforeRow = tbodyEl.rows[options.beforeRow];
      if (beforeRow) return beforeRow.before(rowEl);
    } else if ("replaceRow" in options) {
      const replaceRow = tbodyEl.rows[options.replaceRow];
      if (replaceRow) return replaceRow.replaceWith(rowEl);
    }
    return tbodyEl.appendChild(rowEl);
  }
Adds (or replaces) a single row in an existing table>tbody
NOTE: Row numbers use the rowIndex property of the row element.
@param {string|HTMLTableElement} tbl Either a CSS Selector for the table or a reference to the HTML Table Element
@param {object|Array} rowData A single row of column/cell data
@param {object} [options] Additional options
 @param {number=} options.body Optional, default=0. The tbody section to add the row to.
 @param {boolean=} options.allowHTML Optional, default=false. If true, allows HTML cell content, otherwise only allows text. Always sanitise HTML inputs
 @param {string=} options.rowId Optional. HTML element ID for the added row
 @param {number=} options.afterRow Optional. If provided, the new row will be added after this row number
 @param {number=} options.beforeRow Optional. If provided, the new row will be added before this row number. Ignored if afterRow is provided
 @param {number=} options.replaceRow Optional. If provided, the specified row will be REPLACED instead of added. Ignored if afterRow or beforeRow is provided
 @param {Array<columnDefinition>} [options.cols] Optional. Data about each column. If not provided, will be calculated from the table

@returns {HTMLTableRowElement} Reference to the newly added row. Use the `rowIndex` prop for the row number