Skip to content

Commit f15f1e3

Browse files
committed
chore: fix sizing, use fractional pixels
1 parent 53551a7 commit f15f1e3

File tree

5 files changed

+52
-44
lines changed

5 files changed

+52
-44
lines changed

packages/modules/data-widgets/src/themesource/datawidgets/web/_datagrid.scss

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -411,14 +411,6 @@ $root: ".widget-datagrid";
411411
overflow-x: auto;
412412
}
413413

414-
&-grid-head {
415-
display: contents;
416-
}
417-
418-
&-grid-body {
419-
display: contents;
420-
}
421-
422414
&-footer {
423415
container: widget-datagrid-footer / inline-size;
424416
}
@@ -537,23 +529,36 @@ $root: ".widget-datagrid";
537529

538530
.infinite-loading {
539531
.widget-datagrid-grid-head {
532+
// lock header width
533+
// and prevent it from having own scrolling
534+
// as scrolling is synchronized in JS
540535
width: calc(var(--widgets-grid-width) - var(--widgets-grid-scrollbar-size));
541536
overflow-x: hidden;
542537
}
543538
.widget-datagrid-grid-head[data-scrolled-y="true"] {
539+
// add shadow under the header
540+
// implying that grid is scrolled vertically (there are rows hidden under header)
541+
// the data attribute added in JS
544542
box-shadow: 0 5px 5px -5px gray;
545543
}
546544

547545
.widget-datagrid-grid-body {
546+
// lock the size of the body
547+
// and enable it to have own scrolling
548+
// body is the leading element
549+
// header scroll will be synced to match it
548550
width: var(--widgets-grid-width);
549551
overflow-y: auto;
550552
max-height: var(--widgets-grid-body-height);
551553
}
552554

553555
.widget-datagrid-grid-head[data-scrolled-x="true"]:after {
556+
// add inner shadow to the left side of the grid
557+
// implying that the grid is scrolled horizontally (there are rows hidden on the left)
558+
// the data attribute added in JS
554559
content: "";
555560
position: absolute;
556-
left: 0px;
561+
left: 0;
557562
width: 10px;
558563
box-shadow: inset 5px 0 5px -5px gray;
559564
top: 0;
@@ -563,6 +568,7 @@ $root: ".widget-datagrid";
563568

564569
.widget-datagrid-grid-head {
565570
display: grid;
571+
min-width: 0;
566572

567573
// this head is not part of the grid, so it has dedicated column template --widgets-grid-template-columns-head
568574
// but it might not be available at the initial render, so we use template from the grid --widgets-grid-template-columns
@@ -573,6 +579,7 @@ $root: ".widget-datagrid";
573579
// and everything looks like it should.
574580
grid-template-columns: var(--widgets-grid-template-columns-head, var(--widgets-grid-template-columns));
575581
}
582+
576583
.widget-datagrid-grid-body {
577584
// this element has to position their children (columns or headers)
578585
// as grid and have those aligned with the parent grid
@@ -583,9 +590,7 @@ $root: ".widget-datagrid";
583590
}
584591

585592
.grid-mock-header {
586-
grid-template-columns: subgrid;
587-
grid-column: 1 / -1;
588-
display: grid;
593+
display: contents;
589594
}
590595

591596
:where(#{$root}-paging-bottom, #{$root}-padding-top) {

packages/pluggableWidgets/datagrid-web/src/components/MockHeader.tsx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,42 @@
1-
import { ReactNode, useCallback, useEffect, useRef } from "react";
1+
import { ReactNode, useCallback, useEffect } from "react";
22
import { useColumnsStore, useDatagridConfig, useGridSizeStore } from "../model/hooks/injection-hooks";
33

4-
function getColumnSizes(container: HTMLDivElement | null): Map<string, number> {
5-
const sizes = new Map<string, number>();
6-
if (container) {
7-
container.querySelectorAll<HTMLDivElement>("[data-column-id]").forEach(c => {
8-
const columnId = c.dataset.columnId;
9-
if (!columnId) {
10-
console.debug("getColumnSizes: can't find id on:", c);
11-
return;
12-
}
13-
sizes.set(columnId, c.offsetWidth);
14-
});
15-
}
16-
17-
return sizes;
18-
}
19-
204
export function MockHeader(): ReactNode {
215
const columnsStore = useColumnsStore();
226
const config = useDatagridConfig();
237
const gridSizeStore = useGridSizeStore();
24-
const headerRef = useRef<HTMLDivElement | null>(null);
25-
const resizeCallback = useCallback<ResizeObserverCallback>(() => {
26-
gridSizeStore.updateColumnSizes(getColumnSizes(headerRef.current).values().toArray());
27-
}, [headerRef, gridSizeStore]);
8+
const resizeCallback = useCallback<ResizeObserverCallback>(
9+
entries => {
10+
const container = entries[0].target.parentElement!;
11+
const sizes = new Map<string, number>();
12+
container.querySelectorAll<HTMLDivElement>("[data-column-id]").forEach(c => {
13+
const columnId = c.dataset.columnId;
14+
if (!columnId) {
15+
console.debug("getColumnSizes: can't find id on:", c);
16+
return;
17+
}
18+
19+
sizes.set(columnId, c.getBoundingClientRect().width);
20+
});
21+
gridSizeStore.updateColumnSizes(sizes.values().toArray());
22+
},
23+
[gridSizeStore]
24+
);
2825

2926
useEffect(() => {
3027
const observer = new ResizeObserver(resizeCallback);
3128

32-
if (headerRef.current) {
33-
observer.observe(headerRef.current);
34-
}
29+
columnsStore.visibleColumns.forEach(c => {
30+
if (c.headerElementRef) observer.observe(c.headerElementRef);
31+
});
32+
3533
return () => {
3634
observer.disconnect();
3735
};
38-
}, [resizeCallback, headerRef]);
36+
}, [resizeCallback, columnsStore.visibleColumns]);
3937

4038
return (
41-
<div className={"grid-mock-header"} aria-hidden ref={headerRef}>
39+
<div className={"grid-mock-header"} aria-hidden>
4240
{config.checkboxColumnEnabled && <div data-column-id="checkboxes" key={"checkboxes"}></div>}
4341
{columnsStore.visibleColumns.map(c => (
4442
<div

packages/pluggableWidgets/datagrid-web/src/helpers/state/column/ColumnStore.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class ColumnStore implements GridColumn {
2323
size: number | undefined = undefined;
2424
orderWeight: number;
2525

26-
private headerElementRef: HTMLDivElement | null = null;
26+
headerElementRef: HTMLDivElement | null = null;
2727

2828
private baseInfo: BaseColumnInfo;
2929
private parentStore: IColumnParentStore;

packages/pluggableWidgets/datagrid-web/src/model/hooks/useInfiniteControl.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { RefObject, UIEvent, useCallback, useEffect, useLayoutEffect } from "react";
1+
import { RefObject, UIEvent, useCallback, useEffect } from "react";
22
import { useOnScreen } from "@mendix/widget-plugin-hooks/useOnScreen";
33
import { useGridSizeStore } from "@mendix/datagrid-web/src/model/hooks/injection-hooks";
44
import { VIRTUAL_SCROLLING_OFFSET } from "../stores/GridSize.store";
@@ -43,15 +43,15 @@ export function useInfiniteControl(): [trackBodyScrolling: ((e: any) => void) |
4343

4444
useEffect(() => {
4545
setTimeout(() => isVisible && gridSizeStore.lockGridBodyHeight(), 100);
46-
}, [isVisible, gridSizeStore]);
46+
});
4747

48-
useLayoutEffect(() => {
48+
useEffect(() => {
4949
const observeTarget = gridSizeStore.gridContainerRef.current;
5050
if (!gridSizeStore.hasVirtualScrolling || !observeTarget) return;
5151

5252
const resizeObserver = new ResizeObserver(entries => {
5353
for (const entry of entries) {
54-
gridSizeStore.setGridWidth(entry.target.clientWidth ? entry.target.clientWidth : undefined);
54+
gridSizeStore.setGridWidth(entry.contentRect.width);
5555
}
5656
});
5757

packages/pluggableWidgets/datagrid-web/src/model/stores/GridSize.store.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ export class GridSizeStore {
4545
}
4646

4747
get templateColumnsHead(): string | undefined {
48-
return this.columnSizes?.map(s => `${s}px`).join(" ");
48+
return this.columnSizes
49+
?.map(s => {
50+
const str = s.toString();
51+
return `${str.slice(0, str.indexOf(".") + 4)}px`;
52+
})
53+
.join(" ");
4954
}
5055

5156
bumpPage(): void {

0 commit comments

Comments
 (0)