Skip to content

Commit 2884076

Browse files
authored
feat(ripple): adds unbounded ripple-effect (#16399)
1 parent 4dd4ccc commit 2884076

File tree

12 files changed

+72
-15
lines changed

12 files changed

+72
-15
lines changed

angular/src/directives/proxies.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,13 +652,14 @@ export class ReorderGroup {
652652
}
653653

654654
export declare interface RippleEffect extends StencilComponents<'IonRippleEffect'> {}
655-
@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>' })
655+
@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['type'] })
656656
export class RippleEffect {
657657

658658
constructor(c: ChangeDetectorRef, r: ElementRef) {
659659
c.detach();
660660
const el = r.nativeElement;
661661
proxyMethods(this, el, ['addRipple']);
662+
proxyInputs(this, el, ['type']);
662663
}
663664
}
664665

core/api.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ ion-reorder-group,method,complete,complete(listOrReorder?: boolean | any[] | und
740740
ion-reorder-group,event,ionItemReorder,ItemReorderDetail,true
741741

742742

743+
ion-ripple-effect,prop,type,"bounded" | "unbounded",'bounded',false
743744
ion-ripple-effect,method,addRipple,addRipple(pageX: number, pageY: number) => Promise<() => void>
744745

745746
ion-route-redirect,prop,from,string,undefined,false
@@ -943,6 +944,7 @@ ion-tab-button,style,--padding-bottom
943944
ion-tab-button,style,--padding-end
944945
ion-tab-button,style,--padding-start
945946
ion-tab-button,style,--padding-top
947+
ion-tab-button,style,--ripple-color
946948

947949
ion-tab,prop,component,Function | HTMLElement | null | string | undefined,undefined,false
948950
ion-tab,prop,tab,string,undefined,false

core/src/components.d.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3543,8 +3543,17 @@ export namespace Components {
35433543
* Adds the ripple effect to the parent element
35443544
*/
35453545
'addRipple': (pageX: number, pageY: number) => Promise<() => void>;
3546+
/**
3547+
* 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.
3548+
*/
3549+
'type': 'bounded' | 'unbounded';
3550+
}
3551+
interface IonRippleEffectAttributes extends StencilHTMLAttributes {
3552+
/**
3553+
* 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.
3554+
*/
3555+
'type'?: 'bounded' | 'unbounded';
35463556
}
3547-
interface IonRippleEffectAttributes extends StencilHTMLAttributes {}
35483557

35493558
interface IonRouteRedirect {
35503559
/**

core/src/components/button/button.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@
218218
line-height: 1;
219219

220220
box-shadow: var(--box-shadow);
221-
contain: content;
221+
contain: layout style;
222222
cursor: pointer;
223223
opacity: var(--opacity);
224224
overflow: var(--overflow);

core/src/components/button/button.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { createColorClasses, openURL } from '../../utils/theme';
1313
shadow: true,
1414
})
1515
export class Button implements ComponentInterface {
16+
17+
private inToolbar = false;
18+
1619
@Element() el!: HTMLElement;
1720

1821
@Prop({ context: 'window' }) win!: Window;
@@ -97,9 +100,7 @@ export class Button implements ComponentInterface {
97100
@Event() ionBlur!: EventEmitter<void>;
98101

99102
componentWillLoad() {
100-
if (this.fill === undefined) {
101-
this.fill = this.el.closest('ion-buttons') ? 'clear' : 'solid';
102-
}
103+
this.inToolbar = !!this.el.closest('ion-buttons');
103104
}
104105

105106
private onFocus = () => {
@@ -139,8 +140,11 @@ export class Button implements ComponentInterface {
139140
}
140141

141142
hostData() {
142-
const { buttonType, keyFocus, disabled, color, expand, fill, shape, size, strong } = this;
143-
143+
const { buttonType, keyFocus, disabled, color, expand, shape, size, strong } = this;
144+
let fill = this.fill;
145+
if (fill === undefined) {
146+
fill = this.inToolbar ? 'clear' : 'solid';
147+
}
144148
return {
145149
'ion-activatable': true,
146150
'aria-disabled': this.disabled ? 'true' : null,
@@ -181,7 +185,7 @@ export class Button implements ComponentInterface {
181185
<slot></slot>
182186
<slot name="end"></slot>
183187
</span>
184-
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
188+
{this.mode === 'md' && <ion-ripple-effect type={this.inToolbar ? 'unbounded' : 'bounded'}></ion-ripple-effect>}
185189
</TagType>
186190
);
187191
}

core/src/components/buttons/buttons.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
--padding-start: 0;
2424
--padding-end: 0;
2525
--box-shadow: none;
26+
--overflow: visible;
2627

2728
@include margin-horizontal(2px, 2px);
2829
}

core/src/components/ripple-effect/readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ The ripple effect component adds the [Material Design ink ripple interaction eff
66
<!-- Auto Generated Below -->
77

88

9+
## Properties
10+
11+
| Property | Attribute | Description | Type | Default |
12+
| -------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
13+
| `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'` |
14+
15+
916
## Methods
1017

1118
### `addRipple(pageX: number, pageY: number) => Promise<() => void>`

core/src/components/ripple-effect/ripple-effect.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ $opacity-duration: $fade-in-duration + $fade-out-duration;
1717
contain: strict;
1818
}
1919

20+
:host(.unbounded) {
21+
contain: layout size style;
22+
}
23+
2024
.ripple-effect {
2125
@include border-radius(50%);
2226

core/src/components/ripple-effect/ripple-effect.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ export class RippleEffect implements ComponentInterface {
1212
@Prop({ context: 'queue' }) queue!: QueueApi;
1313
@Prop({ context: 'window' }) win!: Window;
1414

15+
/**
16+
* Sets the type of ripple-effect:
17+
*
18+
* - `bounded`: the ripple effect expands from the user's click position
19+
* - `unbounded`: the ripple effect expands from the center of the button and overflows the container.
20+
*
21+
* NOTE: Surfaces for bounded ripples should have the overflow property set to hidden,
22+
* while surfaces for unbounded ripples should have it set to visible.
23+
*/
24+
@Prop() type: 'bounded' | 'unbounded' = 'bounded';
25+
1526
/**
1627
* Adds the ripple effect to the parent element
1728
*/
@@ -23,13 +34,17 @@ export class RippleEffect implements ComponentInterface {
2334
const width = rect.width;
2435
const height = rect.height;
2536
const hypotenuse = Math.sqrt(width * width + height * height);
26-
const maxRadius = hypotenuse + PADDING;
2737
const maxDim = Math.max(height, width);
28-
const posX = pageX - rect.left;
29-
const posY = pageY - rect.top;
30-
38+
const maxRadius = this.unbounded ? maxDim : hypotenuse + PADDING;
3139
const initialSize = Math.floor(maxDim * INITIAL_ORIGIN_SCALE);
3240
const finalScale = maxRadius / initialSize;
41+
let posX = pageX - rect.left;
42+
let posY = pageY - rect.top;
43+
if (this.type) {
44+
posX = width * 0.5;
45+
posY = height * 0.5;
46+
}
47+
3348
const x = posX - initialSize * 0.5;
3449
const y = posY - initialSize * 0.5;
3550
const moveX = width * 0.5 - posX;
@@ -57,9 +72,16 @@ export class RippleEffect implements ComponentInterface {
5772
});
5873
}
5974

75+
private get unbounded() {
76+
return this.type === 'unbounded';
77+
}
78+
6079
hostData() {
6180
return {
62-
role: 'presentation'
81+
role: 'presentation',
82+
class: {
83+
'unbounded': this.unbounded
84+
}
6385
};
6486
}
6587
}

core/src/components/tab-button/readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ See the [Tabs API Docs](../Tabs/) for more details on configuring Tabs.
3232
| `--padding-end` | End padding of the tab button |
3333
| `--padding-start` | Start padding of the tab button |
3434
| `--padding-top` | Top padding of the tab button |
35+
| `--ripple-color` | Color of the button ripple effect |
3536

3637

3738
----------------------------------------------

0 commit comments

Comments
 (0)