Skip to content

Commit

Permalink
Add sortable code
Browse files Browse the repository at this point in the history
  • Loading branch information
pfych committed Jun 6, 2023
1 parent 135fc66 commit 25e8e1a
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ renderTarget.append(

### Table: `sortable?: boolean`

Stub for later, applies a className to the entire table to allow for sorting target
Allows the table to be sortable, will auto-wrap the table in a `createSortableTable()` call. This is exported for other tables, it takes an input of `Element` and returns `void`. Calling will add click handlers & functions to the table.

### Column: `className?: string`

Expand Down
5 changes: 0 additions & 5 deletions build.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const { build } = require('esbuild');
const { Generator } = require('npm-dts');

const shared = {
entryPoints: ['src/index.ts'],
Expand All @@ -17,9 +16,5 @@ const shared = {
outfile: 'dist/index.esm.js',
format: 'esm',
}),
new Generator({
entry: 'src/index.ts',
output: 'dist/index.d.ts',
}).generate(),
]);
})();
33 changes: 14 additions & 19 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
declare module 'simple-table/index' {
import { Column } from 'simple-table/types';
declare module 'simple-table' {
interface Column<T> {
header: string;
accessor: keyof T;
renderer?: (value: T[keyof T], row?: T) => string;
className?: string;
}

const createSortableTable: (table: Element) => void;

const renderTable: <T>(args: {
columns: Column<T>[];
data: T[];
sortable?: boolean;
columns: Column<T>[];
data: T[];
sortable?: boolean;
}) => Element;
export { renderTable, Column };

export { renderTable, createSortableTable, Column };
}
declare module 'simple-table/types' {
export interface Column<T> {
header: string;
accessor: keyof T;
renderer?: (value: T[keyof T], row?: T) => string;
className?: string;
}

}
declare module 'simple-table' {
import main = require('simple-table/src/index');
export = main;
}
43 changes: 42 additions & 1 deletion dist/index.esm.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,45 @@
// src/index.ts
var createSortableTable = (table) => {
let lastClicked = "";
const sortRows = (sortBy, header2, rows2) => {
const allHeaders = [...header2.querySelectorAll("th") || []];
const indexOfSortBy = allHeaders.map((header3) => header3.innerText).indexOf(sortBy);
allHeaders.forEach((header3) => {
header3.style.textDecoration = "none";
header3.style.userSelect = "none";
});
allHeaders[indexOfSortBy].style.textDecoration = "underline";
const sortedRows = rows2.sort((rowA, rowB) => {
const rowAValue = rowA.querySelectorAll("td")[indexOfSortBy].innerText || "z";
const rowBValue = rowB.querySelectorAll("td")[indexOfSortBy].innerText || "z";
const rowAValueSortable = /^[0-9,.:]*$/.test(rowAValue) ? parseInt(rowAValue.replace(/[,:]/g, "")) : rowAValue;
const rowBValueSortable = /^[0-9,.:]*$/.test(rowBValue) ? parseInt(rowBValue.replace(/[,;]/g, "")) : rowBValue;
if (rowAValueSortable > rowBValueSortable) {
return lastClicked === sortBy ? -1 : 1;
}
if (rowAValueSortable < rowBValueSortable) {
return lastClicked === sortBy ? 1 : -1;
}
return 0;
});
lastClicked = lastClicked === sortBy ? "" : sortBy;
const tableBody = rows2[0].parentElement;
tableBody.innerHTML = "";
tableBody.append(...sortedRows);
};
const header = table.querySelector("thead tr");
const rows = [...table.querySelectorAll("tbody tr") || []];
header.querySelectorAll("th").forEach((node) => {
node.style.setProperty("cursor", "pointer");
node.addEventListener(
"click",
() => sortRows(node.innerText, header, rows)
);
});
};
var renderTable = (args) => {
const { columns, data, sortable } = args;
const wrapper = document.createElement("div");
wrapper.className = sortable ? "sortable" : "";
const table = document.createElement("table");
const header = document.createElement("thead");
const body = document.createElement("tbody");
Expand All @@ -29,8 +66,12 @@ var renderTable = (args) => {
});
body.append(row);
});
if (sortable) {
createSortableTable(table);
}
return wrapper;
};
export {
createSortableTable,
renderTable
};
42 changes: 41 additions & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
(() => {
// src/index.ts
var createSortableTable = (table) => {
let lastClicked = "";
const sortRows = (sortBy, header2, rows2) => {
const allHeaders = [...header2.querySelectorAll("th") || []];
const indexOfSortBy = allHeaders.map((header3) => header3.innerText).indexOf(sortBy);
allHeaders.forEach((header3) => {
header3.style.textDecoration = "none";
header3.style.userSelect = "none";
});
allHeaders[indexOfSortBy].style.textDecoration = "underline";
const sortedRows = rows2.sort((rowA, rowB) => {
const rowAValue = rowA.querySelectorAll("td")[indexOfSortBy].innerText || "z";
const rowBValue = rowB.querySelectorAll("td")[indexOfSortBy].innerText || "z";
const rowAValueSortable = /^[0-9,.:]*$/.test(rowAValue) ? parseInt(rowAValue.replace(/[,:]/g, "")) : rowAValue;
const rowBValueSortable = /^[0-9,.:]*$/.test(rowBValue) ? parseInt(rowBValue.replace(/[,;]/g, "")) : rowBValue;
if (rowAValueSortable > rowBValueSortable) {
return lastClicked === sortBy ? -1 : 1;
}
if (rowAValueSortable < rowBValueSortable) {
return lastClicked === sortBy ? 1 : -1;
}
return 0;
});
lastClicked = lastClicked === sortBy ? "" : sortBy;
const tableBody = rows2[0].parentElement;
tableBody.innerHTML = "";
tableBody.append(...sortedRows);
};
const header = table.querySelector("thead tr");
const rows = [...table.querySelectorAll("tbody tr") || []];
header.querySelectorAll("th").forEach((node) => {
node.style.setProperty("cursor", "pointer");
node.addEventListener(
"click",
() => sortRows(node.innerText, header, rows)
);
});
};
var renderTable = (args) => {
const { columns, data, sortable } = args;
const wrapper = document.createElement("div");
wrapper.className = sortable ? "sortable" : "";
const table = document.createElement("table");
const header = document.createElement("thead");
const body = document.createElement("tbody");
Expand All @@ -30,6 +67,9 @@
});
body.append(row);
});
if (sortable) {
createSortableTable(table);
}
return wrapper;
};
})();
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-table",
"version": "1.0.0",
"version": "1.0.1",
"description": "",
"main": "dist/index.js",
"module": "dist/index.esm.js",
Expand Down
70 changes: 68 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,75 @@
import { Column } from './types';

