Public
Edited
Oct 16, 2024
3 forks
Importers
12 stars
Insert cell
Insert cell
viewof demo = table(await require("@observablehq/cars"))
Insert cell
table = (data = [], options = {}) => {
if (data.length === 0) return html``;
const columnHeaders = [
...data.reduce((result, row) => {
Object.keys(row).forEach((key) => {
result.add(key);
});
return result;
}, new Set())
];
let columns = columnHeaders.map((columnHeader) => ({
data: columnHeader
}));
if (options.sort) {
const index = columnHeaders.indexOf(options.sort) || 0;
options.columnSorting = {
initialConfig: { column: index, sortOrder: options.sortOrder || "asc" }
};
delete options.sort;
}
if (options.columns) {
if (typeof options.columns === "function") {
columns = options.columns(columns);
} else {
columns = columns.map((column) => {
const updatedColumn = options.columns.find(
(_column) => _column.data === column.data
);
if (updatedColumn) {
return { ...updatedColumn, ...column };
}
return column;
});
}
delete options.columns;
}
return handsontable({
data,
columns,
colHeaders: columnHeaders,
columnSorting: true,
// manualColumnMove: true,
// manualColumnResize: true,
// dropdownMenu: true,
// filters: true,
...options
});
}
Insert cell
Insert cell
handsontable = (options = {}, update) => {
const height = Math.min(options.data.length * 22 + 42, 642);
const element = html`<div ${
options.style ? `style="${options.style}"` : ""
} />`;
const hot = Handsontable(element, {
width: "100%",
height: 0, // Fix partial render bug
rowHeights: 22,
licenseKey: "non-commercial-and-evaluation",
data: options.data,
outsideClickDeselects: false,
...options
});
const getValue = () => {
const sourceData = hot.getSourceData();
const headers = Array.from(
sourceData.reduce((result, row) => {
for (let header in row) {
result.add(header);
}
return result;
}, new Set())
);
const currentData = hot
.getData()
.map((row) =>
row.reduce(
(result, value, index) => ({ ...result, [headers[index]]: value }),
{}
)
);
if (options.value) {
return options.value(sourceData, currentData);
}
return currentData;
};
const updateElement = () => {
element.value = getValue();
element.dispatchEvent(new CustomEvent("input"));
};
// const hooks = Object.entries(options).reduce((result, [key, value]) => {
// if (typeof value === 'function') {
// return { ...result, [key]: (...args) => value(...args, hot) };
// }
// }, {});
hot.updateSettings({
// ...hooks,
afterRender: () => {
hot.view.activeWt.wtOverlays?.updateMainScrollableElements();
},
// beforeChange: (changes, source) => {
// updateElement(changes, source);
// },
afterChange: (changes, source) => {
updateElement(changes, source);
}
// afterColumnMove: (column, target) => {
// if (options.afterColumnMove) {
// options.afterColumnMove(column, target);
// }
// updateElement();
// },
// afterColumnResize: (currentColumn, newSize, isDoubleClick) => {
// if (options.afterColumnResize) {
// options.afterColumnResize(currentColumn, newSize, isDoubleClick);
// }
// updateElement();
// },
// afterColumnSort: (currentSortConfig, destinationSortConfig) => {
// if (options.afterColumnSort) {
// options.afterColumnSort(currentSortConfig, destinationSortConfig);
// }
// updateElement();
// },
// afterFilter: conditionsStack => {
// if (options.afterFilter) {
// options.afterFilter(conditionsStack);
// }
// updateElement();
// }
});
element.hot = hot;
element.value = getValue();
invalidation.then(() => element.hot.destroy());
// Fix partial render bug
setTimeout(() => {
element.style.height = `${height}px`;
element.hot.refreshDimensions();
}, 300);
return element;
}
Insert cell
Handsontable = {
const styles = html`<link href="//unpkg.com/handsontable/dist/handsontable.full.min.css" rel="stylesheet" media="screen">`;
document.head.appendChild(styles);
return require('handsontable');
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more