Skip to content

Commit

Permalink
feat(input): add clearInputIcon property (#29246)
Browse files Browse the repository at this point in the history
Issue number: resolves #26974

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

In #26354 we updated
the clear icon to use an ionicon instead of an hardcoded SVG. This has
made it challenging to customize the icon.

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Added `clearInputIcon` property to allow developers to customize the
ionicon used.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->
  • Loading branch information
liamdebeasi committed Apr 2, 2024
1 parent 02e05bd commit 59b72f4
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ ion-input,prop,autocomplete,"name" | "on" | "off" | "honorific-prefix" | "given-
ion-input,prop,autocorrect,"off" | "on",'off',false,false
ion-input,prop,autofocus,boolean,false,false,false
ion-input,prop,clearInput,boolean,false,false,false
ion-input,prop,clearInputIcon,string | undefined,undefined,false,false
ion-input,prop,clearOnEdit,boolean | undefined,undefined,false,false
ion-input,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-input,prop,counter,boolean,false,false,false
Expand Down
8 changes: 8 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,10 @@ export namespace Components {
* If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
*/
"clearInput": boolean;
/**
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
*/
"clearInputIcon"?: string;
/**
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
*/
Expand Down Expand Up @@ -5886,6 +5890,10 @@ declare namespace LocalJSX {
* If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
*/
"clearInput"?: boolean;
/**
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
*/
"clearInputIcon"?: string;
/**
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
*/
Expand Down
11 changes: 9 additions & 2 deletions core/src/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ export class Input implements ComponentInterface {
*/
@Prop() clearInput = false;

/**
* The icon to use for the clear button. Only applies when `clearInput` is set to `true`.
*/
@Prop() clearInputIcon?: string;

/**
* If `true`, the value will be cleared after focus upon edit. Defaults to `true` when `type` is `"password"`, `false` for all other types.
*/
Expand Down Expand Up @@ -681,11 +686,13 @@ export class Input implements ComponentInterface {
}

render() {
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus } = this;
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus, clearInputIcon } = this;
const mode = getIonMode(this);
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const defaultClearIcon = mode === 'ios' ? closeCircle : closeSharp;
const clearIconData = clearInputIcon ?? defaultClearIcon;

const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
Expand Down Expand Up @@ -784,7 +791,7 @@ export class Input implements ComponentInterface {
}}
onClick={this.clearTextInput}
>
<ion-icon aria-hidden="true" icon={mode === 'ios' ? closeCircle : closeSharp}></ion-icon>
<ion-icon aria-hidden="true" icon={clearIconData}></ion-icon>
</button>
)}
<slot name="end"></slot>
Expand Down
16 changes: 16 additions & 0 deletions core/src/components/input/test/input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,19 @@ describe('input: label rendering', () => {
expect(labelText.textContent).toBe('Label Prop Text');
});
});

// https://github.com/ionic-team/ionic-framework/issues/26974
describe('input: clear icon', () => {
it('should render custom icon', async () => {
const page = await newSpecPage({
components: [Input],
html: `
<ion-input clear-input-icon="foo" clear-input="true"></ion-input>
`,
});

const icon = page.body.querySelector<HTMLIonIconElement>('ion-input ion-icon')!;

expect(icon.getAttribute('icon')).toBe('foo');
});
});
4 changes: 2 additions & 2 deletions packages/angular/src/directives/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -955,15 +955,15 @@ export declare interface IonInfiniteScrollContent extends Components.IonInfinite


@ProxyCmp({
inputs: ['autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'spellcheck', 'step', 'type', 'value'],
inputs: ['autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearInputIcon', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'spellcheck', 'step', 'type', 'value'],
methods: ['setFocus', 'getInputElement']
})
@Component({
selector: 'ion-input',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'spellcheck', 'step', 'type', 'value'],
inputs: ['autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearInputIcon', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'spellcheck', 'step', 'type', 'value'],
})
export class IonInput {
protected el: HTMLElement;
Expand Down
1 change: 1 addition & 0 deletions packages/vue/src/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput, JSX.IonInput
'autocorrect',
'autofocus',
'clearInput',
'clearInputIcon',
'clearOnEdit',
'counter',
'counterFormatter',
Expand Down

0 comments on commit 59b72f4

Please sign in to comment.