Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various ag grid theme fixes #3822

Merged
merged 8 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .changeset/large-carrots-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
"@salt-ds/ag-grid-theme": patch
---

- Fixed background color for custom editor component.
- Fixed header text being cropped in HD compact. Closes #3675.
- Fixed Country Symbol taller than expected in HD compact. This alters `--salt-size-base` token so Salt Button, form controls (Input, Dropdown, Combo Box) will be impacted as well. Closes #3775.
- Fixed group value not center aligned vertically.
- Updated ag grid menu styling to match closer to Salt Menu component.
- Updated floating filter column chooser item styles. Closes #3671.

Note: We previously made a mistake on `rowHeight` recommendation when configurating AG Grid, which should be 1px more to account for border between row.
joshwooding marked this conversation as resolved.
Show resolved Hide resolved
`useAgGridHelpers` example hook is updated to reflect this.

| Density | Row height ([`rowHeight`](https://www.ag-grid.com/javascript-data-grid/row-height/)) | Header height ([`headerHeight`](https://www.ag-grid.com/javascript-data-grid/column-headers/#header-height)) |
| ------------ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| HD (Compact) | 21 | 20 |
| HD | 25 | 24 |
| MD | 37 | 36 |
| LD | 49 | 48 |
| TD | 61 | 60 |
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"prettier:ci": "prettier --check .",
"lint": "biome check",
"lint:fix": "biome check --fix",
"lint:check:error": "biome check --diagnostic-level=error",
"lint:style": "yarn lint:style:core && yarn lint:style:icon && yarn lint:style:lab && yarn lint:style:ag-theme",
"lint:style:core": "yarn stylelint -f verbose \"packages/core/src/**/*.css\"",
"lint:style:icon": "yarn stylelint -f verbose \"packages/icons/src/**/*.css\"",
Expand Down
54 changes: 41 additions & 13 deletions packages/ag-grid-theme/css/salt-ag-grid-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,13 @@ div[class*="ag-theme-salt"] {
}

div[class*="ag-theme-salt-compact"] {
--ag-row-height: var(--salt-size-base);
--ag-header-height: var(--salt-size-base);
/*
Ensures icon / country symbol renders correct height.
This also means we don't need to touch `--ag-row-height`, which would impact some internal ag grid height calculation like `--ag-internal-padded-row-height` vs `--ag-internal-calculated-line-height`
*/
--salt-size-base: 16px;
/* This is a deprecated token, until Salt Checkbox uses a new token, temparily pin it to HD size. */
--salt-size-selectable: 12px;
}

div[class*="ag-theme-salt"] .ag-root-wrapper {
Expand Down Expand Up @@ -155,13 +160,33 @@ div[class*="ag-theme-salt"] .ag-header-cell.ag-column-menu-visible .ag-icon {
color: var(--salt-actionable-secondary-foreground-active);
}

div[class*="ag-theme-salt"] .ag-cell-label-container {
/* row height is base size + 50 spacing on top/bottom */
padding: var(--salt-spacing-50) 0;
}

div[class*="ag-theme-salt"] .ag-list-item:hover,
div[class*="ag-theme-salt"] .ag-virtual-list-item:hover {
background-color: var(--salt-selectable-background-hover);
cursor: pointer;
}

div[class*="ag-theme-salt"] .ag-label-align-right .ag-label {
margin-inline-start: var(--salt-spacing-100);
margin-inline-end: 0;
}

/* MENU */

div[class*="ag-theme-salt"] .ag-menu {
padding: var(--salt-spacing-100);
padding: 0;
border: var(--salt-size-border) var(--salt-container-borderStyle) var(--salt-selectable-borderColor-selected);
}

div[class*="ag-theme-salt"] .ag-tabs {
padding: var(--salt-spacing-100);
}

div[class*="ag-theme-salt"] .ag-popup-child:not(.ag-tooltip-custom) {
box-shadow: var(--salt-overlayable-shadow-popout);
}
Expand All @@ -187,8 +212,9 @@ div[class*="ag-theme-salt"] .ag-menu-option {
height: calc(var(--salt-size-base) + var(--salt-spacing-100));
}

div[class*="ag-theme-salt"] .ag-menu-option-icon {
padding: 0 var(--salt-spacing-100);
div[class*="ag-theme-salt"] .ag-menu-option-icon,
div[class*="ag-theme-salt"] .ag-compact-menu-option-icon {
padding-inline-start: var(--salt-spacing-100);
}

div[class*="ag-theme-salt"] .ag-tab {
Expand Down Expand Up @@ -236,6 +262,16 @@ div[class*="ag-theme-salt"] .ag-cell {
padding-right: var(--salt-spacing-100);
}

/* This is not restricted to `.editable-cell`, so any custom editor would get the same background treatment */
div[class*="ag-theme-salt"] .ag-cell-inline-editing:focus-within {
background: var(--salt-container-primary-background);
}

/* This makes sure custom cell editor would start from no padding. Built-in ag grid editor's padding is added below. */
div[class*="ag-theme-salt"] .ag-cell-inline-editing {
padding: 0;
}

div[class*="ag-theme-salt"] .editable-cell,
div[class*="ag-theme-salt"] .editable-numeric-cell {
outline: var(--salt-size-border) var(--salt-container-borderStyle) var(--salt-editable-borderColor);
Expand Down Expand Up @@ -286,14 +322,6 @@ div[class*="ag-theme-salt"] .editable-cell.ag-cell-inline-editing:before {
z-index: 2;
}

div[class*="ag-theme-salt"] .editable-cell.ag-cell-inline-editing {
padding: 0;
}

div[class*="ag-theme-salt"] .editable-cell.ag-cell-inline-editing:focus-within {
background: var(--salt-container-primary-background);
}

div[class*="ag-theme-salt"] .editable-numeric-cell input,
div[class*="ag-theme-salt"] input[class^="ag-"][type="number"] {
padding: 0 var(--salt-spacing-100);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Dropdown, type DropdownProps, Option } from "@salt-ds/core";
import type { ICellEditorParams } from "ag-grid-community";
import {
type KeyboardEvent,
type SyntheticEvent,
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";

export type GridCellValue = string | boolean | number;

export interface DropdownEditorParams extends ICellEditorParams {
source?: Array<GridCellValue>;
dropdownProps?: Partial<DropdownProps<string>>;
}

export const DropdownEditor = forwardRef((props: DropdownEditorParams, ref) => {
const { value: initialValue, source = [], dropdownProps } = props;
const [value, setValue] = useState(initialValue);

const buttonRef = useRef<HTMLButtonElement>(null);

const onSelect = useCallback(
(_event: SyntheticEvent, selectedValue: Array<GridCellValue>) => {
setValue(selectedValue[0]);

// hack to make selection actually record the edit.
// timeout is necessary because otherwise the grid stops editing
// before the useImperativeHandle getValue returns the new value state
setTimeout(() => {
props.api?.stopEditing();
}, 100);
},
[props.api],
);

const onEscapeKeyPressed = useCallback(
(e: KeyboardEvent) => {
if (e.key === "Escape") {
props.api?.stopEditing();
}
},
[props.api],
);

useEffect(() => {
buttonRef.current?.focus();
}, []);

useImperativeHandle(ref, () => ({ getValue: (): typeof value => value }));

return (
<Dropdown
onSelectionChange={onSelect}
defaultOpen={props.cellStartedEdit}
selected={[value || ""]}
ref={buttonRef}
onKeyDown={onEscapeKeyPressed}
className="DropdownEditor"
{...dropdownProps}
style={{
// Outline will be shown on the cell
outline: "none",
// Leave room for cell focus ring
marginInline: "2px",
width: "calc(100% - 4px)",
}}
>
<div
ref={(elem): void => {
if (!elem) return;
// current element -> list container -> list box that matters
(
(elem.parentElement as HTMLElement).parentElement as HTMLElement
).className += " ag-custom-component-popup"; // https://www.ag-grid.com/react-data-grid/component-filter/#custom-filters-containing-a-popup-element
}}
>
{source.map((item) => (
<Option value={item} key={String(item)} />
))}
</div>
</Dropdown>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { countryMetaMap } from "@salt-ds/countries";
import type { CustomCellRendererProps } from "ag-grid-react";

export const FlagRenderer = (props: CustomCellRendererProps) => {
const isoCode = props.value as keyof typeof countryMetaMap;
return (
<div
style={{
display: "flex",
flexFlow: "row",
justifyContent: "center",
width: "100%",
height: "100%",
alignItems: "center",
}}
>
<span
className={`saltCountrySharp-${isoCode}`}
aria-label={countryMetaMap[isoCode]?.countryName}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { ColDef } from "ag-grid-community";
import { DropdownEditor } from "./cell-editors/DropdownEditor";
import { FlagRenderer } from "./cell-renderers/FlagRenderer";

const dataGridExampleColumnsHdCompact: ColDef[] = [
{
headerName: "",
field: "on",
width: 70,
flex: 1,
checkboxSelection: true,
headerCheckboxSelection: true,
pinned: "left",
suppressHeaderMenuButton: true,
resizable: false,
suppressColumnsToolPanel: true,
},
{
headerName: "Name",
field: "name",
filterParams: {
buttons: ["reset", "apply"],
},
editable: false,
},
{
headerName: "Code",
field: "code",
},
{
headerName: "Capital",
field: "capital",
filter: "agSetColumnFilter",
},
{
headerName: "Population",
type: "numericColumn",
field: "population",
filter: "agNumberColumnFilter",
editable: true,
cellClass: ["editable-cell"],
},
{
headerName: "Date",
field: "date",
filter: "agDateColumnFilter",
},
{
headerName: "Rating",
field: "rating",
// Not using `editable-cell` as it doesn't work with Dropdown focus style
editable: true,
cellEditor: "DropdownEditor",
cellEditorParams: {
source: [10, 20, 30, 40, 50, 60],
},
},
{
headerName: "Flag",
field: "country",
cellRenderer: FlagRenderer,
initialWidth: 80,
},
];
export default dataGridExampleColumnsHdCompact;
Loading
Loading