From 2e1066e66047c76e67078eb53f40867aeed19f42 Mon Sep 17 00:00:00 2001 From: Alan Treadway Date: Wed, 19 Aug 2026 15:28:44 +0100 Subject: [PATCH 1/2] Fix .claude/settings.json drift. (#14906) --- .claude/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/settings.json b/.claude/settings.json index 47a56e14ef6..77967fc4346 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -86,7 +86,8 @@ ], "deny": [ "Read(.env.local)", - "Read(credentials/)" + "Read(credentials/)", + "Read(credentials/**)" ] }, "hooks": { From ba11cacdf4674c9aae832f3ddd675da4a5058db8 Mon Sep 17 00:00:00 2001 From: Guilherme Lopes Date: Wed, 19 Aug 2026 16:58:32 -0300 Subject: [PATCH 2/2] AG-15983 - AgInput - Allow auto complete for individual features (#14910) * AG-15983 - AgInput - Allow auto complete for individual features * improved docs --- .../src/content/docs-nav/nav.json | 5 + .../src/content/docs/cell-editors/index.mdoc | 2 + .../docs/filter-set-mini-filter/index.mdoc | 2 + .../src/content/docs/filter-text/index.mdoc | 2 + .../src/content/docs/find/index.mdoc | 2 + .../content/docs/floating-filters/index.mdoc | 18 +- .../src/content/docs/input-fields/index.mdoc | 59 +++++ .../src/content/docs/tool-panel/index.mdoc | 2 + .../src/content/docs/toolbar/index.mdoc | 2 + .../src/edit/cellEditors/dateCellEditor.ts | 4 +- .../edit/cellEditors/dateStringCellEditor.ts | 4 +- .../src/edit/cellEditors/iDateCellEditor.ts | 4 +- .../edit/cellEditors/iDateStringCellEditor.ts | 8 +- .../edit/cellEditors/iLargeTextCellEditor.ts | 3 +- .../src/edit/cellEditors/iNumberCellEditor.ts | 8 +- .../src/edit/cellEditors/iTextCellEditor.ts | 8 +- .../edit/cellEditors/largeTextCellEditor.ts | 3 +- .../src/edit/cellEditors/numberCellEditor.ts | 5 +- .../src/edit/cellEditors/textCellEditor.ts | 6 +- .../provided/textInputFloatingFilter.ts | 2 +- .../filter/provided/bigInt/bigIntFilter.ts | 1 + .../provided/date/defaultDateComponent.ts | 2 + .../src/filter/provided/iSimpleFilter.ts | 3 +- .../filter/provided/number/numberFilter.ts | 14 +- .../src/filter/provided/simpleFilter.ts | 6 + .../src/filter/provided/text/iTextFilter.ts | 15 +- .../src/filter/provided/text/textFilter.ts | 2 +- .../src/interfaces/iAutoComplete.ts | 17 ++ .../src/interfaces/iSetFilter.ts | 3 +- .../src/interfaces/iToolPanel.ts | 5 +- .../src/interfaces/iToolbar.ts | 31 ++- .../ag-grid-community/src/main-internal.ts | 1 + packages/ag-grid-community/src/main.ts | 3 + .../columnToolPanel/agPrimaryColsHeader.ts | 1 + .../agFiltersToolPanelHeader.ts | 1 + .../src/setFilter/setFilter.ts | 5 +- .../toolbar/providedItems/findToolbarItem.ts | 14 +- .../providedItems/quickFilterToolbarItem.ts | 13 +- .../cell-editing-edge-cases.test.ts | 55 +++++ .../browser-autocomplete-params.test.ts | 211 ++++++++++++++++++ .../src/toolbar/toolbar-find.test.ts | 29 +++ .../src/toolbar/toolbar-quick-filter.test.ts | 15 ++ 42 files changed, 533 insertions(+), 63 deletions(-) create mode 100644 documentation/ag-grid-docs/src/content/docs/input-fields/index.mdoc create mode 100644 packages/ag-grid-community/src/interfaces/iAutoComplete.ts create mode 100644 testing/behavioural/src/filters/browser-autocomplete-params.test.ts diff --git a/documentation/ag-grid-docs/src/content/docs-nav/nav.json b/documentation/ag-grid-docs/src/content/docs-nav/nav.json index 947a0ae07da..1c3170ea712 100644 --- a/documentation/ag-grid-docs/src/content/docs-nav/nav.json +++ b/documentation/ag-grid-docs/src/content/docs-nav/nav.json @@ -1204,6 +1204,11 @@ "title": "Touch", "path": "touch" }, + { + "type": "item", + "title": "Input Fields", + "path": "input-fields" + }, { "type": "item", "title": "Accessibility (ARIA)", diff --git a/documentation/ag-grid-docs/src/content/docs/cell-editors/index.mdoc b/documentation/ag-grid-docs/src/content/docs/cell-editors/index.mdoc index b7961f87344..dfe3fc6f246 100644 --- a/documentation/ag-grid-docs/src/content/docs/cell-editors/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/cell-editors/index.mdoc @@ -9,6 +9,8 @@ The example below shows some Provided Editor Components and some Custom Editor C {% gridExampleRunner title="Simple Editor Components" name="component-editor-2" exampleHeight=370 /%} +The provided editors' input fields share the grid-wide input behaviour (clear button on supported inputs, browser autocomplete) described in [Input Fields](./input-fields/). + ## Custom Components {% partial file="./_component-interface-javascript.mdoc" /%} diff --git a/documentation/ag-grid-docs/src/content/docs/filter-set-mini-filter/index.mdoc b/documentation/ag-grid-docs/src/content/docs/filter-set-mini-filter/index.mdoc index 6b47c68eee3..2d3f426088e 100644 --- a/documentation/ag-grid-docs/src/content/docs/filter-set-mini-filter/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/filter-set-mini-filter/index.mdoc @@ -118,6 +118,8 @@ The example below shows this text being customised: {% gridExampleRunner title="Text Customisation" name="text-customisation" /%} +The Mini Filter input shares the grid-wide input behaviour (clear button, browser autocomplete) described in [Input Fields](./input-fields/). + ## Hiding the Mini Filter By default, the Mini Filter is shown whenever the Set Filter is used. If you would like to hide it, you can use the following: diff --git a/documentation/ag-grid-docs/src/content/docs/filter-text/index.mdoc b/documentation/ag-grid-docs/src/content/docs/filter-text/index.mdoc index 1f0dc8b45dd..e724c14b43b 100644 --- a/documentation/ag-grid-docs/src/content/docs/filter-text/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/filter-text/index.mdoc @@ -54,6 +54,8 @@ The following example demonstrates configuring different Text Filter parameters: {% gridExampleRunner title="Text Filter Parameters" name="text-filter-parameters" /%} +Filter input fields share the grid-wide input behaviour (clear button, browser autocomplete) described in [Input Fields](./input-fields/). + ## Text Formatter By default, the grid compares the Text Filter with the values in a case-insensitive way, by converting both the filter text and the values to lower case and comparing them; for example, `'o'` will match `'Olivia'` and `'Salmon'`. If you instead want to have case-sensitive matches, you can set `caseSensitive = true` in the `filterParams`, so that no lowercasing is performed. In this case, `'o'` would no longer match `'Olivia'`. diff --git a/documentation/ag-grid-docs/src/content/docs/find/index.mdoc b/documentation/ag-grid-docs/src/content/docs/find/index.mdoc index e636605cd4d..19dbc5360d4 100644 --- a/documentation/ag-grid-docs/src/content/docs/find/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/find/index.mdoc @@ -53,6 +53,8 @@ The active match and the total number of matches can also be retrieved via the A {% gridExampleRunner title="Find" name="find" /%} +The Find input shares the grid-wide input behaviour (clear button, browser autocomplete) described in [Input Fields](./input-fields/). + ## Using Find with Cell Components By default, Find searches within the [Formatted Value](./value-formatters/) of the cell, or the raw cell value if there is no Value Formatter. This is what is displayed in the cell by default. diff --git a/documentation/ag-grid-docs/src/content/docs/floating-filters/index.mdoc b/documentation/ag-grid-docs/src/content/docs/floating-filters/index.mdoc index 2f70d5925d0..f50277f0dce 100644 --- a/documentation/ag-grid-docs/src/content/docs/floating-filters/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/floating-filters/index.mdoc @@ -70,19 +70,13 @@ The screen shots below show example scenarios where the provided Number floating ### Controlling Autocomplete on Floating Filters -Browser autocomplete is disabled for grid input fields by default. Set `enableInputAutoComplete` to `true` to enable it for eligible inputs. Inputs that provide grid-owned suggestions, such as Rich Select and Advanced Filter inputs, keep browser autocomplete disabled so the browser UI cannot overlap their suggestion lists. +Browser autocomplete on grid inputs is controlled globally by `enableInputAutoComplete` and per input with +`browserAutoComplete` parameters, see [Input Fields](./input-fields/) for the full behaviour and the accepted values. -The `Text` and `Number` floating filters also support overriding this behaviour for an individual input by passing the -`browserAutoComplete` parameter in `floatingFilterComponentParams` (as defined in `ITextFloatingFilterParams` and -`INumberFloatingFilterParams`). - -Possible values for `browserAutoComplete`: - -- `true` to allow the browser's default autocomplete/autofill behaviour. -- `false` to disable the browser autocomplete/autofill behaviour by setting the `autocomplete` attribute to `off`. -- A **string** to be used as the [autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) attribute value. - -Some browsers do not respect setting the HTML attribute `autocomplete="off"` and display the auto-fill prompts anyway. +For floating filters specifically, `browserAutoComplete` can be set in two places: `filterParams` (shared with the +parent filter's inputs, and inherited by the floating filter input) or `floatingFilterComponentParams` (as defined in +`ITextFloatingFilterParams` and `INumberFloatingFilterParams`), which applies to the floating filter input only and +takes precedence over the `filterParams` value. ### Placeholder Text on Floating Filters diff --git a/documentation/ag-grid-docs/src/content/docs/input-fields/index.mdoc b/documentation/ag-grid-docs/src/content/docs/input-fields/index.mdoc new file mode 100644 index 00000000000..3346221769c --- /dev/null +++ b/documentation/ag-grid-docs/src/content/docs/input-fields/index.mdoc @@ -0,0 +1,59 @@ +--- +title: "Input Fields" +--- + +The grid renders text input fields in many features: column filters, floating filters, the Set Filter Mini Filter, +cell editors, tool panel search boxes and toolbar items. This page describes the behaviour these inputs share and how +to configure it, globally or per input. + +## Clear Button + +Supported input fields show a clear button when they contain a value. Clicking it clears the input, keeps focus in the +field, and applies the change immediately, for example, a filter input clears its filter without waiting for the +typing debounce. When a filter has an Apply button, clearing updates the input but the filter model is only changed +once **Apply** is clicked. + +Set `suppressInputClearButton` to `true` to hide the clear button across the grid: + +{% apiDocumentation source="grid-options/properties.json" section="miscellaneous" names=["suppressInputClearButton"] /%} + +Date inputs only show the clear button when a text input is used (`browserDatePicker` disabled); native browser date +pickers provide their own clear affordance. + +## Browser Autocomplete + +Browser autocomplete/autofill is disabled for grid input fields by default. Set `enableInputAutoComplete` to `true` to +enable it for eligible inputs: + +{% apiDocumentation source="grid-options/properties.json" section="miscellaneous" names=["enableInputAutoComplete"] /%} + +Inputs that provide grid-owned suggestions — the Rich Select editor with `allowTyping`, the Advanced Filter input, and +the Calculated Columns expression editor — always keep browser autocomplete disabled so the browser UI cannot overlap +their suggestion lists. + +### Overriding Autocomplete per Input + +Individual inputs can override the global behaviour with a `browserAutoComplete` parameter: + +| Input | Where to set `browserAutoComplete` | +| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| Provided cell editors (text, number, date, date string, large text) | `colDef.cellEditorParams` | +| Provided filter inputs (text, number, date, bigint) | `colDef.filterParams` | +| Text / Number floating filters | `colDef.floatingFilterComponentParams` (takes precedence over the `filterParams` value, which floating filter inputs otherwise inherit) | +| Set Filter Mini Filter | `colDef.filterParams` | +| Columns / Filters Tool Panel search | the tool panel's `toolPanelParams` | +| Find and Quick Filter toolbar items | the item definition's `toolbarItemParams` | + +Possible values for `browserAutoComplete`: + +- `true` to allow the browser's default autocomplete/autofill behaviour. +- `false` to disable the browser autocomplete/autofill behaviour by setting the `autocomplete` attribute to `off`. +- A **string** to be used as the [autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) attribute value, e.g. `'email'` on a cell editor. + +A `browserAutoComplete` value always wins over `enableInputAutoComplete`, in both directions: with the option +disabled, `browserAutoComplete: true` enables autofill for that input alone, and with the option enabled, +`browserAutoComplete: false` disables it for that input alone. Omitting the parameter defers to the option. + +Some browsers do not respect setting the HTML attribute `autocomplete="off"` and display the auto-fill prompts anyway. + +Custom components render their own inputs, so these options do not apply to them. diff --git a/documentation/ag-grid-docs/src/content/docs/tool-panel/index.mdoc b/documentation/ag-grid-docs/src/content/docs/tool-panel/index.mdoc index 2e135d6f9e3..3ab43435213 100644 --- a/documentation/ag-grid-docs/src/content/docs/tool-panel/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/tool-panel/index.mdoc @@ -19,6 +19,8 @@ The grid provides the following Tool Panels: - [Filters Tool Panel](./tool-panel-filters/) - to perform multiple column filters. - [New Filters Tool Panel](./tool-panel-filters-new/) - a redesigned version of the Filters Tool Panel that provides improved UX. +The provided tool panels' search inputs share the grid-wide input behaviour (clear button, browser autocomplete) described in [Input Fields](./input-fields/). + ## Custom Tool Panels In addition to the provided Tool Panels, it is also possible to provide custom Tool Panels. diff --git a/documentation/ag-grid-docs/src/content/docs/toolbar/index.mdoc b/documentation/ag-grid-docs/src/content/docs/toolbar/index.mdoc index 3f7adb3186f..d2a79ed206d 100644 --- a/documentation/ag-grid-docs/src/content/docs/toolbar/index.mdoc +++ b/documentation/ag-grid-docs/src/content/docs/toolbar/index.mdoc @@ -71,6 +71,8 @@ A number of built-in toolbar items are provided for common use cases that integr | [`agMenuToolbarItem`](#dropdown-menus) | Button that opens a [dropdown menu](#dropdown-menus). | `ContextMenuModule` or `ColumnMenuModule` | | `separator` | Vertical divider used to group items visually. Has no behaviour of its own. | None | +The Find and Quick Filter items' inputs share the grid-wide input behaviour (clear button, browser autocomplete) described in [Input Fields](./input-fields/). + ### Row Group and Pivot Panels The Row Group Panel and Pivot Panel can both be embedded in the Quick Access Toolbar using `agRowGroupPanelToolbarItem` and `agPivotPanelToolbarItem`. Both panels are configured independently of the [Row Group Panel](./grouping-group-panel/) and the [Pivot Panel](./pivoting/#enabling-the-pivot-panel/), so you can display each panel in the Toolbar, above the grid, or both at the same time. diff --git a/packages/ag-grid-community/src/edit/cellEditors/dateCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/dateCellEditor.ts index 0fafaaac8c6..6031d05e1eb 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/dateCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/dateCellEditor.ts @@ -36,7 +36,9 @@ class DateCellEditorInput implements CellEditorInput extends ICellEditorParams { +export interface IDateCellEditorParams + extends ICellEditorParams, IAutoCompleteComponentParams { /** Min allowed value. Either `Date` object or string in format `'yyyy-mm-dd'`. */ min?: string | Date; /** Max allowed value. Either `Date` object or string in format `'yyyy-mm-dd'`. */ diff --git a/packages/ag-grid-community/src/edit/cellEditors/iDateStringCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/iDateStringCellEditor.ts index 1e758804edb..96fad3442dd 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/iDateStringCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/iDateStringCellEditor.ts @@ -1,10 +1,8 @@ +import type { IAutoCompleteComponentParams } from '../../interfaces/iAutoComplete'; import type { ICellEditorParams } from '../../interfaces/iCellEditor'; -export interface IDateStringCellEditorParams extends ICellEditorParams< - TData, - string, - TContext -> { +export interface IDateStringCellEditorParams + extends ICellEditorParams, IAutoCompleteComponentParams { /** Min allowed value. Either `Date` object or string in format `'yyyy-mm-dd'`. */ min?: string | Date; /** Max allowed value. Either `Date` object or string in format `'yyyy-mm-dd'`. */ diff --git a/packages/ag-grid-community/src/edit/cellEditors/iLargeTextCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/iLargeTextCellEditor.ts index fd7f5ce42f2..3aef7f74e27 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/iLargeTextCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/iLargeTextCellEditor.ts @@ -1,6 +1,7 @@ +import type { IAutoCompleteComponentParams } from '../../interfaces/iAutoComplete'; import type { ICellEditorParams } from '../../interfaces/iCellEditor'; -export interface ILargeTextEditorParams extends ICellEditorParams { +export interface ILargeTextEditorParams extends ICellEditorParams, IAutoCompleteComponentParams { /** * Max number of characters to allow. * @default 200 diff --git a/packages/ag-grid-community/src/edit/cellEditors/iNumberCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/iNumberCellEditor.ts index ed8d11cedee..ac0e34c708c 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/iNumberCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/iNumberCellEditor.ts @@ -1,10 +1,8 @@ +import type { IAutoCompleteComponentParams } from '../../interfaces/iAutoComplete'; import type { ICellEditorParams } from '../../interfaces/iCellEditor'; -export interface INumberCellEditorParams extends ICellEditorParams< - TData, - number, - TContext -> { +export interface INumberCellEditorParams + extends ICellEditorParams, IAutoCompleteComponentParams { /** Min allowed value. */ min?: number; /** Max allowed value. */ diff --git a/packages/ag-grid-community/src/edit/cellEditors/iTextCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/iTextCellEditor.ts index 9501004447c..36e6cc81a29 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/iTextCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/iTextCellEditor.ts @@ -1,10 +1,8 @@ +import type { IAutoCompleteComponentParams } from '../../interfaces/iAutoComplete'; import type { ICellEditorParams } from '../../interfaces/iCellEditor'; -export interface ITextCellEditorParams extends ICellEditorParams< - TData, - TValue, - TContext -> { +export interface ITextCellEditorParams + extends ICellEditorParams, IAutoCompleteComponentParams { /** If `true`, the editor will use the provided `colDef.valueFormatter` to format the value displayed in the editor. * Used when the cell value needs formatting prior to editing, such as when using reference data and you * want to display text rather than code. */ diff --git a/packages/ag-grid-community/src/edit/cellEditors/largeTextCellEditor.ts b/packages/ag-grid-community/src/edit/cellEditors/largeTextCellEditor.ts index 16656f5acaa..5e95e76668d 100644 --- a/packages/ag-grid-community/src/edit/cellEditors/largeTextCellEditor.ts +++ b/packages/ag-grid-community/src/edit/cellEditors/largeTextCellEditor.ts @@ -32,7 +32,7 @@ export class LargeTextCellEditor extends AgAbstractCellEditor implements CellEditorInput< public init(eEditor: GridInputTextField, params: ITextCellEditorParams): void { this.eEditor = eEditor; this.params = params; - const maxLength = params.maxLength; + + const { maxLength, browserAutoComplete } = params; + + eEditor.setAutoComplete(browserAutoComplete); + if (maxLength != null) { eEditor.setMaxLength(maxLength); } diff --git a/packages/ag-grid-community/src/filter/floating/provided/textInputFloatingFilter.ts b/packages/ag-grid-community/src/filter/floating/provided/textInputFloatingFilter.ts index d2d189416b6..fe3d8840cb5 100644 --- a/packages/ag-grid-community/src/filter/floating/provided/textInputFloatingFilter.ts +++ b/packages/ag-grid-community/src/filter/floating/provided/textInputFloatingFilter.ts @@ -80,7 +80,7 @@ export abstract class TextInputFloatingFilter< inputSvc.setParams({ ariaLabel: this.getAriaLabel(column as AgColumn), - autoComplete: browserAutoComplete, + autoComplete: browserAutoComplete ?? (filterParams as TextFilterParams).browserAutoComplete, placeholder, }); diff --git a/packages/ag-grid-community/src/filter/provided/bigInt/bigIntFilter.ts b/packages/ag-grid-community/src/filter/provided/bigInt/bigIntFilter.ts index 1497349a829..690840e7591 100644 --- a/packages/ag-grid-community/src/filter/provided/bigInt/bigIntFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/bigInt/bigIntFilter.ts @@ -157,6 +157,7 @@ export class BigIntFilter extends SimpleFilter< allowedCharPattern: allowedCharPattern ?? undefined, clearButton: true, searchIcon: true, + autoComplete: this.params.browserAutoComplete, }) ); eValue.addCss(`ag-filter-${fromTo}`); diff --git a/packages/ag-grid-community/src/filter/provided/date/defaultDateComponent.ts b/packages/ag-grid-community/src/filter/provided/date/defaultDateComponent.ts index 6257f5bfb82..55df53d6fb4 100644 --- a/packages/ag-grid-community/src/filter/provided/date/defaultDateComponent.ts +++ b/packages/ag-grid-community/src/filter/provided/date/defaultDateComponent.ts @@ -91,6 +91,8 @@ export class DefaultDateComponent extends Component implements IDateComp { } private setParams(params: IDateParams): void { + // re-applied on refresh so params updates re-pin (or clear) the override + this.eDateInput.setAutoComplete(params.filterParams?.browserAutoComplete); const inputElement = this.eDateInput.getInputElement(); const shouldUseBrowserDatePicker = this.shouldUseBrowserDatePicker(params); diff --git a/packages/ag-grid-community/src/filter/provided/iSimpleFilter.ts b/packages/ag-grid-community/src/filter/provided/iSimpleFilter.ts index 7f34d123758..54d445654df 100644 --- a/packages/ag-grid-community/src/filter/provided/iSimpleFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/iSimpleFilter.ts @@ -1,3 +1,4 @@ +import type { IAutoCompleteComponentParams } from '../../interfaces/iAutoComplete'; import type { IFilterParams } from '../../interfaces/iFilter'; import type { IFloatingFilterParent } from '../floating/floatingFilter'; import type { IProvidedFilter, IProvidedFilterParams, ProvidedFilterModel } from './iProvidedFilter'; @@ -46,7 +47,7 @@ export type SimpleFilterParams = ISimpleFilterParams & IFilterParam /** * Common parameters in `colDef.filterParams` used by all simple filters. Extended by the specific filter types. */ -export interface ISimpleFilterParams extends IProvidedFilterParams { +export interface ISimpleFilterParams extends IProvidedFilterParams, IAutoCompleteComponentParams { /** * Array of filter options to present to the user. * A key the filter cannot evaluate is reported when a value is tested against it under the built-in matching. diff --git a/packages/ag-grid-community/src/filter/provided/number/numberFilter.ts b/packages/ag-grid-community/src/filter/provided/number/numberFilter.ts index 7829814638e..93fdac6e401 100644 --- a/packages/ag-grid-community/src/filter/provided/number/numberFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/number/numberFilter.ts @@ -155,10 +155,20 @@ export class NumberFilter extends SimpleFilter< fromTo: string, allowedCharPattern: string | null ): GridInputTextField | GridInputNumberField { + const { browserAutoComplete } = this.params; const eValue = this.createManagedBean( allowedCharPattern - ? new AgInputTextField({ allowedCharPattern, clearButton: true, searchIcon: true }) - : new AgInputNumberField({ clearButton: true, searchIcon: true }) + ? new AgInputTextField({ + allowedCharPattern, + clearButton: true, + searchIcon: true, + autoComplete: browserAutoComplete, + }) + : new AgInputNumberField({ + clearButton: true, + searchIcon: true, + autoComplete: browserAutoComplete, + }) ); eValue.addCss(`ag-filter-${fromTo}`); eValue.addCss('ag-filter-filter'); diff --git a/packages/ag-grid-community/src/filter/provided/simpleFilter.ts b/packages/ag-grid-community/src/filter/provided/simpleFilter.ts index 074f969ebec..1a88afdfb87 100644 --- a/packages/ag-grid-community/src/filter/provided/simpleFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/simpleFilter.ts @@ -134,6 +134,12 @@ export abstract class SimpleFilter< protected commonUpdateSimpleParams(params: P): void { this.setNumConditions(params); + this.forEachInput((element) => { + if (element instanceof AgAbstractInputField) { + element.setAutoComplete(params.browserAutoComplete); + } + }); + this.defaultJoinOperator = getDefaultJoinOperator(params.defaultJoinOperator); this.filterPlaceholder = params.filterPlaceholder; diff --git a/packages/ag-grid-community/src/filter/provided/text/iTextFilter.ts b/packages/ag-grid-community/src/filter/provided/text/iTextFilter.ts index 1842001f33e..d8500ce31bd 100644 --- a/packages/ag-grid-community/src/filter/provided/text/iTextFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/text/iTextFilter.ts @@ -1,4 +1,5 @@ import type { BaseColDefParams } from '../../../entities/colDef'; +import type { IAutoCompleteComponentParams } from '../../../interfaces/iAutoComplete'; import type { IFilterParams } from '../../../interfaces/iFilter'; import type { IFloatingFilterParams } from '../../floating/floatingFilter'; import type { @@ -94,17 +95,7 @@ export interface ITextFilterParams extends ISimpleFilterParams { trimInput?: boolean; } -export interface ITextInputFloatingFilterParams extends IFloatingFilterParams { - /** - * Overrides the browser's autocomplete/autofill behaviour by updating the autocomplete attribute on the input field used in the floating filter input. - * Possible values are: - * - `true` to allow the **default** browser autocomplete/autofill behaviour. - * - `false` to disable the browser autocomplete/autofill behavior by setting the `autocomplete` attribute to `off`. - * - A **string** to be used as the [autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) attribute value. - * If omitted, the value of `enableInputAutoComplete` is used. - * Some browsers do not respect setting the HTML attribute `autocomplete="off"` and display the auto-fill prompts anyway. - */ - browserAutoComplete?: boolean | string; -} +export interface ITextInputFloatingFilterParams + extends IFloatingFilterParams, IAutoCompleteComponentParams {} export interface ITextFloatingFilterParams extends ITextInputFloatingFilterParams {} diff --git a/packages/ag-grid-community/src/filter/provided/text/textFilter.ts b/packages/ag-grid-community/src/filter/provided/text/textFilter.ts index 1bc43ad86f1..1bc66142764 100644 --- a/packages/ag-grid-community/src/filter/provided/text/textFilter.ts +++ b/packages/ag-grid-community/src/filter/provided/text/textFilter.ts @@ -82,7 +82,7 @@ export class TextFilter extends SimpleFilter( - new AgInputTextField({ clearButton: true, searchIcon: true }) + new AgInputTextField({ clearButton: true, searchIcon: true, autoComplete: this.params.browserAutoComplete }) ); eValue.addCss(`ag-filter-${fromTo}`); eValue.addCss('ag-filter-filter'); diff --git a/packages/ag-grid-community/src/interfaces/iAutoComplete.ts b/packages/ag-grid-community/src/interfaces/iAutoComplete.ts new file mode 100644 index 00000000000..e447dc4599b --- /dev/null +++ b/packages/ag-grid-community/src/interfaces/iAutoComplete.ts @@ -0,0 +1,17 @@ +/** + * Params for components whose input fields support overriding the browser's + * autocomplete/autofill behaviour. + * @internal AG_GRID_INTERNAL - Not for public use. Can change / be removed at any time. + */ +export interface IAutoCompleteComponentParams { + /** + * Overrides the browser's autocomplete/autofill behaviour by updating the `autocomplete` attribute on the component's input field(s). + * Possible values are: + * - `true` to allow the **default** browser autocomplete/autofill behaviour. + * - `false` to disable the browser autocomplete/autofill behaviour by setting the `autocomplete` attribute to `off`. + * - A **string** to be used as the [autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) attribute value. + * If omitted, the value of `enableInputAutoComplete` is used. + * Some browsers do not respect setting the HTML attribute `autocomplete="off"` and display the auto-fill prompts anyway. + */ + browserAutoComplete?: boolean | string; +} diff --git a/packages/ag-grid-community/src/interfaces/iSetFilter.ts b/packages/ag-grid-community/src/interfaces/iSetFilter.ts index 4184a580f61..b4f45a9d870 100644 --- a/packages/ag-grid-community/src/interfaces/iSetFilter.ts +++ b/packages/ag-grid-community/src/interfaces/iSetFilter.ts @@ -5,6 +5,7 @@ import type { FilterUiChangedEvent } from '../events'; import type { IProvidedFilter, IProvidedFilterParams, ProvidedFilterModel } from '../filter/provided/iProvidedFilter'; import type { Column } from '../interfaces/iColumn'; import type { ITooltipParams } from '../tooltip/tooltipComponent'; +import type { IAutoCompleteComponentParams } from './iAutoComplete'; import type { AgGridCommon } from './iCommon'; import type { IFilterParams } from './iFilter'; @@ -134,7 +135,7 @@ export type SetFilterParams = ISetFilterParams extends IProvidedFilterParams { +export interface ISetFilterParams extends IProvidedFilterParams, IAutoCompleteComponentParams { /** * The values to display in the Filter List. If this is not set, the filter will take its * values from what is loaded in the table. diff --git a/packages/ag-grid-community/src/interfaces/iToolPanel.ts b/packages/ag-grid-community/src/interfaces/iToolPanel.ts index 27c8dee0b93..722287b1687 100644 --- a/packages/ag-grid-community/src/interfaces/iToolPanel.ts +++ b/packages/ag-grid-community/src/interfaces/iToolPanel.ts @@ -1,5 +1,6 @@ import type { IComponent } from 'ag-stack'; +import type { IAutoCompleteComponentParams } from './iAutoComplete'; import type { IColumnSelectionPanelParams } from './iColumnSelectionPanel'; import type { AgGridCommon } from './iCommon'; import type { FilterAction } from './iFilter'; @@ -37,7 +38,7 @@ export interface IToolPanel { export interface IToolPanelComp extends IToolPanel, IComponent> {} -export interface IToolPanelColumnCompParams extends IColumnSelectionPanelParams { +export interface IToolPanelColumnCompParams extends IColumnSelectionPanelParams, IAutoCompleteComponentParams { /** Suppress Column Move */ suppressColumnMove?: boolean; /** Suppress Row Groups section */ @@ -52,7 +53,7 @@ export interface IToolPanelColumnCompParams extends IColumnSelectionPanelParams buttons?: ColumnToolPanelAction[]; } -export interface IToolPanelFiltersCompParams { +export interface IToolPanelFiltersCompParams extends IAutoCompleteComponentParams { /** To suppress Expand / Collapse All */ suppressExpandAll: boolean; /** To suppress the Filter Search */ diff --git a/packages/ag-grid-community/src/interfaces/iToolbar.ts b/packages/ag-grid-community/src/interfaces/iToolbar.ts index e04d3251a0a..494c163523a 100644 --- a/packages/ag-grid-community/src/interfaces/iToolbar.ts +++ b/packages/ag-grid-community/src/interfaces/iToolbar.ts @@ -2,6 +2,7 @@ import type { IComponent } from 'ag-stack'; import type { ToolbarItemComponentName } from '../context/context'; import type { IconName } from '../utils/icon'; +import type { IAutoCompleteComponentParams } from './iAutoComplete'; import type { AgGridCommon } from './iCommon'; import type { DefaultMenuItem, MenuItemDef } from './menuItem'; @@ -81,7 +82,7 @@ export interface ToolbarMenuItemParams { export interface ToolbarBuiltInItemDef extends ToolbarItemDefBase { /** A built-in toolbar item component name, or `'separator'`. */ toolbarItem: Exclude | 'separator'; - /** Built-in items (other than `agMenuToolbarItem`) do not accept params. */ + /** Not accepted here — `agMenuToolbarItem` and the input items take params via their dedicated variants. */ toolbarItemParams?: never; /** Not used for built-in items — use the Action Button variant for label/icon/action. */ label?: never; @@ -111,6 +112,26 @@ export interface ToolbarMenuBuiltInItemDef extends action?: never; } +/** The built-in toolbar items that render a text input. */ +export type InputToolbarItemName = 'agFindToolbarItem' | 'agQuickFilterToolbarItem'; + +/** + * Reference to a built-in input toolbar item (`agFindToolbarItem`, `agQuickFilterToolbarItem`), + * with `toolbarItemParams` carrying the input configuration. + */ +export interface ToolbarInputBuiltInItemDef extends ToolbarItemDefBase { + /** A built-in input toolbar item component name. */ + toolbarItem: InputToolbarItemName; + /** Configuration for the input (e.g. `browserAutoComplete`). */ + toolbarItemParams?: IInputToolbarItemParams; + /** Not used for input items — use the Action Button variant for label/icon/action. */ + label?: never; + /** Not used for input items — use the Action Button variant for label/icon/action. */ + icon?: never; + /** Not used for input items — use the Action Button variant for label/icon/action. */ + action?: never; +} + /** * Reference to a user-provided custom toolbar item component. * `toolbarItem` is a component class/function, or the name of a registered custom component. @@ -133,14 +154,22 @@ export interface ToolbarCustomItemDef extends Tool * - {@link ToolbarButtonItemDef} — action button shorthand (`label`/`icon`/`action`) * - {@link ToolbarBuiltInItemDef} — reference to a built-in component or `'separator'` * - {@link ToolbarMenuBuiltInItemDef} — reference to the `agMenuToolbarItem` dropdown menu button + * - {@link ToolbarInputBuiltInItemDef} — reference to a built-in input item (`agFindToolbarItem`, `agQuickFilterToolbarItem`) * - {@link ToolbarCustomItemDef} — reference to a custom component */ export type ToolbarItemDef = | ToolbarButtonItemDef | ToolbarBuiltInItemDef | ToolbarMenuBuiltInItemDef + | ToolbarInputBuiltInItemDef | ToolbarCustomItemDef; +/** + * Params accepted by the provided input toolbar items (`agFindToolbarItem`, `agQuickFilterToolbarItem`), + * supplied via the item definition's `toolbarItemParams`. + */ +export interface IInputToolbarItemParams extends IAutoCompleteComponentParams {} + /** * Params delivered to a toolbar item component. Mirrors the runtime shape produced by the * grid: a flat object containing the item-definition fields the grid forwards, merged with diff --git a/packages/ag-grid-community/src/main-internal.ts b/packages/ag-grid-community/src/main-internal.ts index 97ad16a70da..1594d16c414 100644 --- a/packages/ag-grid-community/src/main-internal.ts +++ b/packages/ag-grid-community/src/main-internal.ts @@ -312,6 +312,7 @@ export type { IShowValuesAsService } from './interfaces/iShowValuesAsService'; export type { ISideBar, ISideBarService } from './interfaces/iSideBar'; export type { SortOption } from './interfaces/iSortOption'; export { _resolveSortOptions } from './sort/sortOptionUtils'; +export type { IAutoCompleteComponentParams } from './interfaces/iAutoComplete'; export type { IToolbarComp, IToolbarService } from './interfaces/iToolbar'; export type { IStickyRowFeature, IStickyRowService } from './interfaces/iStickyRows'; export type { ComponentType, UserCompDetails } from './interfaces/iUserCompDetails'; diff --git a/packages/ag-grid-community/src/main.ts b/packages/ag-grid-community/src/main.ts index 9eaa3579154..a8c464711e4 100644 --- a/packages/ag-grid-community/src/main.ts +++ b/packages/ag-grid-community/src/main.ts @@ -489,9 +489,12 @@ export type { export type { IToolbarItem, IToolbarItemComp, + IInputToolbarItemParams, + InputToolbarItemName, IToolbarItemParams, Toolbar, ToolbarBuiltInItemDef, + ToolbarInputBuiltInItemDef, ToolbarButtonItemDef, ToolbarCustomItemDef, ToolbarItemActionParams, diff --git a/packages/ag-grid-enterprise/src/columnToolPanel/agPrimaryColsHeader.ts b/packages/ag-grid-enterprise/src/columnToolPanel/agPrimaryColsHeader.ts index bc7f6233a17..0c8404b0fe5 100644 --- a/packages/ag-grid-enterprise/src/columnToolPanel/agPrimaryColsHeader.ts +++ b/packages/ag-grid-enterprise/src/columnToolPanel/agPrimaryColsHeader.ts @@ -85,6 +85,7 @@ export class AgPrimaryColsHeader extends Component { public init(params: ToolPanelColumnCompParams): void { this.params = params; + this.eFilterTextField.setAutoComplete(params.browserAutoComplete); const readOnly = this.gos.get('functionsReadOnly'); this.eSelect.setReadOnly(readOnly); diff --git a/packages/ag-grid-enterprise/src/filterToolPanel/agFiltersToolPanelHeader.ts b/packages/ag-grid-enterprise/src/filterToolPanel/agFiltersToolPanelHeader.ts index 4da0fa3d969..eb504d8013e 100644 --- a/packages/ag-grid-enterprise/src/filterToolPanel/agFiltersToolPanelHeader.ts +++ b/packages/ag-grid-enterprise/src/filterToolPanel/agFiltersToolPanelHeader.ts @@ -64,6 +64,7 @@ export class AgFiltersToolPanelHeader extends Component super.updateParams(newParams, oldParams); this.updateMiniFilter(); + this.eMiniFilter.setAutoComplete(newParams.browserAutoComplete); if (newParams.suppressSelectAll !== oldParams.suppressSelectAll) { this.createVirtualListModel(newParams); @@ -581,9 +582,9 @@ export class SetFilter } private initMiniFilter() { - const { eMiniFilter } = this; + const { eMiniFilter, params } = this; - eMiniFilter.setClearButtonEnabled(true).setSearchIcon(true); + eMiniFilter.setClearButtonEnabled(true).setSearchIcon(true).setAutoComplete(params.browserAutoComplete); this.updateMiniFilter(); eMiniFilter.onValueChange(() => this.onMiniFilterInput()).onValueClear(() => this.onMiniFilterInput(true)); eMiniFilter.setInputAriaLabel(translateForSetFilter(this, 'ariaSearchFilterValues')); diff --git a/packages/ag-grid-enterprise/src/toolbar/providedItems/findToolbarItem.ts b/packages/ag-grid-enterprise/src/toolbar/providedItems/findToolbarItem.ts index 96a8b60aaf1..f9be3d11d45 100644 --- a/packages/ag-grid-enterprise/src/toolbar/providedItems/findToolbarItem.ts +++ b/packages/ag-grid-enterprise/src/toolbar/providedItems/findToolbarItem.ts @@ -1,6 +1,12 @@ import { _debounce, _setDisabled } from 'ag-stack'; -import type { FindChangedEvent, GridInputTextField, IToolbarItemComp, IToolbarItemParams } from 'ag-grid-community'; +import type { + FindChangedEvent, + GridInputTextField, + IInputToolbarItemParams, + IToolbarItemComp, + IToolbarItemParams, +} from 'ag-grid-community'; import { AgInputTextField, Component, _createElement } from 'ag-grid-community'; import { createToolbarIconButton, createToolbarInput } from './toolbarItemUtils'; @@ -28,7 +34,7 @@ export class FindToolbarItem extends Component implements IToolbarItemComp { super({ tag: 'div', cls: 'ag-toolbar-item ag-toolbar-input ag-toolbar-find' }); } - public init(_params: IToolbarItemParams): void { + public init(params: IToolbarItemParams): void { if (!this.gos.isModuleRegistered('Find')) { this.beans.log.error(302, { itemName: 'agFindToolbarItem', @@ -49,6 +55,7 @@ export class FindToolbarItem extends Component implements IToolbarItemComp { this.eInputField = this.createManagedBean( new AgInputTextField({ clearButton: true, + autoComplete: params.toolbarItemParams?.browserAutoComplete, onValueClear: () => { clearTimeout(findSearchValueTimeout); flushFindSearchValue(); @@ -119,10 +126,11 @@ export class FindToolbarItem extends Component implements IToolbarItemComp { this.syncMatchState(); } - public refresh(_params: IToolbarItemParams): boolean { + public refresh(params: IToolbarItemParams): boolean { if (!this.eInput) { return false; } + this.eInputField.setAutoComplete(params.toolbarItemParams?.browserAutoComplete); this.eInputField.setValue(this.gos.get('findSearchValue'), true); this.syncMatchState(); return true; diff --git a/packages/ag-grid-enterprise/src/toolbar/providedItems/quickFilterToolbarItem.ts b/packages/ag-grid-enterprise/src/toolbar/providedItems/quickFilterToolbarItem.ts index 14202e30009..5beed020205 100644 --- a/packages/ag-grid-enterprise/src/toolbar/providedItems/quickFilterToolbarItem.ts +++ b/packages/ag-grid-enterprise/src/toolbar/providedItems/quickFilterToolbarItem.ts @@ -1,6 +1,11 @@ import { _debounce } from 'ag-stack'; -import type { GridInputTextField, IToolbarItemComp, IToolbarItemParams } from 'ag-grid-community'; +import type { + GridInputTextField, + IInputToolbarItemParams, + IToolbarItemComp, + IToolbarItemParams, +} from 'ag-grid-community'; import { AgInputTextField, Component } from 'ag-grid-community'; import { createToolbarInput } from './toolbarItemUtils'; @@ -15,7 +20,7 @@ export class QuickFilterToolbarItem extends Component implements IToolbarItemCom super({ tag: 'div', cls: 'ag-toolbar-item ag-toolbar-input' }); } - public init(_params: IToolbarItemParams): void { + public init(params: IToolbarItemParams): void { if (!this.gos.isModuleRegistered('QuickFilter')) { this.beans.log.error(302, { itemName: 'agQuickFilterToolbarItem', @@ -34,6 +39,7 @@ export class QuickFilterToolbarItem extends Component implements IToolbarItemCom this.eInputField = this.createManagedBean( new AgInputTextField({ clearButton: true, + autoComplete: params.toolbarItemParams?.browserAutoComplete, onValueClear: () => { clearTimeout(quickFilterTextTimeout); this.gos.updateGridOptions({ options: { quickFilterText: '' } }); @@ -62,10 +68,11 @@ export class QuickFilterToolbarItem extends Component implements IToolbarItemCom }); } - public refresh(_params: IToolbarItemParams): boolean { + public refresh(params: IToolbarItemParams): boolean { if (!this.eInput) { return false; } + this.eInputField.setAutoComplete(params.toolbarItemParams?.browserAutoComplete); this.eInputField.setValue(this.gos.get('quickFilterText'), true); return true; } diff --git a/testing/behavioural/src/cell-editing/cell-editing-edge-cases.test.ts b/testing/behavioural/src/cell-editing/cell-editing-edge-cases.test.ts index 6fcc57e7e4e..079eb9ca89f 100644 --- a/testing/behavioural/src/cell-editing/cell-editing-edge-cases.test.ts +++ b/testing/behavioural/src/cell-editing/cell-editing-edge-cases.test.ts @@ -993,4 +993,59 @@ describe('Cell Editing: edge cases', () => { // No such row, so no controller — the answer must still be about this cell. expect(api.isEditing({ rowIndex: 900, rowPinned: null, column: colA })).toBe(false); }); + + describe('editor input attributes', () => { + test('enableInputAutoComplete controls the editor input autocomplete attribute', async () => { + const api = await gridMgr.createGridAndWait('editor-autocomplete', { + columnDefs: [{ field: 'a', editable: true }], + rowData: [{ id: 'ROW_0', a: 'x' }], + getRowId: (params) => params.data.id, + enableInputAutoComplete: true, + }); + + api.startEditingCell({ rowIndex: 0, colKey: 'a' }); + await asyncSetTimeout(0); + const input = getGridElement(api)!.querySelector('.ag-text-field-input')!; + expect(input.getAttribute('autocomplete')).toBeNull(); + + // a live editor reacts to the option changing under it + api.setGridOption('enableInputAutoComplete', false); + expect(input.autocomplete).toBe('off'); + api.setGridOption('enableInputAutoComplete', true); + expect(input.getAttribute('autocomplete')).toBeNull(); + api.stopEditing(); + + // a freshly created editor reads the current value + api.setGridOption('enableInputAutoComplete', false); + api.startEditingCell({ rowIndex: 0, colKey: 'a' }); + await asyncSetTimeout(0); + const freshInput = getGridElement(api)!.querySelector('.ag-text-field-input')!; + expect(freshInput.autocomplete).toBe('off'); + }); + + test('cellEditorParams.browserAutoComplete overrides enableInputAutoComplete per column', async () => { + const api = await gridMgr.createGridAndWait('editor-autocomplete-override', { + columnDefs: [ + { field: 'a', editable: true, cellEditorParams: { browserAutoComplete: 'email' } }, + { field: 'b', editable: true }, + ], + rowData: [{ id: 'ROW_0', a: 'x', b: 'y' }], + getRowId: (params) => params.data.id, + enableInputAutoComplete: true, + }); + + api.startEditingCell({ rowIndex: 0, colKey: 'a' }); + await asyncSetTimeout(0); + const overridden = getGridElement(api)!.querySelector('.ag-text-field-input')!; + expect(overridden.getAttribute('autocomplete')).toBe('email'); + api.stopEditing(); + await asyncSetTimeout(0); + + // a column without the param defers to the grid option + api.startEditingCell({ rowIndex: 0, colKey: 'b' }); + await asyncSetTimeout(0); + const deferring = getGridElement(api)!.querySelector('.ag-text-field-input')!; + expect(deferring.getAttribute('autocomplete')).toBeNull(); + }); + }); }); diff --git a/testing/behavioural/src/filters/browser-autocomplete-params.test.ts b/testing/behavioural/src/filters/browser-autocomplete-params.test.ts new file mode 100644 index 00000000000..48638290ebc --- /dev/null +++ b/testing/behavioural/src/filters/browser-autocomplete-params.test.ts @@ -0,0 +1,211 @@ +import { getByTestId } from '@testing-library/dom'; +import { + ColumnFilterHarness, + TestGridsManager, + asyncSetTimeout, + installFilterLayoutMock, + uninstallFilterLayoutMock, +} from 'ag-test-utils'; + +import type { GridApi } from 'ag-grid-community'; +import { + ClientSideRowModelModule, + DateFilterModule, + TextFilterModule, + agTestIdFor, + getGridElement, + setupAgTestIds, +} from 'ag-grid-community'; +import { ColumnsToolPanelModule, FiltersToolPanelModule, SetFilterModule } from 'ag-grid-enterprise'; + +const ROW_DATA = [{ country: 'Ireland' }, { country: 'Italy' }]; + +/** + * Cross-surface coverage for the `browserAutoComplete` params: each user-facing input surface can + * override `enableInputAutoComplete` individually, and omitting the param defers to the option. + */ +describe('browserAutoComplete params', () => { + const gridsManager = new TestGridsManager({ + modules: [ + ClientSideRowModelModule, + DateFilterModule, + TextFilterModule, + SetFilterModule, + FiltersToolPanelModule, + ColumnsToolPanelModule, + ], + }); + + beforeAll(() => { + setupAgTestIds(); + installFilterLayoutMock(); + }); + afterAll(() => uninstallFilterLayoutMock()); + afterEach(() => gridsManager.reset()); + + test('filterParams overrides the option on filter body inputs and omitting defers', async () => { + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [ + { field: 'country', filter: 'agTextColumnFilter', filterParams: { browserAutoComplete: 'name' } }, + { colId: 'plain', field: 'country', filter: 'agTextColumnFilter' }, + ], + rowData: ROW_DATA, + enableInputAutoComplete: true, + }); + + const overridden = await ColumnFilterHarness.open(api, 'country'); + expect(overridden.input('text').getAttribute('autocomplete')).toBe('name'); + + const deferring = await ColumnFilterHarness.open(api, 'plain'); + expect(deferring.input('text').getAttribute('autocomplete')).toBeNull(); + + api.setGridOption('enableInputAutoComplete', false); + expect(deferring.input('text').getAttribute('autocomplete')).toBe('off'); + }); + + test('boolean overrides win in both directions and survive option toggles', async () => { + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [ + { + colId: 'on', + field: 'country', + filter: 'agTextColumnFilter', + filterParams: { browserAutoComplete: true }, + }, + { + colId: 'off', + field: 'country', + filter: 'agTextColumnFilter', + filterParams: { browserAutoComplete: false }, + }, + ], + rowData: ROW_DATA, + enableInputAutoComplete: false, + }); + + // option off, param true: enabled individually + const enabled = await ColumnFilterHarness.open(api, 'on'); + expect(enabled.input('text').getAttribute('autocomplete')).toBeNull(); + + // option on, param false: disabled individually + api.setGridOption('enableInputAutoComplete', true); + const disabled = await ColumnFilterHarness.open(api, 'off'); + expect(disabled.input('text').getAttribute('autocomplete')).toBe('off'); + + // overrides are pinned: further option toggles change neither + api.setGridOption('enableInputAutoComplete', false); + const enabledAgain = await ColumnFilterHarness.open(api, 'on'); + expect(enabledAgain.input('text').getAttribute('autocomplete')).toBeNull(); + const disabledAgain = await ColumnFilterHarness.open(api, 'off'); + expect(disabledAgain.input('text').getAttribute('autocomplete')).toBe('off'); + }); + + test('floating filter inputs inherit filterParams unless floatingFilterComponentParams overrides', async () => { + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [ + { + field: 'country', + filter: 'agTextColumnFilter', + floatingFilter: true, + filterParams: { browserAutoComplete: 'country-name' }, + }, + { + colId: 'both', + field: 'country', + filter: 'agTextColumnFilter', + floatingFilter: true, + filterParams: { browserAutoComplete: 'country-name' }, + floatingFilterComponentParams: { browserAutoComplete: false }, + }, + ], + rowData: ROW_DATA, + }); + await asyncSetTimeout(0); + + const gridDiv = getGridElement(api)! as HTMLElement; + const inherited = getByTestId( + gridDiv, + agTestIdFor.textFilterInstanceInput({ source: 'floating-filter', colId: 'country' }) + ) as HTMLInputElement; + expect(inherited.getAttribute('autocomplete')).toBe('country-name'); + + const overridden = getByTestId( + gridDiv, + agTestIdFor.textFilterInstanceInput({ source: 'floating-filter', colId: 'both' }) + ) as HTMLInputElement; + expect(overridden.getAttribute('autocomplete')).toBe('off'); + }); + + test('set filter mini filter honours filterParams.browserAutoComplete', async () => { + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [ + { field: 'country', filter: 'agSetColumnFilter', filterParams: { browserAutoComplete: true } }, + ], + rowData: ROW_DATA, + }); + + await ColumnFilterHarness.open(api, 'country'); + const miniFilterInput = document.querySelector('.ag-mini-filter input[type="text"]')!; + expect(miniFilterInput.getAttribute('autocomplete')).toBeNull(); + }); + + test('date inputs re-apply browserAutoComplete on filter params updates', async () => { + const dateColumn = { + field: 'when', + filter: 'agDateColumnFilter', + floatingFilter: true, + filterParams: { browserAutoComplete: 'bday' }, + }; + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [dateColumn], + rowData: [{ when: new Date(2020, 0, 1) }], + }); + await asyncSetTimeout(0); + + const gridDiv = getGridElement(api)! as HTMLElement; + const dateInput = gridDiv.querySelector('.ag-floating-filter .ag-date-filter input')!; + expect(dateInput.getAttribute('autocomplete')).toBe('bday'); + + api.setGridOption('columnDefs', [{ ...dateColumn, filterParams: {} }]); + await asyncSetTimeout(0); + expect(dateInput.getAttribute('autocomplete')).toBe('off'); + }); + + test('tool panel search inputs honour toolPanelParams.browserAutoComplete', async () => { + const api: GridApi = await gridsManager.createGridAndWait('grid1', { + columnDefs: [{ field: 'country', filter: 'agTextColumnFilter' }], + rowData: ROW_DATA, + sideBar: { + toolPanels: [ + { + id: 'filters', + labelDefault: 'Filters', + labelKey: 'filters', + iconKey: 'filter', + toolPanel: 'agFiltersToolPanel', + toolPanelParams: { browserAutoComplete: true }, + }, + { + id: 'columns', + labelDefault: 'Columns', + labelKey: 'columns', + iconKey: 'columns', + toolPanel: 'agColumnsToolPanel', + toolPanelParams: { browserAutoComplete: 'off-the-record' }, + }, + ], + defaultToolPanel: 'filters', + }, + }); + await asyncSetTimeout(0); + + const gridDiv = getGridElement(api)! as HTMLElement; + const filtersSearch = gridDiv.querySelector('.ag-filter-toolpanel-search input')!; + expect(filtersSearch.getAttribute('autocomplete')).toBeNull(); + + api.openToolPanel('columns'); + await asyncSetTimeout(0); + const columnsSearch = gridDiv.querySelector('.ag-column-select-header-filter-wrapper input')!; + expect(columnsSearch.getAttribute('autocomplete')).toBe('off-the-record'); + }); +}); diff --git a/testing/behavioural/src/toolbar/toolbar-find.test.ts b/testing/behavioural/src/toolbar/toolbar-find.test.ts index 45882797d55..ef41a590558 100644 --- a/testing/behavioural/src/toolbar/toolbar-find.test.ts +++ b/testing/behavioural/src/toolbar/toolbar-find.test.ts @@ -1,6 +1,7 @@ import { fireEvent } from '@testing-library/dom'; import { ALL_SEVERITIES, GridColumns, GridRows, TestGridsManager, waitForEvent } from 'ag-test-utils'; +import type { ToolbarBuiltInItemDef } from 'ag-grid-community'; import { ClientSideRowModelModule, enableDevValidations } from 'ag-grid-community'; import { FindModule, ToolbarModule } from 'ag-grid-enterprise'; @@ -44,6 +45,34 @@ describe('Toolbar find item', () => { `); }); + test('accepts pre-existing ToolbarBuiltInItemDef typing for input items', async () => { + // compile-time compatibility pin: this assignment must keep compiling for released user code + const legacyDef: ToolbarBuiltInItemDef = { toolbarItem: 'agFindToolbarItem' }; + const api = gridMgr.createGrid('find-legacy-def', { + columnDefs: [{ field: 'name' }], + rowData: [{ name: 'Alice' }], + toolbar: { items: [legacyDef] }, + }); + await waitForEvent('firstDataRendered', api); + + expect(TestGridsManager.getHTMLElement(api)!.querySelector('.ag-toolbar-input-field')).not.toBeNull(); + }); + + test('toolbarItemParams.browserAutoComplete overrides enableInputAutoComplete', async () => { + const api = gridMgr.createGrid('find-autocomplete-override', { + columnDefs: [{ field: 'name' }], + rowData: [{ name: 'Alice' }], + enableInputAutoComplete: true, + toolbar: { + items: [{ toolbarItem: 'agFindToolbarItem', toolbarItemParams: { browserAutoComplete: false } }], + }, + }); + await waitForEvent('firstDataRendered', api); + + const input = TestGridsManager.getHTMLElement(api)!.querySelector('.ag-toolbar-input-field')!; + expect(input.getAttribute('autocomplete')).toBe('off'); + }); + test('sets findSearchValue on input', async () => { const api = gridMgr.createGrid('find-input', { columnDefs: [{ field: 'name' }], diff --git a/testing/behavioural/src/toolbar/toolbar-quick-filter.test.ts b/testing/behavioural/src/toolbar/toolbar-quick-filter.test.ts index 804ec533a55..ac448346c1d 100644 --- a/testing/behavioural/src/toolbar/toolbar-quick-filter.test.ts +++ b/testing/behavioural/src/toolbar/toolbar-quick-filter.test.ts @@ -46,6 +46,21 @@ describe('Toolbar quickFilter item', () => { `); }); + test('toolbarItemParams.browserAutoComplete overrides enableInputAutoComplete', async () => { + const api = gridMgr.createGrid('quick-filter-autocomplete-override', { + columnDefs: [{ field: 'name' }], + rowData: [{ name: 'Alice' }], + enableInputAutoComplete: true, + toolbar: { + items: [{ toolbarItem: 'agQuickFilterToolbarItem', toolbarItemParams: { browserAutoComplete: false } }], + }, + }); + await waitForEvent('firstDataRendered', api); + + const input = TestGridsManager.getHTMLElement(api)!.querySelector('.ag-toolbar-input-field')!; + expect(input.getAttribute('autocomplete')).toBe('off'); + }); + test('global input options control toolbar autocomplete and the clear button', async () => { const api = gridMgr.createGrid('quick-filter-input-options', { columnDefs: [{ field: 'name' }],