diff --git a/core/api.txt b/core/api.txt index 55f32d049b..2c79b81465 100644 --- a/core/api.txt +++ b/core/api.txt @@ -185,6 +185,7 @@ ion-app,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-app,method,setFocus,setFocus(elements: HTMLElement[]) => Promise ion-avatar,shadow +ion-avatar,prop,disabled,boolean,false,false,false ion-avatar,prop,mode,"ios" | "md",undefined,false,false ion-avatar,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false ion-avatar,prop,size,"large" | "medium" | "small" | "xlarge" | "xsmall" | "xxsmall" | undefined,undefined,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index b798198e7e..cea5a27201 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -343,6 +343,10 @@ export namespace Components { "theme"?: "ios" | "md" | "ionic"; } interface IonAvatar { + /** + * If `true`, the user cannot interact with the avatar. + */ + "disabled": boolean; /** * The mode determines the platform behaviors of the component. */ @@ -5759,6 +5763,10 @@ declare namespace LocalJSX { "theme"?: "ios" | "md" | "ionic"; } interface IonAvatar { + /** + * If `true`, the user cannot interact with the avatar. + */ + "disabled"?: boolean; /** * The mode determines the platform behaviors of the component. */ diff --git a/core/src/components/avatar/avatar.ionic.scss b/core/src/components/avatar/avatar.ionic.scss index 2648f827a4..a37227748f 100644 --- a/core/src/components/avatar/avatar.ionic.scss +++ b/core/src/components/avatar/avatar.ionic.scss @@ -171,3 +171,9 @@ :host(.avatar-xxsmall) ::slotted(ion-badge.badge-vertical-bottom:empty) { transform: translate(globals.$ion-scale-100, calc(globals.$ion-scale-100)); } + +// Avatar Disabled +// -------------------------------------------------- +:host(.avatar-disabled)::before { + @include globals.disabled-state(); +} diff --git a/core/src/components/avatar/avatar.tsx b/core/src/components/avatar/avatar.tsx index b961fa3301..da5ccb8170 100644 --- a/core/src/components/avatar/avatar.tsx +++ b/core/src/components/avatar/avatar.tsx @@ -40,6 +40,11 @@ export class Avatar implements ComponentInterface { */ @Prop() shape?: 'soft' | 'round' | 'rectangular'; + /** + * If `true`, the user cannot interact with the avatar. + */ + @Prop() disabled = false; + get hasImage() { return !!this.el.querySelector('ion-img') || !!this.el.querySelector('img'); } @@ -81,6 +86,7 @@ export class Avatar implements ComponentInterface { } render() { + const { hasImage, hasIcon, disabled } = this; const theme = getIonTheme(this); const size = this.getSize(); const shape = this.getShape(); @@ -91,8 +97,9 @@ export class Avatar implements ComponentInterface { [theme]: true, [`avatar-${size}`]: size !== undefined, [`avatar-${shape}`]: shape !== undefined, - [`avatar-image`]: this.hasImage, - [`avatar-icon`]: this.hasIcon, + [`avatar-image`]: hasImage, + [`avatar-icon`]: hasIcon, + [`avatar-disabled`]: disabled, }} > diff --git a/core/src/components/avatar/test/states/avatar.e2e.ts b/core/src/components/avatar/test/states/avatar.e2e.ts new file mode 100644 index 0000000000..3e2e570328 --- /dev/null +++ b/core/src/components/avatar/test/states/avatar.e2e.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; + +/** + * Avatar does not test RTL behaviors. + * Usages of Avatar in slots are tested in components that use Avatar. + */ +configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ config, screenshot, title }) => { + test.describe(title('avatar: states'), () => { + test('should not have visual regressions', async ({ page }) => { + await page.setContent( + ` +
+ AV + + + +
+ `, + config + ); + const container = page.locator('#container'); + + await expect(container).toHaveScreenshot(screenshot(`avatar-disabled`)); + }); + }); +}); diff --git a/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..a97cbaf436 Binary files /dev/null and b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..16058da48f Binary files /dev/null and b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 0000000000..d88b84ce75 Binary files /dev/null and b/core/src/components/avatar/test/states/avatar.e2e.ts-snapshots/avatar-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/avatar/test/states/index.html b/core/src/components/avatar/test/states/index.html new file mode 100644 index 0000000000..687985d9e5 --- /dev/null +++ b/core/src/components/avatar/test/states/index.html @@ -0,0 +1,34 @@ + + + + + Avatar - States + + + + + + + + + + + + + Avatar - States + + + + +

Disabled

+ AV + + + +
+
+ + diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 9bc44081d0..44480e1b89 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -211,14 +211,14 @@ export declare interface IonApp extends Components.IonApp {} @ProxyCmp({ - inputs: ['mode', 'shape', 'size', 'theme'] + inputs: ['disabled', 'mode', 'shape', 'size', 'theme'] }) @Component({ selector: 'ion-avatar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['mode', 'shape', 'size', 'theme'], + inputs: ['disabled', 'mode', 'shape', 'size', 'theme'], }) export class IonAvatar { protected el: HTMLIonAvatarElement; diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index a6c871c280..055393b5f0 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -295,14 +295,14 @@ export declare interface IonApp extends Components.IonApp {} @ProxyCmp({ defineCustomElementFn: defineIonAvatar, - inputs: ['mode', 'shape', 'size', 'theme'] + inputs: ['disabled', 'mode', 'shape', 'size', 'theme'] }) @Component({ selector: 'ion-avatar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['mode', 'shape', 'size', 'theme'], + inputs: ['disabled', 'mode', 'shape', 'size', 'theme'], standalone: true }) export class IonAvatar { diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index 7aa2faa56b..fe28254a3f 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -112,7 +112,8 @@ export const IonAccordionGroup: StencilVueComponent = /*@__PURE__*/ defineContainer('ion-avatar', defineIonAvatar, [ 'size', - 'shape' + 'shape', + 'disabled' ]);