diff --git a/BREAKING.md b/BREAKING.md index 2bbb979de6a..1b138cc012b 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -19,6 +19,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver - [Card](#version-9x-card) - [Chip](#version-9x-chip) - [Grid](#version-9x-grid) + - [Input Otp](#version-9x-input-otp) - [Radio Group](#version-9x-radio-group) - [Textarea](#version-9x-textarea) @@ -149,6 +150,12 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has ` ``` +

Input Otp

+ +Converted `ion-input-otp` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). + +If you were targeting the internals of `ion-input-otp` in your CSS, you will need to target the `group`, `container`, `native`, `separator` or `description` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables. +

Radio Group

Converted `ion-radio-group` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). diff --git a/core/api.txt b/core/api.txt index dd7f9195e18..b82f0a090b2 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1035,18 +1035,20 @@ ion-input,css-prop,--placeholder-opacity,ionic ion-input,css-prop,--placeholder-opacity,ios ion-input,css-prop,--placeholder-opacity,md -ion-input-otp,scoped +ion-input-otp,shadow ion-input-otp,prop,autocapitalize,string,'off',false,false ion-input-otp,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record | undefined,undefined,false,true ion-input-otp,prop,disabled,boolean,false,false,true ion-input-otp,prop,fill,"outline" | "solid" | undefined,'outline',false,false ion-input-otp,prop,inputmode,"decimal" | "email" | "none" | "numeric" | "search" | "tel" | "text" | "url" | undefined,undefined,false,false ion-input-otp,prop,length,number,4,false,false +ion-input-otp,prop,mode,"ios" | "md",undefined,false,false ion-input-otp,prop,pattern,string | undefined,undefined,false,false ion-input-otp,prop,readonly,boolean,false,false,true ion-input-otp,prop,separators,number[] | string | undefined,undefined,false,false ion-input-otp,prop,shape,"rectangular" | "round" | "soft",'round',false,false ion-input-otp,prop,size,"large" | "medium" | "small",'medium',false,false +ion-input-otp,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-input-otp,prop,type,"number" | "text",'number',false,false ion-input-otp,prop,value,null | number | string | undefined,'',false,false ion-input-otp,method,setFocus,setFocus(index?: number) => Promise @@ -1127,6 +1129,11 @@ ion-input-otp,css-prop,--separator-width,md ion-input-otp,css-prop,--width,ionic ion-input-otp,css-prop,--width,ios ion-input-otp,css-prop,--width,md +ion-input-otp,part,container +ion-input-otp,part,description +ion-input-otp,part,group +ion-input-otp,part,native +ion-input-otp,part,separator ion-input-password-toggle,shadow ion-input-password-toggle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record | undefined,undefined,false,true diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 5119829a658..a4f8833d199 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -1779,6 +1779,10 @@ export namespace Components { * @default 4 */ "length": number; + /** + * The mode determines the platform behaviors of the component. + */ + "mode"?: "ios" | "md"; /** * A regex pattern string for allowed characters. Defaults based on type. For numbers (`type="number"`): `"[\p{N}]"` For text (`type="text"`): `"[\p{L}\p{N}]"` */ @@ -1807,6 +1811,10 @@ export namespace Components { * @default 'medium' */ "size": 'small' | 'medium' | 'large'; + /** + * The theme determines the visual appearance of the component. + */ + "theme"?: "ios" | "md" | "ionic"; /** * The type of input allowed in the input boxes. * @default 'number' @@ -7762,6 +7770,10 @@ declare namespace LocalJSX { * @default 4 */ "length"?: number; + /** + * The mode determines the platform behaviors of the component. + */ + "mode"?: "ios" | "md"; /** * Emitted when the input group loses focus. */ @@ -7805,6 +7817,10 @@ declare namespace LocalJSX { * @default 'medium' */ "size"?: 'small' | 'medium' | 'large'; + /** + * The theme determines the visual appearance of the component. + */ + "theme"?: "ios" | "md" | "ionic"; /** * The type of input allowed in the input boxes. * @default 'number' diff --git a/core/src/components/input-otp/input-otp.common.scss b/core/src/components/input-otp/input-otp.common.scss index 6af7c8cee63..74ae4ea2821 100644 --- a/core/src/components/input-otp/input-otp.common.scss +++ b/core/src/components/input-otp/input-otp.common.scss @@ -94,10 +94,13 @@ background: var(--background); color: var(--color); + font-family: inherit; font-size: inherit; text-align: center; appearance: none; + + box-sizing: border-box; } :host(.has-focus) .native-input { diff --git a/core/src/components/input-otp/input-otp.native.scss b/core/src/components/input-otp/input-otp.native.scss index daf2b3ff877..f2fe5b5ec89 100644 --- a/core/src/components/input-otp/input-otp.native.scss +++ b/core/src/components/input-otp/input-otp.native.scss @@ -19,6 +19,8 @@ --highlight-color-valid: #{ion-color(success, base)}; --highlight-color-invalid: #{ion-color(danger, base)}; + font-family: $font-family-base; + font-size: dynamic-font(14px); } diff --git a/core/src/components/input-otp/input-otp.tsx b/core/src/components/input-otp/input-otp.tsx index 3e8684505ab..20c0471d9e7 100644 --- a/core/src/components/input-otp/input-otp.tsx +++ b/core/src/components/input-otp/input-otp.tsx @@ -16,6 +16,16 @@ import type { InputOtpInputEventDetail, } from './input-otp-interface'; +/** + * @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component. + * @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component. + * + * @part group - The container element that wraps all input boxes. + * @part container - The wrapper element for each individual input box. + * @part native - The native input element. + * @part separator - The separator element displayed between input boxes. + * @part description - The container element for the description text. + */ @Component({ tag: 'ion-input-otp', styleUrls: { @@ -23,7 +33,8 @@ import type { md: 'input-otp.md.scss', ionic: 'input-otp.ionic.scss', }, - scoped: true, + shadow: true, + formAssociated: true, }) export class InputOTP implements ComponentInterface { private inheritedAttributes: Attributes = {}; @@ -817,12 +828,19 @@ export class InputOTP implements ComponentInterface { 'input-otp-readonly': readonly, })} > -
+
{Array.from({ length }).map((_, index) => ( <> -
+
- {this.showSeparator(index) &&
} + {this.showSeparator(index) &&
} ))}
@@ -851,6 +869,7 @@ export class InputOTP implements ComponentInterface { 'input-otp-description': true, 'input-otp-description-hidden': !hasDescription, }} + part="description" >
diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 91f6426be13..020f0d15c3d 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -1043,7 +1043,7 @@ This event will not emit when programmatically setting the `value` property. @ProxyCmp({ - inputs: ['autocapitalize', 'color', 'disabled', 'fill', 'inputmode', 'length', 'pattern', 'readonly', 'separators', 'shape', 'size', 'type', 'value'], + inputs: ['autocapitalize', 'color', 'disabled', 'fill', 'inputmode', 'length', 'mode', 'pattern', 'readonly', 'separators', 'shape', 'size', 'theme', 'type', 'value'], methods: ['setFocus'] }) @Component({ @@ -1051,7 +1051,7 @@ This event will not emit when programmatically setting the `value` property. changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['autocapitalize', 'color', 'disabled', 'fill', 'inputmode', 'length', 'pattern', 'readonly', 'separators', 'shape', 'size', 'type', 'value'], + inputs: ['autocapitalize', 'color', 'disabled', 'fill', 'inputmode', 'length', 'mode', 'pattern', 'readonly', 'separators', 'shape', 'size', 'theme', 'type', 'value'], }) export class IonInputOtp { protected el: HTMLIonInputOtpElement; diff --git a/packages/react/test/base/tests/e2e/specs/components/inputs.cy.ts b/packages/react/test/base/tests/e2e/specs/components/inputs.cy.ts index c0a757e8f03..48ea4aa7964 100644 --- a/packages/react/test/base/tests/e2e/specs/components/inputs.cy.ts +++ b/packages/react/test/base/tests/e2e/specs/components/inputs.cy.ts @@ -55,7 +55,7 @@ describe('Inputs', () => { }); it('typing into input-otp should update ref', () => { - cy.get('ion-input-otp input').eq(0).type('1234', { scrollBehavior: false }); + cy.get('ion-input-otp').shadow().find('input').eq(0).type('1234', { scrollBehavior: false }); cy.get('#input-otp-ref').should('have.text', '1234'); }); diff --git a/packages/vue/test/base/tests/e2e/specs/inputs.cy.js b/packages/vue/test/base/tests/e2e/specs/inputs.cy.js index 91d33d0c8b2..fc6f91cb6e2 100644 --- a/packages/vue/test/base/tests/e2e/specs/inputs.cy.js +++ b/packages/vue/test/base/tests/e2e/specs/inputs.cy.js @@ -53,7 +53,7 @@ describe('Inputs', () => { cy.get('#input-ref').should('have.text', 'Hello Input'); }); it('typing into input-otp should update ref', () => { - cy.get('ion-input-otp input').eq(0).type('1234', { scrollBehavior: false }); + cy.get('ion-input-otp').shadow().find('input').eq(0).type('1234', { scrollBehavior: false }); cy.get('#input-otp-ref').should('have.text', '1234'); });