diff --git a/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json b/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json index c65a2b58c08..3359dabd96f 100644 --- a/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json +++ b/documentation/ag-grid-docs/src/content/api-documentation/theming-api/properties.json @@ -32,10 +32,13 @@ } }, "cellFontFamily": {}, + "cellFontSize": {}, + "cellFontWeight": {}, "cellTextColor": {}, "dataFontSize": {}, "fontFamily": {}, "fontSize": {}, + "fontWeight": {}, "headerFontFamily": {}, "headerFontSize": {}, "headerFontWeight": {} diff --git a/documentation/ag-grid-docs/src/content/docs/cell-editing/index.mdoc b/documentation/ag-grid-docs/src/content/docs/cell-editing/index.mdoc index 0c7a8dc635d..738a594c764 100644 --- a/documentation/ag-grid-docs/src/content/docs/cell-editing/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/cell-editing/index.mdoc @@ -57,7 +57,9 @@ This is demonstrated in the following example, note that: ## Two Way Binding -If you want to have row data changes done within the grid - i.e. from the Grid back up to the parent component - then you'll need to make use of `v-model` instead of binding to `rowData`. +By default, `:rowData` is a **one-way binding**: data flows into the grid, but changes made within the grid (e.g. via cell editing) will **not** propagate back to the parent component's `rowData` variable. + +To have row data changes flow back up from the grid to the parent component, use `v-model` instead of `:rowData`. For example: diff --git a/documentation/ag-grid-docs/src/content/docs/components/_register-vue.mdoc b/documentation/ag-grid-docs/src/content/docs/components/_register-vue.mdoc index 889e4b2e610..9c64568bf60 100644 --- a/documentation/ag-grid-docs/src/content/docs/components/_register-vue.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/components/_register-vue.mdoc @@ -7,6 +7,10 @@ It is however useful here to step back and focus on the component registration p Nuxt's auto-import component is not supported with custom components within the grid. Please register any custom components manually as described below. {% /note %} +{% note %} +Async components (e.g. `defineAsyncComponent`) are not supported as custom grid components. Use regular synchronous components instead. +{% /note %} + Custom Components can be registered in two ways: - Globally diff --git a/documentation/ag-grid-docs/src/content/docs/data-update-row-data/index.mdoc b/documentation/ag-grid-docs/src/content/docs/data-update-row-data/index.mdoc index c9cc1bbf124..ace6f5f0332 100644 --- a/documentation/ag-grid-docs/src/content/docs/data-update-row-data/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/data-update-row-data/index.mdoc @@ -100,7 +100,9 @@ If you have smaller data sets (hundreds of rows) then everything should work wit ## Two Way Binding -If you want to have row data changes done within the grid - i.e. from the Grid back up to the parent component - then you'll need to make use of `v-model` instead of binding to `rowData`. +By default, `:rowData` is a **one-way binding**: data flows into the grid, but changes made within the grid (e.g. via cell editing) will **not** propagate back to the parent component's `rowData` variable. + +To have row data changes flow back up from the grid to the parent component, use `v-model` instead of `:rowData`. For example: diff --git a/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/_examples/rich-select-async-values/main.ts b/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/_examples/rich-select-async-values/main.ts index 19cfec456df..60618bf9fca 100644 --- a/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/_examples/rich-select-async-values/main.ts +++ b/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/_examples/rich-select-async-values/main.ts @@ -1,4 +1,10 @@ -import type { ColDef, GridApi, GridOptions, IRichCellEditorParams } from 'ag-grid-community'; +import type { + ColDef, + GridApi, + GridOptions, + IRichCellEditorParams, + RichCellEditorValuesCallbackParams, +} from 'ag-grid-community'; import { ClientSideRowModelModule, ModuleRegistry, @@ -22,13 +28,19 @@ function getRandomNumber(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1) + min); } +function getValueFromServer(_params: RichCellEditorValuesCallbackParams): Promise { + // simulates an async request to a server + return new Promise((resolve) => { + setTimeout(() => resolve(languages), 1000); + }); +} + const columnDefs: ColDef[] = [ { field: 'language', cellEditor: 'agRichSelectCellEditor', cellEditorParams: { - // Simulates an async request to a server - values: (_params) => fetch('/api/languages').then((res) => res.json()), + values: getValueFromServer, } as IRichCellEditorParams, }, ]; diff --git a/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/index.mdoc b/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/index.mdoc index d494c5f6d92..d5e813655ae 100644 --- a/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/provided-cell-editors-rich-select-async/index.mdoc @@ -9,6 +9,8 @@ The Rich Select Cell Editor supports loading values asynchronously, including pa List values can be provided asynchronously to the editor as shown below: +When `values` is provided as a callback function, the callback receives `params` with type `RichCellEditorValuesCallbackParams`. + {% interfaceDocumentation interfaceName="IRichCellEditorParams" overrideSrc="provided-cell-editors-rich-select/rich-select.json" names=["values"] config={ "description": "" } /%} {% gridExampleRunner title="Rich Select Async Values" name="rich-select-async-values" /%} @@ -27,7 +29,7 @@ columnDefs: [ ## Paged Async Values -For large datasets, `valuesPage` avoids loading all items at once and instead loads values on demand based on user scroll and interactions. `valuesPageInitialStartRow` can be used to set the initial position. The `valuesPage` callback should return a value that conforms to the `RichCellEditorValuesPageResult` interface. +For large datasets, `valuesPage` avoids loading all items at once and instead loads values on demand based on user scroll and interactions. `valuesPageInitialStartRow` can be used to set the initial position. The `valuesPage` callback receives `params` with type `RichCellEditorValuesPageParams` and should return a value that conforms to the `RichCellEditorValuesPageResult` interface. {% interfaceDocumentation interfaceName="IRichCellEditorParams" overrideSrc="provided-cell-editors-rich-select/rich-select.json" names=["valuesPage", "valuesPageInitialStartRow", "valuesPageSize", "valuesPageLoadThreshold"] config={ "description": "" } /%} @@ -38,7 +40,7 @@ columnDefs: [ { cellEditor: 'agRichSelectCellEditor', cellEditorParams: { - valuesPage: (params) : Promise> { + valuesPage: (params) => { return fetch(`/api/languages? startRow=${params.startRow} &endRow=${params.endRow}`) @@ -55,6 +57,7 @@ columnDefs: [ ## Async Filtering For advanced filtering scenarios, combine async `values` callback, `allowTyping`, and `filterListAsync` to enable async filtering. +The `values` callback params remain typed as `RichCellEditorValuesCallbackParams`. When `filterListAsync` is set to `true`, the cell editor behaves as follows: @@ -78,11 +81,12 @@ columnDefs: [ allowTyping: true, filterList: true, filterListAsync: true, - values: (params): Promise { + values: (params) => { return fetch(`/api/languages?search=${encodeURIComponent(params.search)}`) - .then(res => res.json()) - .then(data => data.items as string[]) + .then((res) => res.json()) + .then((data) => data.items); } + } } ] ``` @@ -111,7 +115,7 @@ columnDefs: [ filterList: true, filterListAsync: true, valuesPageInitialStartRow: (value) => getRowForSelectedValue(value), - valuesPage: (params): Promise> { + valuesPage: (params) => { return fetch( `/api/languages ?search=${encodeURIComponent(params.search)} diff --git a/documentation/ag-grid-docs/src/content/docs/theming-compactness/index.mdoc b/documentation/ag-grid-docs/src/content/docs/theming-compactness/index.mdoc index 50f5b2a1bb6..86acaab3e38 100644 --- a/documentation/ag-grid-docs/src/content/docs/theming-compactness/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/theming-compactness/index.mdoc @@ -12,7 +12,7 @@ In the following example, classes are applied to the grid container that change ## Row Height -By default, row height is determined by the content height plus padding. Content height is `max(iconSize, dataFontSize)`. Padding is a multiple of `spacing`. This means that your rows can change size if you change any of the icon size, font size, or spacing. +By default, row height is determined by the content height plus padding. Content height is `max(iconSize, cellFontSize)`. Padding is a multiple of `spacing`. This means that your rows can change size if you change any of the icon size, font size, or spacing. The grid provides two ways of customising row height: diff --git a/documentation/ag-grid-docs/src/content/docs/theming-fonts/index.mdoc b/documentation/ag-grid-docs/src/content/docs/theming-fonts/index.mdoc index 0f63ebddde8..b7555ff4f2f 100644 --- a/documentation/ag-grid-docs/src/content/docs/theming-fonts/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/theming-fonts/index.mdoc @@ -6,11 +6,11 @@ Altering typography within the grid ## Font Family Parameters -The grid provides the following [Theme Parameters](./theming-parameters/) to control fonts: +The grid provides many [Theme Parameters](./theming-parameters/) for controlling fonts, the key ones are: -- `fontFamily` sets a default font for all text in the grid -- `headerFontFamily` optionally overrides the font used in the header -- `cellFontFamily` optionally overrides the font used in the data Cells +- `fontFamily`, `fontSize` and `fontWeight` set the default font for all text in the grid +- `headerFontFamily`, `headerFontSize` and `headerFontWeight` optionally override the font for the header +- `cellFontFamily`, `cellFontSize` and `cellFontWeight` optionally override the font used in data cells ```js const myTheme = themeQuartz.withParams({ diff --git a/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts b/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts index 516ed88c07b..19ed629e5a2 100644 --- a/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts +++ b/packages/ag-grid-angular/projects/ag-grid-angular/src/lib/ag-grid-angular.component.ts @@ -1424,7 +1424,7 @@ export class AgGridAngular = ColDef = { borderRadius: 4, spacing: 8, fontSize: 14, + fontWeight: 'inherit', focusShadow: { spread: 3, color: accentMix(0.5), @@ -497,7 +503,7 @@ export const sharedDefaults: Readonly = { ref: 'textColor', }, headerHeight: { - calc: 'max(iconSize, dataFontSize) + spacing * 4 * headerVerticalPaddingScale', + calc: 'max(iconSize, headerFontSize) + spacing * 4 * headerVerticalPaddingScale', }, headerVerticalPaddingScale: 1, menuBorder: { diff --git a/packages/ag-grid-community/src/entities/gridOptions.ts b/packages/ag-grid-community/src/entities/gridOptions.ts index 32ed8cce14e..ba1d492a2ab 100644 --- a/packages/ag-grid-community/src/entities/gridOptions.ts +++ b/packages/ag-grid-community/src/entities/gridOptions.ts @@ -1499,7 +1499,7 @@ export interface GridOptions { * When using `groupDisplayType='multipleColumns'` or `groupHideOpenParents=true`, hides group columns for levels * that have not yet been expanded. Only the top-level group column is initially * visible; each subsequent level becomes visible when at least one group at the - * preceding level is expanded. + * preceding level is expanded. (Client Side Row Model only) * @default false * @agModule `RowGroupingModule` */ diff --git a/packages/ag-grid-community/src/gridOptionsUtils.ts b/packages/ag-grid-community/src/gridOptionsUtils.ts index 70404c02af8..76f4d7b81a8 100644 --- a/packages/ag-grid-community/src/gridOptionsUtils.ts +++ b/packages/ag-grid-community/src/gridOptionsUtils.ts @@ -237,7 +237,7 @@ export function _isGroupMultiAutoColumn(gos: GridOptionsService) { } export function _isGroupHideColumnsUntilExpanded(gos: GridOptionsService) { - return _isGroupMultiAutoColumn(gos) && gos.get('groupHideColumnsUntilExpanded'); + return _isGroupMultiAutoColumn(gos) && gos.get('groupHideColumnsUntilExpanded') && _isClientSideRowModel(gos); } export function _isGroupUseEntireRow(gos: GridOptionsService, pivotMode: boolean): boolean { diff --git a/packages/ag-grid-community/src/misc/state/stateService.ts b/packages/ag-grid-community/src/misc/state/stateService.ts index d15d7c476d7..9230e0413d7 100644 --- a/packages/ag-grid-community/src/misc/state/stateService.ts +++ b/packages/ag-grid-community/src/misc/state/stateService.ts @@ -433,10 +433,11 @@ export class StateService extends BeanStub implements NamedBean { const shouldSetSortState = shouldSetState('sort', sortState); if (shouldSetSortState) { - sortState?.sortModel.forEach(({ colId, sort }, sortIndex) => { + sortState?.sortModel.forEach(({ colId, sort, type }, sortIndex) => { const columnState = getColumnState(colId); columnState.sort = sort; columnState.sortIndex = sortIndex; + columnState.sortType = type; }); } if (shouldSetSortState || !partialColumnState) { diff --git a/packages/ag-grid-community/src/theming/core/core-css.ts b/packages/ag-grid-community/src/theming/core/core-css.ts index 716156ce917..b05d426937f 100644 --- a/packages/ag-grid-community/src/theming/core/core-css.ts +++ b/packages/ag-grid-community/src/theming/core/core-css.ts @@ -233,6 +233,16 @@ export interface CoreParams extends SharedThemeParams { */ cellFontFamily: FontFamilyValue; + /** + * Font size of text in grid cells + */ + cellFontSize: LengthValue; + + /** + * Font weight of text in grid cells + */ + cellFontWeight: FontWeightValue; + /** * Borders between and below header rows. */ @@ -641,6 +651,12 @@ export const coreDefaults: Readonly> = cellFontFamily: { ref: 'fontFamily', }, + cellFontSize: { + ref: 'dataFontSize', + }, + cellFontWeight: { + ref: 'fontWeight', + }, headerCellHoverBackgroundColor: 'transparent', headerCellMovingBackgroundColor: { ref: 'headerCellHoverBackgroundColor' }, headerCellBackgroundTransitionDuration: '0.2s', @@ -679,7 +695,7 @@ export const coreDefaults: Readonly> = valueChangeDeltaDownColor: '#e53935', valueChangeValueHighlightBackgroundColor: '#16a08580', rowHeight: { - calc: 'max(iconSize, dataFontSize) + spacing * 3.25 * rowVerticalPaddingScale', + calc: 'max(iconSize, cellFontSize) + spacing * 3.25 * rowVerticalPaddingScale', }, rowVerticalPaddingScale: 1, paginationPanelHeight: { diff --git a/packages/ag-grid-community/src/theming/core/css/_grid-layout.css b/packages/ag-grid-community/src/theming/core/css/_grid-layout.css index c502b59d572..342b0866121 100644 --- a/packages/ag-grid-community/src/theming/core/css/_grid-layout.css +++ b/packages/ag-grid-community/src/theming/core/css/_grid-layout.css @@ -55,7 +55,8 @@ color: var(--ag-cell-text-color); font-family: var(--ag-cell-font-family); white-space: nowrap; - font-size: var(--ag-data-font-size); + font-size: var(--ag-cell-font-size); + font-weight: var(--ag-cell-font-weight); /* Work out the correct line height. --ag-row-height is the default row height, --ag-line-height is the actual row height, only set if variable row diff --git a/packages/ag-grid-community/src/theming/parts/theme/themes.ts b/packages/ag-grid-community/src/theming/parts/theme/themes.ts index a37af64b6d1..2816e18f64a 100644 --- a/packages/ag-grid-community/src/theming/parts/theme/themes.ts +++ b/packages/ag-grid-community/src/theming/parts/theme/themes.ts @@ -302,10 +302,10 @@ export const styleMaterial = /*#__PURE__*/ makeStyleMaterialTreeShakeable(); export const themeMaterialParams = () => ({ rowHeight: { - calc: 'max(iconSize, dataFontSize) + spacing * 3.75 * rowVerticalPaddingScale', + calc: 'max(iconSize, cellFontSize) + spacing * 3.75 * rowVerticalPaddingScale', }, headerHeight: { - calc: 'max(iconSize, dataFontSize) + spacing * 4.75 * headerVerticalPaddingScale', + calc: 'max(iconSize, cellFontSize) + spacing * 4.75 * headerVerticalPaddingScale', }, widgetVerticalSpacing: { calc: 'spacing * 1.75', diff --git a/packages/ag-grid-vue3/src/components/utils.ts b/packages/ag-grid-vue3/src/components/utils.ts index 8825a67f6cc..eda197f78c5 100644 --- a/packages/ag-grid-vue3/src/components/utils.ts +++ b/packages/ag-grid-vue3/src/components/utils.ts @@ -1247,7 +1247,7 @@ export interface Props { /** When using `groupDisplayType='multipleColumns'` or `groupHideOpenParents=true`, hides group columns for levels * that have not yet been expanded. Only the top-level group column is initially * visible; each subsequent level becomes visible when at least one group at the - * preceding level is expanded. + * preceding level is expanded. (Client Side Row Model only) * @default false * @agModule `RowGroupingModule` */ diff --git a/testing/behavioural/src/grid-state/grid-state.test.ts b/testing/behavioural/src/grid-state/grid-state.test.ts index e34f8d4fc28..08d8626058f 100644 --- a/testing/behavioural/src/grid-state/grid-state.test.ts +++ b/testing/behavioural/src/grid-state/grid-state.test.ts @@ -648,6 +648,55 @@ describe('StateService - Grid State Management', () => { expect(restoredState).toEqual(savedState); }); + test('should preserve absolute sort type when restoring state via setState', async () => { + const api = gridsManager.createGrid('myGrid', { + columnDefs: defaultColumnDefs, + rowData: defaultRowData, + }); + + api.applyColumnState({ + state: [{ colId: 'age', sort: 'asc', sortType: 'absolute' }], + }); + + const savedState = api.getState(); + expect(savedState.sort?.sortModel).toEqual([{ colId: 'age', sort: 'asc', type: 'absolute' }]); + + // Clear sort and restore from saved state + api.applyColumnState({ state: [{ colId: 'age', sort: null }] }); + expect(api.getState().sort?.sortModel ?? []).toHaveLength(0); + + api.setState(savedState); + await asyncSetTimeout(50); + + expect(api.getState().sort?.sortModel).toEqual([{ colId: 'age', sort: 'asc', type: 'absolute' }]); + }); + + test('should clear absolute sort from a column not present in the restored sort state', async () => { + const api = gridsManager.createGrid('myGrid', { + columnDefs: defaultColumnDefs, + rowData: defaultRowData, + }); + + // Set absolute sort on 'age', default sort on 'name' + api.applyColumnState({ + state: [ + { colId: 'age', sort: 'asc', sortType: 'absolute', sortIndex: 0 }, + { colId: 'name', sort: 'desc', sortIndex: 1 }, + ], + }); + + expect(api.getState().sort?.sortModel).toEqual([ + { colId: 'age', sort: 'asc', type: 'absolute' }, + { colId: 'name', sort: 'desc', type: 'default' }, + ]); + + // Restore a state that only sorts 'name' — 'age' absolute sort should be cleared + api.setState({ sort: { sortModel: [{ colId: 'name', sort: 'asc', type: 'default' }] } }); + await asyncSetTimeout(50); + + expect(api.getState().sort?.sortModel).toEqual([{ colId: 'name', sort: 'asc', type: 'default' }]); + }); + test('should initialize grid with initial state', async () => { const initialState: GridState = { sort: {