mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
feat(input): component api for input masking (#27339)
Issue number: Internal --------- <!-- Please refer to our contributing documentation for any questions on submitting a pull request, or let us know here if you need any help: https://ionicframework.com/docs/building/contributing --> <!-- Some docs updates need to be made in the `ionic-docs` repo, in a separate PR. See https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#modifying-documentation for details. --> <!-- 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. --> N/A ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Adds `mask`, `maskVisibility` and `maskPlaceholder` properties to `ion-input` for input masking ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> ---------
This commit is contained in:
@ -977,7 +977,7 @@ export declare interface IonInfiniteScrollContent extends Components.IonInfinite
|
||||
|
||||
|
||||
@ProxyCmp({
|
||||
inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'legacy', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'size', 'spellcheck', 'step', 'type', 'value'],
|
||||
inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'legacy', 'mask', 'maskPlaceholder', 'maskVisibility', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'size', 'spellcheck', 'step', 'type', 'value'],
|
||||
methods: ['setFocus', 'getInputElement']
|
||||
})
|
||||
@Component({
|
||||
@ -985,7 +985,7 @@ export declare interface IonInfiniteScrollContent extends Components.IonInfinite
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-content></ng-content>',
|
||||
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
|
||||
inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'legacy', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'size', 'spellcheck', 'step', 'type', 'value'],
|
||||
inputs: ['accept', 'autocapitalize', 'autocomplete', 'autocorrect', 'autofocus', 'clearInput', 'clearOnEdit', 'color', 'counter', 'counterFormatter', 'debounce', 'disabled', 'enterkeyhint', 'errorText', 'fill', 'helperText', 'inputmode', 'label', 'labelPlacement', 'legacy', 'mask', 'maskPlaceholder', 'maskVisibility', 'max', 'maxlength', 'min', 'minlength', 'mode', 'multiple', 'name', 'pattern', 'placeholder', 'readonly', 'required', 'shape', 'size', 'spellcheck', 'step', 'type', 'value'],
|
||||
})
|
||||
export class IonInput {
|
||||
protected el: HTMLElement;
|
||||
|
@ -553,6 +553,9 @@ ion-input,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "
|
||||
ion-input,prop,label,string | undefined,undefined,false,false
|
||||
ion-input,prop,labelPlacement,"end" | "fixed" | "floating" | "stacked" | "start",'start',false,false
|
||||
ion-input,prop,legacy,boolean | undefined,undefined,false,false
|
||||
ion-input,prop,mask,(string | RegExp)[] | RegExp | undefined,undefined,false,false
|
||||
ion-input,prop,maskPlaceholder,null | string | undefined,'_',false,false
|
||||
ion-input,prop,maskVisibility,"always" | "focus" | "never" | undefined,'always',false,false
|
||||
ion-input,prop,max,number | string | undefined,undefined,false,false
|
||||
ion-input,prop,maxlength,number | undefined,undefined,false,false
|
||||
ion-input,prop,min,number | string | undefined,undefined,false,false
|
||||
|
26
core/src/components.d.ts
vendored
26
core/src/components.d.ts
vendored
@ -17,6 +17,7 @@ import { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interf
|
||||
import { ScrollBaseDetail, ScrollDetail } from "./components/content/content-interface";
|
||||
import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
|
||||
import { SpinnerTypes } from "./components/spinner/spinner-configs";
|
||||
import { MaskExpression, MaskPlaceholder, MaskVisibility } from "./utils/input-masking";
|
||||
import { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
|
||||
import { CounterFormatter } from "./components/item/item-interface";
|
||||
import { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
@ -53,6 +54,7 @@ export { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interf
|
||||
export { ScrollBaseDetail, ScrollDetail } from "./components/content/content-interface";
|
||||
export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimePresentation, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
|
||||
export { SpinnerTypes } from "./components/spinner/spinner-configs";
|
||||
export { MaskExpression, MaskPlaceholder, MaskVisibility } from "./utils/input-masking";
|
||||
export { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
|
||||
export { CounterFormatter } from "./components/item/item-interface";
|
||||
export { MenuChangeEventDetail, Side } from "./components/menu/menu-interface";
|
||||
@ -1225,6 +1227,18 @@ export namespace Components {
|
||||
* Set the `legacy` property to `true` to forcibly use the legacy form control markup. Ionic will only opt components in to the modern form markup when they are using either the `aria-label` attribute or the `label` property. As a result, the `legacy` property should only be used as an escape hatch when you want to avoid this automatic opt-in behavior. Note that this property will be removed in an upcoming major release of Ionic, and all form components will be opted-in to using the modern form markup.
|
||||
*/
|
||||
"legacy"?: boolean;
|
||||
/**
|
||||
* The predefined format of the user's input. For example, you can set a mask that only accepts digits, or you can configure a more complex pattern like a phone number or credit card number. The mask supports two formats: 1. A valid [regular expression pattern](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) 2. An array containing regular expression and fixed character patterns The fixed characters in the mask cannot be erased or replaced by the user. For example in a phone number mask, the `(`, `)` and `-` are examples of fixed characters.
|
||||
*/
|
||||
"mask"?: MaskExpression;
|
||||
/**
|
||||
* Character or string to cover unfilled parts of the mask. The default character is `_`. If set to `null`, `undefined` or an empty string, unfilled parts will be empty as in a regular input.
|
||||
*/
|
||||
"maskPlaceholder"?: MaskPlaceholder;
|
||||
/**
|
||||
* The visibility of the mask placeholder. With `always`, the placeholder will be visible even when the control does not have focus. With `focus`, the placeholder will only be visible when the control has focus. With `never`, the placeholder will never be visibly displayed.
|
||||
*/
|
||||
"maskVisibility"?: MaskVisibility;
|
||||
/**
|
||||
* The maximum value, which must not be less than its minimum (min attribute) value.
|
||||
*/
|
||||
@ -5255,6 +5269,18 @@ declare namespace LocalJSX {
|
||||
* Set the `legacy` property to `true` to forcibly use the legacy form control markup. Ionic will only opt components in to the modern form markup when they are using either the `aria-label` attribute or the `label` property. As a result, the `legacy` property should only be used as an escape hatch when you want to avoid this automatic opt-in behavior. Note that this property will be removed in an upcoming major release of Ionic, and all form components will be opted-in to using the modern form markup.
|
||||
*/
|
||||
"legacy"?: boolean;
|
||||
/**
|
||||
* The predefined format of the user's input. For example, you can set a mask that only accepts digits, or you can configure a more complex pattern like a phone number or credit card number. The mask supports two formats: 1. A valid [regular expression pattern](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) 2. An array containing regular expression and fixed character patterns The fixed characters in the mask cannot be erased or replaced by the user. For example in a phone number mask, the `(`, `)` and `-` are examples of fixed characters.
|
||||
*/
|
||||
"mask"?: MaskExpression;
|
||||
/**
|
||||
* Character or string to cover unfilled parts of the mask. The default character is `_`. If set to `null`, `undefined` or an empty string, unfilled parts will be empty as in a regular input.
|
||||
*/
|
||||
"maskPlaceholder"?: MaskPlaceholder;
|
||||
/**
|
||||
* The visibility of the mask placeholder. With `always`, the placeholder will be visible even when the control does not have focus. With `focus`, the placeholder will only be visible when the control has focus. With `never`, the placeholder will never be visibly displayed.
|
||||
*/
|
||||
"maskVisibility"?: MaskVisibility;
|
||||
/**
|
||||
* The maximum value, which must not be less than its minimum (min attribute) value.
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@ import type { LegacyFormController } from '../../utils/forms';
|
||||
import { createLegacyFormController } from '../../utils/forms';
|
||||
import type { Attributes } from '../../utils/helpers';
|
||||
import { inheritAriaAttributes, debounceEvent, findItemLabel, inheritAttributes } from '../../utils/helpers';
|
||||
import type { MaskExpression, MaskPlaceholder, MaskVisibility } from '../../utils/input-masking';
|
||||
import { printIonWarning } from '../../utils/logging';
|
||||
import { createColorClasses, hostContext } from '../../utils/theme';
|
||||
|
||||
@ -272,6 +273,35 @@ export class Input implements ComponentInterface {
|
||||
*/
|
||||
@Prop({ mutable: true }) value?: string | number | null = '';
|
||||
|
||||
/**
|
||||
* The predefined format of the user's input. For example, you can set a mask
|
||||
* that only accepts digits, or you can configure a more complex pattern like
|
||||
* a phone number or credit card number.
|
||||
*
|
||||
* The mask supports two formats:
|
||||
* 1. A valid [regular expression pattern](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
* 2. An array containing regular expression and fixed character patterns
|
||||
*
|
||||
* The fixed characters in the mask cannot be erased or replaced by the user. For example
|
||||
* in a phone number mask, the `(`, `)` and `-` are examples of fixed characters.
|
||||
*
|
||||
*/
|
||||
@Prop() mask?: MaskExpression;
|
||||
|
||||
/**
|
||||
* The visibility of the mask placeholder. With `always`, the placeholder will be
|
||||
* visible even when the control does not have focus. With `focus`, the placeholder
|
||||
* will only be visible when the control has focus. With `never`, the placeholder will
|
||||
* never be visibly displayed.
|
||||
*/
|
||||
@Prop() maskVisibility?: MaskVisibility = 'always';
|
||||
|
||||
/**
|
||||
* Character or string to cover unfilled parts of the mask. The default character is `_`.
|
||||
* If set to `null`, `undefined` or an empty string, unfilled parts will be empty as in a regular input.
|
||||
*/
|
||||
@Prop() maskPlaceholder?: MaskPlaceholder = '_';
|
||||
|
||||
/**
|
||||
* The `ionInput` event fires when the `value` of an `<ion-input>` element
|
||||
* has been changed.
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
import { Input } from '../input';
|
||||
|
||||
it('should inherit attributes', async () => {
|
||||
@ -7,7 +8,7 @@ it('should inherit attributes', async () => {
|
||||
html: '<ion-input title="my title" tabindex="-1" data-form-type="password"></ion-input>',
|
||||
});
|
||||
|
||||
const nativeEl = page.body.querySelector('ion-input input');
|
||||
const nativeEl = page.body.querySelector('ion-input input')!;
|
||||
expect(nativeEl.getAttribute('title')).toBe('my title');
|
||||
expect(nativeEl.getAttribute('tabindex')).toBe('-1');
|
||||
expect(nativeEl.getAttribute('data-form-type')).toBe('password');
|
||||
|
1
core/src/interface.d.ts
vendored
1
core/src/interface.d.ts
vendored
@ -43,6 +43,7 @@ export {
|
||||
AnimationKeyFrames,
|
||||
AnimationLifecycle,
|
||||
} from './utils/animation/animation-interface';
|
||||
export { MaskExpression, MaskPlaceholder, MaskVisibility } from './utils/input-masking';
|
||||
export { HTMLIonOverlayElement, OverlayController, OverlayInterface } from './utils/overlays-interface';
|
||||
export { Config, config } from './global/config';
|
||||
export { Gesture, GestureConfig, GestureDetail } from './utils/gesture';
|
||||
|
1
core/src/utils/input-masking/index.ts
Normal file
1
core/src/utils/input-masking/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './input-masking-interface';
|
5
core/src/utils/input-masking/input-masking-interface.ts
Normal file
5
core/src/utils/input-masking/input-masking-interface.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type MaskVisibility = 'always' | 'focus' | 'never';
|
||||
|
||||
export type MaskExpression = RegExp | (string | RegExp)[];
|
||||
|
||||
export type MaskPlaceholder = string | null | undefined;
|
@ -428,6 +428,9 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput, JSX.IonInput
|
||||
'size',
|
||||
'type',
|
||||
'value',
|
||||
'mask',
|
||||
'maskVisibility',
|
||||
'maskPlaceholder',
|
||||
'ionInput',
|
||||
'ionChange',
|
||||
'ionBlur',
|
||||
|
Reference in New Issue
Block a user