feat(ui): refresh core grid table ux foundation

This commit is contained in:
2026-04-22 19:56:23 +02:00
parent fecbbdde24
commit 0c8ccae0fb
3 changed files with 385 additions and 179 deletions

View File

@@ -8,6 +8,9 @@ import { buildChipsFromMeta, removeChipFromMetaState, clearMetaState } from '../
const DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
const PAGE_SIZE_STORAGE_PREFIX = 'grid:page-size';
const DEFAULT_GRID_HEIGHT = 'min(68vh, 760px)';
const GRID_DENSITY_VALUES = new Set(['sm', 'md', 'lg']);
const GRID_LOADING_MODE_VALUES = new Set(['skeleton', 'bar']);
const parsePositiveInt = (value) => {
const parsed = Number.parseInt(String(value ?? ''), 10);
@@ -31,6 +34,16 @@ const normalizePageSizeOptions = (options) => {
return normalized.length ? normalized : [...DEFAULT_PAGE_SIZE_OPTIONS];
};
const normalizeGridDensity = (value) => {
const normalized = String(value ?? '').trim().toLowerCase();
return GRID_DENSITY_VALUES.has(normalized) ? normalized : 'md';
};
const normalizeLoadingMode = (value) => {
const normalized = String(value ?? '').trim().toLowerCase();
return GRID_LOADING_MODE_VALUES.has(normalized) ? normalized : 'skeleton';
};
const escapeHtmlAttr = (value) => String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
@@ -101,7 +114,8 @@ export function createServerGrid(options) {
rowInteraction = null,
rowDataset = null,
selection = null,
pageSize = null
pageSize = null,
ui = null
} = options || {};
const normalizedFilterBindingMode = String(filterBindingMode || 'live').trim().toLowerCase() === 'manual'
@@ -120,6 +134,19 @@ export function createServerGrid(options) {
return null;
}
const uiConfig = ui && typeof ui === 'object' ? ui : {};
const stickyHeaderEnabled = uiConfig.stickyHeader !== false;
const gridHeight = typeof uiConfig.height === 'string' && uiConfig.height.trim() !== ''
? uiConfig.height.trim()
: DEFAULT_GRID_HEIGHT;
const loadingMode = normalizeLoadingMode(uiConfig.loadingMode);
const densityMode = normalizeGridDensity(uiConfig.density);
containerEl.classList.remove('app-grid-density-sm', 'app-grid-density-md', 'app-grid-density-lg');
containerEl.classList.add(`app-grid-density-${densityMode}`);
containerEl.classList.toggle('app-grid-loading-bar', loadingMode === 'bar');
containerEl.classList.toggle('app-grid-loading-skeleton', loadingMode === 'skeleton');
const normalizedColumns = normalizeGridColumns(columns, sortColumns);
const params = new URLSearchParams(window.location.search);
@@ -688,6 +715,8 @@ export function createServerGrid(options) {
search: false,
sort: sortConfig,
pagination: paginationConfig,
fixedHeader: stickyHeaderEnabled,
...(stickyHeaderEnabled ? { height: gridHeight } : {}),
language,
plugins
});
@@ -706,6 +735,8 @@ export function createServerGrid(options) {
};
const setUpdating = () => containerEl.classList.add('gridjs-is-updating');
const clearUpdating = () => containerEl.classList.remove('gridjs-is-updating');
const setErrorState = () => containerEl.classList.add('gridjs-has-error');
const clearErrorState = () => containerEl.classList.remove('gridjs-has-error');
const ensureErrorRetryControl = () => {
const errorMessage = containerEl.querySelector('.gridjs-message.gridjs-error');
if (!errorMessage) {
@@ -738,9 +769,12 @@ export function createServerGrid(options) {
clearUpdating();
}
if (state.status === 4) {
setErrorState();
setTimeout(() => {
ensureErrorRetryControl();
}, 0);
} else {
clearErrorState();
}
if (state.status >= 2) {
markLoadedOnce();
@@ -764,8 +798,12 @@ export function createServerGrid(options) {
if (rowOpenUrl !== '') {
rowEl.setAttribute('data-row-open-url', rowOpenUrl);
rowEl.setAttribute('tabindex', '-1');
rowEl.setAttribute('title', rowEnterHint);
rowEl.setAttribute('aria-label', rowEnterHint);
} else {
rowEl.removeAttribute('data-row-open-url');
rowEl.removeAttribute('title');
rowEl.removeAttribute('aria-label');
if (rowEl.getAttribute('tabindex') === '-1') {
rowEl.removeAttribute('tabindex');
}