diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts index 5bd6436a6b4..82a097d7ccc 100644 --- a/angular/src/directives/proxies.ts +++ b/angular/src/directives/proxies.ts @@ -652,13 +652,14 @@ export class ReorderGroup { } export declare interface RippleEffect extends StencilComponents<'IonRippleEffect'> {} -@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '' }) +@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '', inputs: ['type'] }) export class RippleEffect { constructor(c: ChangeDetectorRef, r: ElementRef) { c.detach(); const el = r.nativeElement; proxyMethods(this, el, ['addRipple']); + proxyInputs(this, el, ['type']); } } diff --git a/core/api.txt b/core/api.txt index 0e483beb3b9..81f5454fc24 100644 --- a/core/api.txt +++ b/core/api.txt @@ -740,6 +740,7 @@ ion-reorder-group,method,complete,complete(listOrReorder?: boolean | any[] | und ion-reorder-group,event,ionItemReorder,ItemReorderDetail,true +ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false ion-ripple-effect,method,addRipple,addRipple(pageX: number, pageY: number) => Promise<() => void> ion-route-redirect,prop,from,string,undefined,false @@ -943,6 +944,7 @@ ion-tab-button,style,--padding-bottom ion-tab-button,style,--padding-end ion-tab-button,style,--padding-start ion-tab-button,style,--padding-top +ion-tab-button,style,--ripple-color ion-tab,prop,component,Function | HTMLElement | null | string | undefined,undefined,false ion-tab,prop,tab,string,undefined,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 7055fab623a..93a59c144f8 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -3543,8 +3543,17 @@ export namespace Components { * Adds the ripple effect to the parent element */ 'addRipple': (pageX: number, pageY: number) => Promise<() => void>; + /** + * Sets the type of ripple-effect: - `bounded`: the ripple effect expands from the user's click position - `unbounded`: the ripple effect expands from the center of the button and overflows the container. NOTE: Surfaces for bounded ripples should have the overflow property set to hidden, while surfaces for unbounded ripples should have it set to visible. + */ + 'type': 'bounded' | 'unbounded'; + } + interface IonRippleEffectAttributes extends StencilHTMLAttributes { + /** + * Sets the type of ripple-effect: - `bounded`: the ripple effect expands from the user's click position - `unbounded`: the ripple effect expands from the center of the button and overflows the container. NOTE: Surfaces for bounded ripples should have the overflow property set to hidden, while surfaces for unbounded ripples should have it set to visible. + */ + 'type'?: 'bounded' | 'unbounded'; } - interface IonRippleEffectAttributes extends StencilHTMLAttributes {} interface IonRouteRedirect { /** diff --git a/core/src/components/button/button.scss b/core/src/components/button/button.scss index 9cfdc69ab57..c2905b84ee2 100644 --- a/core/src/components/button/button.scss +++ b/core/src/components/button/button.scss @@ -218,7 +218,7 @@ line-height: 1; box-shadow: var(--box-shadow); - contain: content; + contain: layout style; cursor: pointer; opacity: var(--opacity); overflow: var(--overflow); diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx index e4ffffce42e..69ffd098558 100644 --- a/core/src/components/button/button.tsx +++ b/core/src/components/button/button.tsx @@ -13,6 +13,9 @@ import { createColorClasses, openURL } from '../../utils/theme'; shadow: true, }) export class Button implements ComponentInterface { + + private inToolbar = false; + @Element() el!: HTMLElement; @Prop({ context: 'window' }) win!: Window; @@ -97,9 +100,7 @@ export class Button implements ComponentInterface { @Event() ionBlur!: EventEmitter; componentWillLoad() { - if (this.fill === undefined) { - this.fill = this.el.closest('ion-buttons') ? 'clear' : 'solid'; - } + this.inToolbar = !!this.el.closest('ion-buttons'); } private onFocus = () => { @@ -139,8 +140,11 @@ export class Button implements ComponentInterface { } hostData() { - const { buttonType, keyFocus, disabled, color, expand, fill, shape, size, strong } = this; - + const { buttonType, keyFocus, disabled, color, expand, shape, size, strong } = this; + let fill = this.fill; + if (fill === undefined) { + fill = this.inToolbar ? 'clear' : 'solid'; + } return { 'ion-activatable': true, 'aria-disabled': this.disabled ? 'true' : null, @@ -181,7 +185,7 @@ export class Button implements ComponentInterface { - {this.mode === 'md' && } + {this.mode === 'md' && } ); } diff --git a/core/src/components/buttons/buttons.scss b/core/src/components/buttons/buttons.scss index 74e21c21432..53dad899dfe 100644 --- a/core/src/components/buttons/buttons.scss +++ b/core/src/components/buttons/buttons.scss @@ -23,6 +23,7 @@ --padding-start: 0; --padding-end: 0; --box-shadow: none; + --overflow: visible; @include margin-horizontal(2px, 2px); } diff --git a/core/src/components/ripple-effect/readme.md b/core/src/components/ripple-effect/readme.md index 7c66c666d6d..5f734b56e1b 100644 --- a/core/src/components/ripple-effect/readme.md +++ b/core/src/components/ripple-effect/readme.md @@ -6,6 +6,13 @@ The ripple effect component adds the [Material Design ink ripple interaction eff +## Properties + +| Property | Attribute | Description | Type | Default | +| -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- | +| `type` | `type` | Sets the type of ripple-effect: - `bounded`: the ripple effect expands from the user's click position - `unbounded`: the ripple effect expands from the center of the button and overflows the container. NOTE: Surfaces for bounded ripples should have the overflow property set to hidden, while surfaces for unbounded ripples should have it set to visible. | `"bounded" \| "unbounded"` | `'bounded'` | + + ## Methods ### `addRipple(pageX: number, pageY: number) => Promise<() => void>` diff --git a/core/src/components/ripple-effect/ripple-effect.scss b/core/src/components/ripple-effect/ripple-effect.scss index cfd26c9e894..36bf6a1a7a2 100644 --- a/core/src/components/ripple-effect/ripple-effect.scss +++ b/core/src/components/ripple-effect/ripple-effect.scss @@ -17,6 +17,10 @@ $opacity-duration: $fade-in-duration + $fade-out-duration; contain: strict; } +:host(.unbounded) { + contain: layout size style; +} + .ripple-effect { @include border-radius(50%); diff --git a/core/src/components/ripple-effect/ripple-effect.tsx b/core/src/components/ripple-effect/ripple-effect.tsx index 89792769b99..98ae9d683f0 100644 --- a/core/src/components/ripple-effect/ripple-effect.tsx +++ b/core/src/components/ripple-effect/ripple-effect.tsx @@ -12,6 +12,17 @@ export class RippleEffect implements ComponentInterface { @Prop({ context: 'queue' }) queue!: QueueApi; @Prop({ context: 'window' }) win!: Window; + /** + * Sets the type of ripple-effect: + * + * - `bounded`: the ripple effect expands from the user's click position + * - `unbounded`: the ripple effect expands from the center of the button and overflows the container. + * + * NOTE: Surfaces for bounded ripples should have the overflow property set to hidden, + * while surfaces for unbounded ripples should have it set to visible. + */ + @Prop() type: 'bounded' | 'unbounded' = 'bounded'; + /** * Adds the ripple effect to the parent element */ @@ -23,13 +34,17 @@ export class RippleEffect implements ComponentInterface { const width = rect.width; const height = rect.height; const hypotenuse = Math.sqrt(width * width + height * height); - const maxRadius = hypotenuse + PADDING; const maxDim = Math.max(height, width); - const posX = pageX - rect.left; - const posY = pageY - rect.top; - + const maxRadius = this.unbounded ? maxDim : hypotenuse + PADDING; const initialSize = Math.floor(maxDim * INITIAL_ORIGIN_SCALE); const finalScale = maxRadius / initialSize; + let posX = pageX - rect.left; + let posY = pageY - rect.top; + if (this.type) { + posX = width * 0.5; + posY = height * 0.5; + } + const x = posX - initialSize * 0.5; const y = posY - initialSize * 0.5; const moveX = width * 0.5 - posX; @@ -57,9 +72,16 @@ export class RippleEffect implements ComponentInterface { }); } + private get unbounded() { + return this.type === 'unbounded'; + } + hostData() { return { - role: 'presentation' + role: 'presentation', + class: { + 'unbounded': this.unbounded + } }; } } diff --git a/core/src/components/tab-button/readme.md b/core/src/components/tab-button/readme.md index 8fb9ad3261b..0d7e526c058 100644 --- a/core/src/components/tab-button/readme.md +++ b/core/src/components/tab-button/readme.md @@ -32,6 +32,7 @@ See the [Tabs API Docs](../Tabs/) for more details on configuring Tabs. | `--padding-end` | End padding of the tab button | | `--padding-start` | Start padding of the tab button | | `--padding-top` | Top padding of the tab button | +| `--ripple-color` | Color of the button ripple effect | ---------------------------------------------- diff --git a/core/src/components/tab-button/tab-button.scss b/core/src/components/tab-button/tab-button.scss index aa9cccb50af..b32b5e2a3aa 100644 --- a/core/src/components/tab-button/tab-button.scss +++ b/core/src/components/tab-button/tab-button.scss @@ -10,8 +10,10 @@ * @prop --padding-end: End padding of the tab button * @prop --padding-bottom: Bottom padding of the tab button * @prop --padding-start: Start padding of the tab button + * @prop --ripple-color: Color of the button ripple effect */ --badge-end: 4%; + --ripple-color: var(--color-selected); flex: 1; @@ -177,3 +179,7 @@ a:focus-visible { :host(.tab-has-label-only) { --badge-end: #{calc(50% - 50px)}; } + +ion-ripple-effect { + color: var(--ripple-color); +} diff --git a/core/src/components/tab-button/tab-button.tsx b/core/src/components/tab-button/tab-button.tsx index c620642aaf7..68dcc49aede 100644 --- a/core/src/components/tab-button/tab-button.tsx +++ b/core/src/components/tab-button/tab-button.tsx @@ -122,7 +122,7 @@ export class TabButton implements ComponentInterface { return ( - {mode === 'md' && } + {mode === 'md' && } ); }