[release-12.2.1] Table: Backport the Safari 26 fixes to 12.2.1 (#111906)

* [release-12.2.1] Table: Disable virtualization, hover overflow, and scrollbar width resizing on Safari 26 (#111834)

* Table: Disable virtualization, hover overflow, and scrollbar width resizing on Safari 26

* pull obj def out of method

* [release-12.2.1] Table: Avoid overflow issues in Safari 26 (#111858)
This commit is contained in:
Paul Marbach 2025-10-07 11:08:14 -04:00 committed by GitHub
parent 0c5602dd10
commit 10fe7d04e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 11 deletions

View File

@ -96,6 +96,7 @@ import {
shouldTextWrap, shouldTextWrap,
withDataLinksActionsTooltip, withDataLinksActionsTooltip,
getSummaryCellTextAlign, getSummaryCellTextAlign,
IS_SAFARI_26,
} from './utils'; } from './utils';
const EXPANDED_COLUMN_KEY = 'expanded'; const EXPANDED_COLUMN_KEY = 'expanded';
@ -286,7 +287,7 @@ export function TableNG(props: TableNGProps) {
const commonDataGridProps = useMemo( const commonDataGridProps = useMemo(
() => () =>
({ ({
enableVirtualization: enableVirtualization !== false && rowHeight !== 'auto', enableVirtualization: !IS_SAFARI_26 && enableVirtualization !== false && rowHeight !== 'auto',
defaultColumnOptions: { defaultColumnOptions: {
minWidth: 50, minWidth: 50,
resizable: true, resizable: true,
@ -459,7 +460,8 @@ export function TableNG(props: TableNGProps) {
? clsx('table-cell-actions', getCellActionStyles(theme, textAlign)) ? clsx('table-cell-actions', getCellActionStyles(theme, textAlign))
: undefined; : undefined;
const shouldOverflow = rowHeight !== 'auto' && (shouldTextOverflow(field) || Boolean(maxRowHeight)); const shouldOverflow =
!IS_SAFARI_26 && rowHeight !== 'auto' && (shouldTextOverflow(field) || Boolean(maxRowHeight));
const textWrap = rowHeight === 'auto' || shouldTextWrap(field); const textWrap = rowHeight === 'auto' || shouldTextWrap(field);
const withTooltip = withDataLinksActionsTooltip(field, cellType); const withTooltip = withDataLinksActionsTooltip(field, cellType);
const canBeColorized = canFieldBeColorized(cellType, applyToRowBgFn); const canBeColorized = canFieldBeColorized(cellType, applyToRowBgFn);
@ -781,7 +783,7 @@ export function TableNG(props: TableNGProps) {
const displayedEnd = pageRangeEnd; const displayedEnd = pageRangeEnd;
const numRows = sortedRows.length; const numRows = sortedRows.length;
return ( let rendered = (
<> <>
<DataGrid<TableRow, TableSummaryRow> <DataGrid<TableRow, TableSummaryRow>
{...commonDataGridProps} {...commonDataGridProps}
@ -869,6 +871,12 @@ export function TableNG(props: TableNGProps) {
)} )}
</> </>
); );
if (IS_SAFARI_26) {
rendered = <div className={styles.safariWrapper}>{rendered}</div>;
}
return rendered;
} }
/** /**

View File

@ -16,6 +16,7 @@ import {
computeColWidths, computeColWidths,
buildHeaderHeightMeasurers, buildHeaderHeightMeasurers,
buildCellHeightMeasurers, buildCellHeightMeasurers,
IS_SAFARI_26,
} from './utils'; } from './utils';
// Helper function to get displayed value // Helper function to get displayed value
@ -468,7 +469,7 @@ export function useScrollbarWidth(ref: RefObject<DataGridHandle>, height: number
useLayoutEffect(() => { useLayoutEffect(() => {
const el = ref.current?.element; const el = ref.current?.element;
if (!el) { if (!el || IS_SAFARI_26) {
return; return;
} }

View File

@ -1,11 +1,12 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { Property } from 'csstype'; import { Property } from 'csstype';
import memoize from 'micro-memoize';
import { GrafanaTheme2, colorManipulator } from '@grafana/data'; import { GrafanaTheme2, colorManipulator } from '@grafana/data';
import { COLUMN, TABLE } from './constants'; import { COLUMN, TABLE } from './constants';
import { TableCellStyles } from './types'; import { TableCellStyles } from './types';
import { getJustifyContent, TextAlign } from './utils'; import { getJustifyContent, IS_SAFARI_26, TextAlign } from './utils';
export const getGridStyles = (theme: GrafanaTheme2, enablePagination?: boolean, transparent?: boolean) => { export const getGridStyles = (theme: GrafanaTheme2, enablePagination?: boolean, transparent?: boolean) => {
const bgColor = transparent ? theme.colors.background.canvas : theme.colors.background.primary; const bgColor = transparent ? theme.colors.background.canvas : theme.colors.background.primary;
@ -51,14 +52,14 @@ export const getGridStyles = (theme: GrafanaTheme2, enablePagination?: boolean,
'& > :not(.rdg-summary-row, .rdg-header-row) > .rdg-cell': { '& > :not(.rdg-summary-row, .rdg-header-row) > .rdg-cell': {
[getActiveCellSelector()]: { boxShadow: theme.shadows.z2 }, [getActiveCellSelector()]: { boxShadow: theme.shadows.z2 },
// selected cells should appear below hovered cells. // selected cells should appear below hovered cells.
'&:hover': { zIndex: theme.zIndex.tooltip - 7 }, ...(!IS_SAFARI_26 && { '&:hover': { zIndex: theme.zIndex.tooltip - 7 } }),
'&[aria-selected=true]': { zIndex: theme.zIndex.tooltip - 6 }, '&[aria-selected=true]': { zIndex: theme.zIndex.tooltip - 6 },
}, },
'.rdg-cell.rdg-cell-frozen': { '.rdg-cell.rdg-cell-frozen': {
backgroundColor: '--rdg-row-background-color', backgroundColor: 'var(--rdg-row-background-color)',
zIndex: theme.zIndex.tooltip - 4, zIndex: theme.zIndex.tooltip - 4,
'&:hover': { zIndex: theme.zIndex.tooltip - 2 }, ...(!IS_SAFARI_26 && { '&:hover': { zIndex: theme.zIndex.tooltip - 2 } }),
'&[aria-selected=true]': { zIndex: theme.zIndex.tooltip - 3 }, '&[aria-selected=true]': { zIndex: theme.zIndex.tooltip - 3 },
}, },
@ -70,7 +71,6 @@ export const getGridStyles = (theme: GrafanaTheme2, enablePagination?: boolean,
}, },
}, },
}, },
'.rdg-summary-row >': { '.rdg-summary-row >': {
'.rdg-cell': { '.rdg-cell': {
// 0.75 padding causes "jumping" on hover. // 0.75 padding causes "jumping" on hover.
@ -123,6 +123,7 @@ export const getGridStyles = (theme: GrafanaTheme2, enablePagination?: boolean,
padding: theme.spacing(0, 1, 0, 2), padding: theme.spacing(0, 1, 0, 2),
}), }),
menuItem: css({ maxWidth: '200px' }), menuItem: css({ maxWidth: '200px' }),
safariWrapper: css({ contain: 'strict', height: '100%' }),
}; };
}; };
@ -235,5 +236,22 @@ export const getTooltipStyles = (theme: GrafanaTheme2, textAlign: TextAlign) =>
}), }),
}); });
export const getActiveCellSelector = (isNested?: boolean) => const ACTIVE_CELL_SELECTORS = {
isNested ? '.rdg-cell:hover &, [aria-selected=true] &' : '&:hover, &[aria-selected=true]'; hover: {
nested: '.rdg-cell:hover &',
normal: '&:hover',
},
selected: {
nested: '[aria-selected=true] &',
normal: '&[aria-selected=true]',
},
} as const;
export const getActiveCellSelector = memoize((isNested?: boolean) => {
const selectors = [];
selectors.push(ACTIVE_CELL_SELECTORS.selected[isNested ? 'nested' : 'normal']);
if (!IS_SAFARI_26) {
selectors.push(ACTIVE_CELL_SELECTORS.hover[isNested ? 'nested' : 'normal']);
}
return selectors.join(', ');
});

View File

@ -1009,3 +1009,13 @@ export function getSummaryCellTextAlign(textAlign: TextAlign, cellType: TableCel
return textAlign; return textAlign;
} }
// Safari 26 introduced rendering bugs which require us to disable several features of the table.
export const IS_SAFARI_26 = (() => {
if (navigator == null) {
return false;
}
const userAgent = navigator.userAgent;
const safariVersionMatch = userAgent.match(/Version\/(\d+)\./);
return safariVersionMatch && parseInt(safariVersionMatch[1], 10) === 26;
})();