Merge remote-tracking branch 'origin/feature-8.0' into sp/next

This commit is contained in:
Sean Perkins
2024-03-26 20:12:00 -04:00
21 changed files with 571 additions and 22 deletions

View File

@ -30,6 +30,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Progress bar](#version-8x-progress-bar)
- [Radio](#version-8x-radio)
- [Range](#version-8x-range)
- [Searchbar](#version-8x-searchbar)
- [Select](#version-8x-select)
- [Textarea](#version-8x-textarea)
- [Toggle](#version-8x-toggle)
@ -264,6 +265,10 @@ For more information on styling toast buttons, refer to the [Toast Theming docum
- The `legacy` property and support for the legacy syntax, which involved placing an `ion-range` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy range syntax, refer to the [Range documentation](https://ionicframework.com/docs/api/range#migrating-from-legacy-range-syntax).
<h4 id="version-8x-searchbar">Searchbar</h4>
- The `autocapitalize` property now defaults to `'off'`.
<h4 id="version-8x-select">Select</h4>
- The `legacy` property and support for the legacy syntax, which involved placing an `ion-select` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy select syntax, refer to the [Select documentation](https://ionicframework.com/docs/api/select#migrating-from-legacy-select-syntax).

View File

@ -603,7 +603,7 @@ ion-input,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secon
ion-input,prop,counter,boolean,false,false,false
ion-input,prop,counterFormatter,((inputLength: number, maxLength: number) => string) | undefined,undefined,false,false
ion-input,prop,debounce,number | undefined,undefined,false,false
ion-input,prop,disabled,boolean,false,false,false
ion-input,prop,disabled,boolean,false,false,true
ion-input,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
ion-input,prop,errorText,string | undefined,undefined,false,false
ion-input,prop,fill,"outline" | "solid" | undefined,undefined,false,false
@ -620,7 +620,7 @@ ion-input,prop,multiple,boolean | undefined,undefined,false,false
ion-input,prop,name,string,this.inputId,false,false
ion-input,prop,pattern,string | undefined,undefined,false,false
ion-input,prop,placeholder,string | undefined,undefined,false,false
ion-input,prop,readonly,boolean,false,false,false
ion-input,prop,readonly,boolean,false,false,true
ion-input,prop,required,boolean,false,false,false
ion-input,prop,shape,"round" | undefined,undefined,false,false
ion-input,prop,spellcheck,boolean,false,false,false
@ -653,6 +653,12 @@ ion-input,css-prop,--placeholder-font-style
ion-input,css-prop,--placeholder-font-weight
ion-input,css-prop,--placeholder-opacity
ion-input-password-toggle,shadow
ion-input-password-toggle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-input-password-toggle,prop,hideIcon,string | undefined,undefined,false,false
ion-input-password-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-input-password-toggle,prop,showIcon,string | undefined,undefined,false,false
ion-item,shadow
ion-item,prop,button,boolean,false,false,false
ion-item,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
@ -1265,7 +1271,7 @@ ion-row,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocapitalize,string,undefined,true,false
ion-searchbar,prop,autocapitalize,string,'off',false,false
ion-searchbar,prop,autocomplete,"name" | "email" | "tel" | "url" | "on" | "off" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "photo",'off',false,false
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', arrowBackSharp) as string,false,false

View File

@ -1471,6 +1471,25 @@ export namespace Components {
*/
"value"?: string | number | null;
}
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* The icon that can be used to represent hiding a password. If not set, the "eyeOff" Ionicon will be used.
*/
"hideIcon"?: string;
/**
* The mode determines which platform styles to use.
*/
"mode"?: "ios" | "md";
/**
* The icon that can be used to represent showing a password. If not set, the "eye" Ionicon will be used.
*/
"showIcon"?: string;
"type": TextFieldTypes;
}
interface IonItem {
/**
* If `true`, a button tag will be rendered and the item will be tappable.
@ -4323,6 +4342,12 @@ declare global {
prototype: HTMLIonInputElement;
new (): HTMLIonInputElement;
};
interface HTMLIonInputPasswordToggleElement extends Components.IonInputPasswordToggle, HTMLStencilElement {
}
var HTMLIonInputPasswordToggleElement: {
prototype: HTMLIonInputPasswordToggleElement;
new (): HTMLIonInputPasswordToggleElement;
};
interface HTMLIonItemElement extends Components.IonItem, HTMLStencilElement {
}
var HTMLIonItemElement: {
@ -5147,6 +5172,7 @@ declare global {
"ion-infinite-scroll": HTMLIonInfiniteScrollElement;
"ion-infinite-scroll-content": HTMLIonInfiniteScrollContentElement;
"ion-input": HTMLIonInputElement;
"ion-input-password-toggle": HTMLIonInputPasswordToggleElement;
"ion-item": HTMLIonItemElement;
"ion-item-divider": HTMLIonItemDividerElement;
"ion-item-group": HTMLIonItemGroupElement;
@ -6689,6 +6715,25 @@ declare namespace LocalJSX {
*/
"value"?: string | number | null;
}
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* The icon that can be used to represent hiding a password. If not set, the "eyeOff" Ionicon will be used.
*/
"hideIcon"?: string;
/**
* The mode determines which platform styles to use.
*/
"mode"?: "ios" | "md";
/**
* The icon that can be used to represent showing a password. If not set, the "eye" Ionicon will be used.
*/
"showIcon"?: string;
"type"?: TextFieldTypes;
}
interface IonItem {
/**
* If `true`, a button tag will be rendered and the item will be tappable.
@ -8121,7 +8166,7 @@ declare namespace LocalJSX {
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
"autocapitalize": string;
"autocapitalize"?: string;
/**
* Set the input's autocomplete property.
*/
@ -9064,6 +9109,7 @@ declare namespace LocalJSX {
"ion-infinite-scroll": IonInfiniteScroll;
"ion-infinite-scroll-content": IonInfiniteScrollContent;
"ion-input": IonInput;
"ion-input-password-toggle": IonInputPasswordToggle;
"ion-item": IonItem;
"ion-item-divider": IonItemDivider;
"ion-item-group": IonItemGroup;
@ -9162,6 +9208,7 @@ declare module "@stencil/core" {
"ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollElement>;
"ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollContentElement>;
"ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes<HTMLIonInputElement>;
"ion-input-password-toggle": LocalJSX.IonInputPasswordToggle & JSXBase.HTMLAttributes<HTMLIonInputPasswordToggleElement>;
"ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes<HTMLIonItemElement>;
"ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes<HTMLIonItemDividerElement>;
"ion-item-group": LocalJSX.IonItemGroup & JSXBase.HTMLAttributes<HTMLIonItemGroupElement>;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,152 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, h, Watch } from '@stencil/core';
import { printIonWarning } from '@utils/logging';
import { createColorClasses } from '@utils/theme';
import { eyeOff, eye } from 'ionicons/icons';
import { getIonMode } from '../../global/ionic-global';
import type { Color, TextFieldTypes } from '../../interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
@Component({
tag: 'ion-input-password-toggle',
/**
* Empty CSS files are required in order for the mode to be inherited to the
* inner ion-button. Otherwise, the setMode callback provided to Stencil will not get called
* and we will default to MD mode.
*/
styleUrls: {
ios: 'input-password-toggle.scss',
md: 'input-password-toggle.scss',
},
shadow: true,
})
export class InputPasswordToggle implements ComponentInterface {
private inputElRef!: HTMLIonInputElement | null;
@Element() el!: HTMLIonInputElement;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
@Prop({ reflect: true }) color?: Color;
/**
* The icon that can be used to represent showing a password. If not set, the "eye" Ionicon will be used.
*/
@Prop() showIcon?: string;
/**
* The icon that can be used to represent hiding a password. If not set, the "eyeOff" Ionicon will be used.
*/
@Prop() hideIcon?: string;
/**
* @internal
*/
@Prop({ mutable: true }) type: TextFieldTypes = 'password';
/**
* Whenever the input type changes we need to re-run validation to ensure the password
* toggle is being used with the correct input type. If the application changes the type
* outside of this component we also need to re-render so the correct icon is shown.
*/
@Watch('type')
onTypeChange(newValue: TextFieldTypes) {
if (newValue !== 'text' && newValue !== 'password') {
printIonWarning(
`ion-input-password-toggle only supports inputs of type "text" or "password". Input of type "${newValue}" is not compatible.`,
this.el
);
return;
}
}
connectedCallback() {
const { el } = this;
const inputElRef = (this.inputElRef = el.closest('ion-input'));
if (!inputElRef) {
printIonWarning(
'No ancestor ion-input found for ion-input-password-toggle. This component must be slotted inside of an ion-input.',
el
);
return;
}
/**
* Important: Set the type in connectedCallback because the default value
* of this.type may not always be accurate. Usually inputs have the "password" type
* but it is possible to have the input to initially have the "text" type. In that scenario
* the wrong icon will show briefly before switching to the correct icon. Setting the
* type here allows us to avoid that flicker.
*/
this.type = inputElRef.type;
}
disconnectedCallback() {
this.inputElRef = null;
}
private togglePasswordVisibility = () => {
const { inputElRef } = this;
if (!inputElRef) {
return;
}
inputElRef.type = inputElRef.type === 'text' ? 'password' : 'text';
};
render() {
const { color, type } = this;
const mode = getIonMode(this);
const showPasswordIcon = this.showIcon ?? eye;
const hidePasswordIcon = this.hideIcon ?? eyeOff;
const isPasswordVisible = type === 'text';
return (
<Host
class={createColorClasses(color, {
[mode]: true,
})}
>
<ion-button
mode={mode}
color={color}
fill="clear"
shape="round"
aria-checked={isPasswordVisible ? 'true' : 'false'}
aria-label="show password"
role="switch"
type="button"
onPointerDown={(ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the password toggle
* button is activated.
*/
ev.preventDefault();
}}
onClick={this.togglePasswordVisibility}
>
<ion-icon
slot="icon-only"
aria-hidden="true"
icon={isPasswordVisible ? hidePasswordIcon : showPasswordIcon}
></ion-icon>
</ion-button>
</Host>
);
}
}

View File

@ -0,0 +1,23 @@
import AxeBuilder from '@axe-core/playwright';
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('input password toggle: a11y'), () => {
test('should not have accessibility violations', async ({ page }) => {
await page.setContent(
`
<main>
<ion-input label="input" type="password">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
</main>
`,
config
);
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});
});
});

View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Input - Toggle Password</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<style>
.grid {
display: grid;
grid-template-columns: repeat(5, minmax(250px, 1fr));
grid-row-gap: 20px;
grid-column-gap: 20px;
}
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
}
@media screen and (max-width: 800px) {
.grid {
grid-template-columns: 1fr;
padding: 0;
}
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Input - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content" class="ion-padding">
<div class="grid">
<div class="grid-item">
<h2>Default</h2>
<ion-input type="password" value="supersecurepassword" label="Password">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
</div>
<div class="grid-item">
<h2>Custom Icon</h2>
<ion-input type="password" value="supersecurepassword" label="Password">
<ion-input-password-toggle show-icon="trash" slot="end"></ion-input-password-toggle>
</ion-input>
</div>
<div class="grid-item">
<h2>Custom Mode/Color</h2>
<ion-input type="password" value="supersecurepassword" label="Password">
<ion-input-password-toggle
color="danger"
mode="ios"
show-icon="trash"
slot="end"
></ion-input-password-toggle>
</ion-input>
</div>
</div>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,50 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('input password toggle: states'), () => {
test('should be hidden when inside of a readonly input', async ({ page }) => {
await page.setContent(
`
<ion-input label="input" type="password" readonly="true">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
`,
config
);
const inputPasswordToggle = page.locator('ion-input-password-toggle');
await expect(inputPasswordToggle).toBeHidden();
});
test('should be hidden when inside of a disabled input', async ({ page }) => {
await page.setContent(
`
<ion-input label="input" type="password" disabled="true">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
`,
config
);
const inputPasswordToggle = page.locator('ion-input-password-toggle');
await expect(inputPasswordToggle).toBeHidden();
});
});
test.describe(title('input password toggle: rendering'), () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<ion-input label="input" type="password">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
`,
config
);
const inputPasswordToggle = page.locator('ion-input-password-toggle');
await expect(inputPasswordToggle).toHaveScreenshot(screenshot('input-password-toggle'));
});
});
});

View File

@ -0,0 +1,115 @@
import { h } from '@stencil/core';
import { newSpecPage } from '@stencil/core/testing';
import { Input } from '../../input/input';
import { InputPasswordToggle } from '../input-password-toggle';
import { Button } from '../../button/button';
import { initialize } from '../../../global/ionic-global';
describe('input password toggle', () => {
it('should toggle input type when clicked', async () => {
const page = await newSpecPage({
components: [Input, InputPasswordToggle, Button],
template: () => (
<ion-input type="password">
<ion-input-password-toggle slot="end"></ion-input-password-toggle>
</ion-input>
),
});
const inputPasswordToggle = page.body.querySelector('ion-input-password-toggle')!;
const button = inputPasswordToggle.shadowRoot!.querySelector('ion-button')!;
const input = page.body.querySelector('ion-input')!;
expect(input.type).toBe('password');
button.click();
await page.waitForChanges();
expect(input.type).toBe('text');
button.click();
await page.waitForChanges();
expect(input.type).toBe('password');
});
it('should render custom icons', async () => {
const page = await newSpecPage({
components: [Input, InputPasswordToggle, Button],
template: () => (
<ion-input type="password">
<ion-input-password-toggle showIcon="show" hideIcon="hide" slot="end"></ion-input-password-toggle>
</ion-input>
),
});
const inputPasswordToggle = page.body.querySelector('ion-input-password-toggle')!;
const button = inputPasswordToggle.shadowRoot!.querySelector('ion-button')!;
const icon = inputPasswordToggle.shadowRoot!.querySelector('ion-icon')!;
// Grab the attribute to test since we are not actually passing in a valid SVG
expect(icon.getAttribute('icon')).toBe('show');
button.click();
await page.waitForChanges();
expect(icon.getAttribute('icon')).toBe('hide');
});
it('changing the type on the input should update the icon used in password toggle', async () => {
const page = await newSpecPage({
components: [Input, InputPasswordToggle, Button],
template: () => (
<ion-input type="password">
<ion-input-password-toggle showIcon="show" hideIcon="hide" slot="end"></ion-input-password-toggle>
</ion-input>
),
});
const inputPasswordToggle = page.body.querySelector('ion-input-password-toggle')!;
const input = page.body.querySelector('ion-input')!;
const icon = inputPasswordToggle.shadowRoot!.querySelector('ion-icon')!;
// Grab the attribute to test since we are not actually passing in a valid SVG
expect(icon.getAttribute('icon')).toBe('show');
input.type = 'text';
await page.waitForChanges();
expect(icon.getAttribute('icon')).toBe('hide');
input.type = 'password';
await page.waitForChanges();
expect(icon.getAttribute('icon')).toBe('show');
});
it('should inherit the mode and color to internal ionic components', async () => {
/**
* This initialize script tells Stencil how to determine the mode on components.
* This is required for any getIonMode internal logic to function properly in spec tests.
*/
initialize();
const page = await newSpecPage({
components: [Input, InputPasswordToggle, Button],
template: () => (
<ion-input type="password" color="primary">
<ion-input-password-toggle slot="end" mode="ios" color="danger"></ion-input-password-toggle>
</ion-input>
),
});
const inputPasswordToggle = page.body.querySelector('ion-input-password-toggle')!;
const button = inputPasswordToggle.shadowRoot!.querySelector('ion-button')!;
await page.waitForChanges();
// mode is a virtual prop so we need to access it as an attribute
expect(button.getAttribute('mode')).toBe('ios');
// color is an actual prop so we can access the element property
expect(button.color).toBe('danger');
});
});

View File

@ -605,3 +605,12 @@
margin-inline-start: $form-control-label-margin;
margin-inline-end: 0;
}
/**
* The input password toggle component should be hidden when the input is readonly/disabled
* because it is not possible to edit a password.
*/
:host([disabled]) ::slotted(ion-input-password-toggle),
:host([readonly]) ::slotted(ion-input-password-toggle) {
display: none;
}

View File

@ -132,7 +132,7 @@ export class Input implements ComponentInterface {
/**
* If `true`, the user cannot interact with the input.
*/
@Prop() disabled = false;
@Prop({ reflect: true }) disabled = false;
/**
* A hint to the browser for which enter key to display.
@ -228,7 +228,7 @@ export class Input implements ComponentInterface {
/**
* If `true`, the user cannot modify the value.
*/
@Prop() readonly = false;
@Prop({ reflect: true }) readonly = false;
/**
* If `true`, the user must fill in a value before submitting a form.
@ -256,6 +256,20 @@ export class Input implements ComponentInterface {
*/
@Prop() type: TextFieldTypes = 'text';
/**
* Whenever the type on the input changes we need
* to update the internal type prop on the password
* toggle so that that correct icon is shown.
*/
@Watch('type')
onTypeChange() {
const passwordToggle = this.el.querySelector('ion-input-password-toggle');
if (passwordToggle) {
passwordToggle.type = this.type;
}
}
/**
* The value of the input.
*/
@ -346,6 +360,14 @@ export class Input implements ComponentInterface {
componentDidLoad() {
this.originalIonInput = this.ionInput;
/**
* Set the type on the password toggle in the event that this input's
* type was set async and does not match the default type for the password toggle.
* This can happen when the type is bound using a JS framework binding syntax
* such as [type] in Angular.
*/
this.onTypeChange();
}
componentDidRender() {

View File

@ -80,26 +80,11 @@ export class Searchbar implements ComponentInterface {
*/
@Prop() animated = false;
/**
* Prior to the addition of this property
* autocapitalize was enabled by default on iOS
* and disabled by default on Android
* for Searchbar. The autocapitalize type on HTMLElement
* requires that it be a string and never undefined.
* However, setting it to a string value would be a breaking change
* in behavior, so we use "!" to tell TypeScript that this property
* is always defined so we can rely on the browser defaults. Browsers
* will automatically set a default value if the developer does not set one.
*
* In the future, this property will default to "off" to align with
* Input and Textarea, and the "!" will not be needed.
*/
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
@Prop() autocapitalize!: string;
@Prop() autocapitalize: string = 'off';
/**
* Set the input's autocomplete property.

View File

@ -36,6 +36,7 @@ export const DIRECTIVES = [
d.IonInfiniteScroll,
d.IonInfiniteScrollContent,
d.IonInput,
d.IonInputPasswordToggle,
d.IonItem,
d.IonItemDivider,
d.IonItemGroup,

View File

@ -1016,6 +1016,28 @@ where the user's interaction is typing.
}
@ProxyCmp({
inputs: ['color', 'hideIcon', 'mode', 'showIcon']
})
@Component({
selector: 'ion-input-password-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'hideIcon', 'mode', 'showIcon'],
})
export class IonInputPasswordToggle {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
}
}
export declare interface IonInputPasswordToggle extends Components.IonInputPasswordToggle {}
@ProxyCmp({
inputs: ['button', 'color', 'detail', 'detailIcon', 'disabled', 'download', 'href', 'lines', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'target', 'theme', 'type']
})

View File

@ -36,6 +36,7 @@ import { defineCustomElement as defineIonHeader } from '@ionic/core/components/i
import { defineCustomElement as defineIonImg } from '@ionic/core/components/ion-img.js';
import { defineCustomElement as defineIonInfiniteScroll } from '@ionic/core/components/ion-infinite-scroll.js';
import { defineCustomElement as defineIonInfiniteScrollContent } from '@ionic/core/components/ion-infinite-scroll-content.js';
import { defineCustomElement as defineIonInputPasswordToggle } from '@ionic/core/components/ion-input-password-toggle.js';
import { defineCustomElement as defineIonItem } from '@ionic/core/components/ion-item.js';
import { defineCustomElement as defineIonItemDivider } from '@ionic/core/components/ion-item-divider.js';
import { defineCustomElement as defineIonItemGroup } from '@ionic/core/components/ion-item-group.js';
@ -978,6 +979,30 @@ export class IonInfiniteScrollContent {
export declare interface IonInfiniteScrollContent extends Components.IonInfiniteScrollContent {}
@ProxyCmp({
defineCustomElementFn: defineIonInputPasswordToggle,
inputs: ['color', 'hideIcon', 'mode', 'showIcon']
})
@Component({
selector: 'ion-input-password-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['color', 'hideIcon', 'mode', 'showIcon'],
standalone: true
})
export class IonInputPasswordToggle {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
}
}
export declare interface IonInputPasswordToggle extends Components.IonInputPasswordToggle {}
@ProxyCmp({
defineCustomElementFn: defineIonItem,
inputs: ['button', 'color', 'detail', 'detailIcon', 'disabled', 'download', 'href', 'lines', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'target', 'theme', 'type']

View File

@ -31,6 +31,7 @@ import { defineCustomElement as defineIonImg } from '@ionic/core/components/ion-
import { defineCustomElement as defineIonInfiniteScroll } from '@ionic/core/components/ion-infinite-scroll.js';
import { defineCustomElement as defineIonInfiniteScrollContent } from '@ionic/core/components/ion-infinite-scroll-content.js';
import { defineCustomElement as defineIonInput } from '@ionic/core/components/ion-input.js';
import { defineCustomElement as defineIonInputPasswordToggle } from '@ionic/core/components/ion-input-password-toggle.js';
import { defineCustomElement as defineIonItemDivider } from '@ionic/core/components/ion-item-divider.js';
import { defineCustomElement as defineIonItemGroup } from '@ionic/core/components/ion-item-group.js';
import { defineCustomElement as defineIonItemOptions } from '@ionic/core/components/ion-item-options.js';
@ -99,6 +100,7 @@ export const IonImg = /*@__PURE__*/createReactComponent<JSX.IonImg, HTMLIonImgEl
export const IonInfiniteScroll = /*@__PURE__*/createReactComponent<JSX.IonInfiniteScroll, HTMLIonInfiniteScrollElement>('ion-infinite-scroll', undefined, undefined, defineIonInfiniteScroll);
export const IonInfiniteScrollContent = /*@__PURE__*/createReactComponent<JSX.IonInfiniteScrollContent, HTMLIonInfiniteScrollContentElement>('ion-infinite-scroll-content', undefined, undefined, defineIonInfiniteScrollContent);
export const IonInput = /*@__PURE__*/createReactComponent<JSX.IonInput, HTMLIonInputElement>('ion-input', undefined, undefined, defineIonInput);
export const IonInputPasswordToggle = /*@__PURE__*/createReactComponent<JSX.IonInputPasswordToggle, HTMLIonInputPasswordToggleElement>('ion-input-password-toggle', undefined, undefined, defineIonInputPasswordToggle);
export const IonItemDivider = /*@__PURE__*/createReactComponent<JSX.IonItemDivider, HTMLIonItemDividerElement>('ion-item-divider', undefined, undefined, defineIonItemDivider);
export const IonItemGroup = /*@__PURE__*/createReactComponent<JSX.IonItemGroup, HTMLIonItemGroupElement>('ion-item-group', undefined, undefined, defineIonItemGroup);
export const IonItemOptions = /*@__PURE__*/createReactComponent<JSX.IonItemOptions, HTMLIonItemOptionsElement>('ion-item-options', undefined, undefined, defineIonItemOptions);

View File

@ -35,6 +35,7 @@ import { defineCustomElement as defineIonImg } from '@ionic/core/components/ion-
import { defineCustomElement as defineIonInfiniteScroll } from '@ionic/core/components/ion-infinite-scroll.js';
import { defineCustomElement as defineIonInfiniteScrollContent } from '@ionic/core/components/ion-infinite-scroll-content.js';
import { defineCustomElement as defineIonInput } from '@ionic/core/components/ion-input.js';
import { defineCustomElement as defineIonInputPasswordToggle } from '@ionic/core/components/ion-input-password-toggle.js';
import { defineCustomElement as defineIonItem } from '@ionic/core/components/ion-item.js';
import { defineCustomElement as defineIonItemDivider } from '@ionic/core/components/ion-item-divider.js';
import { defineCustomElement as defineIonItemGroup } from '@ionic/core/components/ion-item-group.js';
@ -436,6 +437,14 @@ export const IonInput = /*@__PURE__*/ defineContainer<JSX.IonInput, JSX.IonInput
'value', 'ion-input');
export const IonInputPasswordToggle = /*@__PURE__*/ defineContainer<JSX.IonInputPasswordToggle>('ion-input-password-toggle', defineIonInputPasswordToggle, [
'color',
'showIcon',
'hideIcon',
'type'
]);
export const IonItem = /*@__PURE__*/ defineContainer<JSX.IonItem>('ion-item', defineIonItem, [
'color',
'button',