Skip to content

Commit

Permalink
Improves UI issues when rendering a Kino.DataTable (#497)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonatan Kłosko <[email protected]>
  • Loading branch information
hugobarauna and jonatanklosko authored Mar 5, 2025
1 parent 6d2a3ab commit 02eeeb7
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 68 deletions.
40 changes: 40 additions & 0 deletions assets/packs/data_table/Skeleton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Creates a loading skeleton for the data table
*/
export function createTableSkeleton() {
const container = document.createElement("div");
container.innerHTML = `
<div class="w-full">
<table class="w-full border-separate border-spacing-0 mt-2 animate-pulse">
<tbody>
${createTableRow()}
${createTableRow()}
${createTableRow()}
${createTableRow()}
${createTableRow()}
</tbody>
</table>
</div>
`;
return container;
}

function createTableRow() {
return `
<tr>
${createDataCell("w-12")}
${createDataCell("w-32")}
${createDataCell("w-48")}
${createDataCell("w-20")}
</tr>
`;
}

function createDataCell(width) {
return `
<td class="p-2.5 border-b border-slate-100 ${width}">
<div class="bg-gradient-to-r from-gray-100 via-gray-200 to-gray-100 h-4 rounded">
</div>
</td>
`;
}
73 changes: 60 additions & 13 deletions assets/packs/data_table/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,66 @@ import "@glideapps/glide-data-grid/dist/index.css";
import React from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";
import { createTableSkeleton } from "./Skeleton";

export async function init(ctx, data) {
// In Firefox and Safari, during the first load (uncached), the data
// grid renders the default font and the font is only updated after
// hovering the grid. Ensuring the font is loaded helps in Firefox.
await ctx.importCSS(
"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap",
);
ctx.importCSS(
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap",
);
ctx.importCSS("main.css");

const root = createRoot(ctx.root);
root.render(<App ctx={ctx} data={data} />);
ctx.root.appendChild(createTableSkeleton());

try {
await loadStyles(ctx);
} finally {
const root = createRoot(ctx.root);
root.render(<App ctx={ctx} data={data} />);
}
}

async function loadStyles(ctx) {
const cssPromises = [
ctx.importCSS(
"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap",
),
ctx.importCSS(
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
),
ctx.importCSS("main.css"),
];

// We force all fonts to be loaded by adding an invisible element,
// and then we explicitly wait for the fonts to finish loading.
// This is important on first uncached render. If we don't wait
// and render the table with fallback fonts, the columns get wrong
// default widths. Also, on Firefox ans Safari, once the font is
// loaded, the table only updates on hover, which is bad UX.

const fontPreloader = document.createElement("div");
fontPreloader.setAttribute("aria-hidden", "true");
fontPreloader.style.cssText = `
position: absolute;
visibility: hidden;
left: -9999px;
`;
fontPreloader.innerHTML = `
<span style="font-family: 'JetBrains Mono'">
<span style="font-weight: 400">preload</span>"
<span style="font-weight: 500">preload</span>"
<span style="font-weight: 600">preload</span>"
</span>"
<span style="font-family: 'Inter'">
<span style="font-weight: 400">preload</span>"
<span style="font-weight: 500">preload</span>"
<span style="font-weight: 600">preload</span>"
</span>"
`;

document.body.appendChild(fontPreloader);

try {
await Promise.all(cssPromises);

if (document.fonts && document.fonts.ready) {
await document.fonts.ready;
}
} finally {
document.body.removeChild(fontPreloader);
}
}
Loading

0 comments on commit 02eeeb7

Please sign in to comment.