const createSortableTable = (table: Element): void => {
let lastClicked = '';

const sortRows = (sortBy: string, header: Element, rows: Element[]) => {
// Discover the selected header
const allHeaders = [...(header.querySelectorAll('th') || [])];
const indexOfSortBy = allHeaders
.map((header) => header.innerText)
.indexOf(sortBy);

// Apply Styles to selected header
allHeaders.forEach((header) => {
header.style.textDecoration = 'none';
header.style.userSelect = 'none';
});
allHeaders[indexOfSortBy].style.textDecoration = 'underline';

// Sort the rows and update the parent
const sortedRows = rows.sort((rowA, rowB) => {
const rowAValue =
rowA.querySelectorAll('td')[indexOfSortBy].innerText || 'z';
const rowBValue =
rowB.querySelectorAll('td')[indexOfSortBy].innerText || 'z';

const rowAValueSortable = /^[0-9,.:]*$/.test(rowAValue)
? parseInt(rowAValue.replace(/[,:]/g, ''))
: rowAValue;

const rowBValueSortable = /^[0-9,.:]*$/.test(rowBValue)
? parseInt(rowBValue.replace(/[,;]/g, ''))
: rowBValue;

if (rowAValueSortable > rowBValueSortable) {
return lastClicked === sortBy ? -1 : 1;
}

if (rowAValueSortable < rowBValueSortable) {
return lastClicked === sortBy ? 1 : -1;
}

return 0;
});

lastClicked = lastClicked === sortBy ? '' : sortBy;

const tableBody = rows[0].parentElement;

tableBody.innerHTML = '';
tableBody.append(...sortedRows);
};

const header = table.querySelector('thead tr');
const rows = [...(table.querySelectorAll('tbody tr') || [])];

// Add Click handlers to headers
header.querySelectorAll('th').forEach((node) => {
node.style.setProperty('cursor', 'pointer');
node.addEventListener('click', () =>
sortRows(node.innerText, header, rows),
);
});
};

const renderTable = <T>(args: {
columns: Column<T>[];
data: T[];
sortable?: boolean;
}): Element => {
const { columns, data, sortable } = args;
const wrapper = document.createElement('div');
wrapper.className = sortable ? 'sortable' : '';

const table = document.createElement('table');
const header = document.createElement('thead');
Expand Down Expand Up @@ -48,7 +110,11 @@ const renderTable = <T>(args: {
body.append(row);
});

if (sortable) {
createSortableTable(table);
}

return wrapper;
};

export { renderTable, Column };
export { renderTable, createSortableTable, Column };

0 comments on commit 25e8e1a

Please sign in to comment.