mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
299 lines
7.3 KiB
TypeScript
299 lines
7.3 KiB
TypeScript
import { css, CSSObject } from '@emotion/css';
|
|
|
|
import { GrafanaTheme2 } from '@grafana/data';
|
|
import { TableCellHeight } from '@grafana/schema';
|
|
|
|
export function useTableStyles(theme: GrafanaTheme2, cellHeightOption: TableCellHeight) {
|
|
const borderColor = theme.colors.border.weak;
|
|
const resizerColor = theme.colors.primary.border;
|
|
const cellPadding = 6;
|
|
const cellHeight = getCellHeight(theme, cellHeightOption, cellPadding);
|
|
const rowHeight = cellHeight + 2;
|
|
const headerHeight = 28;
|
|
|
|
const buildCellContainerStyle = (color?: string, background?: string, overflowOnHover?: boolean) => {
|
|
const cellActionsOverflow: CSSObject = {
|
|
margin: theme.spacing(0, -0.5, 0, 0.5),
|
|
};
|
|
|
|
const cellActionsNoOverflow: CSSObject = {
|
|
position: 'absolute',
|
|
top: 0,
|
|
right: 0,
|
|
margin: 'auto',
|
|
};
|
|
|
|
const onHoverOverflow: CSSObject = {
|
|
overflow: 'visible',
|
|
width: 'auto !important',
|
|
boxShadow: `0 0 2px ${theme.colors.primary.main}`,
|
|
background: background ?? theme.components.table.rowHoverBackground,
|
|
zIndex: 1,
|
|
};
|
|
|
|
return css`
|
|
label: ${overflowOnHover ? 'cellContainerOverflow' : 'cellContainerNoOverflow'};
|
|
padding: ${cellPadding}px;
|
|
width: 100%;
|
|
// Cell height need to account for row border
|
|
height: ${rowHeight - 1}px;
|
|
display: flex;
|
|
align-items: center;
|
|
border-right: 1px solid ${borderColor};
|
|
|
|
${color ? `color: ${color};` : ''};
|
|
${background ? `background: ${background};` : ''};
|
|
background-clip: padding-box;
|
|
|
|
&:last-child:not(:only-child) {
|
|
border-right: none;
|
|
}
|
|
|
|
&:hover {
|
|
${overflowOnHover && onHoverOverflow};
|
|
.cellActions {
|
|
visibility: visible;
|
|
opacity: 1;
|
|
width: auto;
|
|
}
|
|
}
|
|
|
|
a {
|
|
color: inherit;
|
|
}
|
|
|
|
.cellActions {
|
|
display: flex;
|
|
${overflowOnHover ? cellActionsOverflow : cellActionsNoOverflow}
|
|
visibility: hidden;
|
|
opacity: 0;
|
|
width: 0;
|
|
align-items: center;
|
|
height: 100%;
|
|
padding: ${theme.spacing(1, 0.5, 1, 0.5)};
|
|
background: ${background ? 'none' : theme.colors.emphasize(theme.colors.background.primary, 0.03)};
|
|
|
|
svg {
|
|
color: ${color};
|
|
}
|
|
}
|
|
|
|
.cellActionsLeft {
|
|
right: auto !important;
|
|
left: 0;
|
|
}
|
|
|
|
.cellActionsTransparent {
|
|
background: none;
|
|
}
|
|
`;
|
|
};
|
|
|
|
return {
|
|
theme,
|
|
cellHeight,
|
|
buildCellContainerStyle,
|
|
cellPadding,
|
|
cellHeightInner: cellHeight - cellPadding * 2,
|
|
rowHeight,
|
|
table: css`
|
|
height: 100%;
|
|
width: 100%;
|
|
overflow: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
`,
|
|
thead: css`
|
|
label: thead;
|
|
height: ${headerHeight}px;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
position: relative;
|
|
`,
|
|
tfoot: css`
|
|
label: tfoot;
|
|
height: ${headerHeight}px;
|
|
border-top: 1px solid ${borderColor};
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
position: relative;
|
|
`,
|
|
headerRow: css`
|
|
label: row;
|
|
border-bottom: 1px solid ${borderColor};
|
|
`,
|
|
headerCell: css`
|
|
height: 100%;
|
|
padding: 0 ${cellPadding}px;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
display: flex;
|
|
align-items: center;
|
|
font-weight: ${theme.typography.fontWeightMedium};
|
|
|
|
&:last-child {
|
|
border-right: none;
|
|
}
|
|
`,
|
|
headerCellLabel: css`
|
|
border: none;
|
|
padding: 0;
|
|
background: inherit;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
font-weight: ${theme.typography.fontWeightMedium};
|
|
display: flex;
|
|
align-items: center;
|
|
margin-right: ${theme.spacing(0.5)};
|
|
|
|
&:hover {
|
|
text-decoration: underline;
|
|
color: ${theme.colors.text.link};
|
|
}
|
|
`,
|
|
cellContainer: buildCellContainerStyle(undefined, undefined, true),
|
|
cellContainerNoOverflow: buildCellContainerStyle(undefined, undefined, false),
|
|
cellText: css`
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
user-select: text;
|
|
white-space: nowrap;
|
|
`,
|
|
sortIcon: css`
|
|
margin-left: ${theme.spacing(0.5)};
|
|
`,
|
|
cellLink: css`
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
user-select: text;
|
|
white-space: nowrap;
|
|
color: ${theme.colors.text.link};
|
|
font-weight: ${theme.typography.fontWeightMedium};
|
|
&:hover {
|
|
text-decoration: underline;
|
|
color: ${theme.colors.text.link};
|
|
}
|
|
`,
|
|
cellLinkForColoredCell: css`
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
user-select: text;
|
|
white-space: nowrap;
|
|
font-weight: ${theme.typography.fontWeightMedium};
|
|
text-decoration: underline;
|
|
`,
|
|
imageCellLink: css`
|
|
cursor: pointer;
|
|
overflow: hidden;
|
|
height: 100%;
|
|
`,
|
|
headerFilter: css`
|
|
background: transparent;
|
|
border: none;
|
|
label: headerFilter;
|
|
padding: 0;
|
|
`,
|
|
paginationWrapper: css`
|
|
display: flex;
|
|
height: ${cellHeight}px;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
li {
|
|
margin-bottom: 0;
|
|
}
|
|
`,
|
|
paginationSummary: css`
|
|
color: ${theme.colors.text.secondary};
|
|
font-size: ${theme.typography.bodySmall.fontSize};
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
padding: ${theme.spacing(0, 1, 0, 2)};
|
|
`,
|
|
|
|
tableContentWrapper: (totalColumnsWidth: number) => {
|
|
const width = totalColumnsWidth !== undefined ? `${totalColumnsWidth}px` : '100%';
|
|
|
|
return css`
|
|
label: tableContentWrapper;
|
|
width: ${width};
|
|
display: flex;
|
|
flex-direction: column;
|
|
`;
|
|
},
|
|
row: css`
|
|
label: row;
|
|
border-bottom: 1px solid ${borderColor};
|
|
|
|
&:hover {
|
|
background-color: ${theme.components.table.rowHoverBackground};
|
|
}
|
|
|
|
&:last-child {
|
|
border-bottom: 0;
|
|
}
|
|
`,
|
|
imageCell: css`
|
|
height: 100%;
|
|
`,
|
|
resizeHandle: css`
|
|
label: resizeHandle;
|
|
cursor: col-resize !important;
|
|
display: inline-block;
|
|
background: ${resizerColor};
|
|
opacity: 0;
|
|
transition: opacity 0.2s ease-in-out;
|
|
width: 8px;
|
|
height: 100%;
|
|
position: absolute;
|
|
right: -4px;
|
|
border-radius: ${theme.shape.radius.default};
|
|
top: 0;
|
|
touch-action: none;
|
|
|
|
&:hover {
|
|
opacity: 1;
|
|
}
|
|
`,
|
|
typeIcon: css`
|
|
margin-right: ${theme.spacing(1)};
|
|
color: ${theme.colors.text.secondary};
|
|
`,
|
|
noData: css`
|
|
align-items: center;
|
|
display: flex;
|
|
height: 100%;
|
|
justify-content: center;
|
|
width: 100%;
|
|
`,
|
|
expanderCell: css`
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
height: ${rowHeight}px;
|
|
cursor: pointer;
|
|
`,
|
|
};
|
|
}
|
|
|
|
export type TableStyles = ReturnType<typeof useTableStyles>;
|
|
|
|
function getCellHeight(theme: GrafanaTheme2, cellHeightOption: TableCellHeight, cellPadding: number) {
|
|
const bodyFontSize = theme.typography.fontSize;
|
|
const lineHeight = theme.typography.body.lineHeight;
|
|
|
|
switch (cellHeightOption) {
|
|
case 'md':
|
|
return 42;
|
|
case 'lg':
|
|
return 48;
|
|
case 'sm':
|
|
default:
|
|
return cellPadding * 2 + bodyFontSize * lineHeight;
|
|
}
|
|
}
|