feat(ripple): adds unbounded ripple-effect (#16399)

This commit is contained in:
Manu MA
2018-11-20 23:37:54 +01:00
committed by GitHub
parent 4dd4ccc4ce
commit 2884076834
12 changed files with 72 additions and 15 deletions

View File

@@ -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: '<ng-content></ng-content>' })
@Component({ selector: 'ion-ripple-effect', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['type'] })
export class RippleEffect {
constructor(c: ChangeDetectorRef, r: ElementRef) {
c.detach();
const el = r.nativeElement;
proxyMethods(this, el, ['addRipple']);
proxyInputs(this, el, ['type']);
}
}

View File

@@ -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

View File

@@ -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 {
/**

View File

@@ -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);

View File

@@ -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<void>;
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 {
<slot></slot>
<slot name="end"></slot>
</span>
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{this.mode === 'md' && <ion-ripple-effect type={this.inToolbar ? 'unbounded' : 'bounded'}></ion-ripple-effect>}
</TagType>
);
}

View File

@@ -23,6 +23,7 @@
--padding-start: 0;
--padding-end: 0;
--box-shadow: none;
--overflow: visible;
@include margin-horizontal(2px, 2px);
}

View File

@@ -6,6 +6,13 @@ The ripple effect component adds the [Material Design ink ripple interaction eff
<!-- Auto Generated Below -->
## 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>`

View File

@@ -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%);

View File

@@ -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
}
};
}
}

View File

@@ -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 |
----------------------------------------------

View File

@@ -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);
}

View File

@@ -122,7 +122,7 @@ export class TabButton implements ComponentInterface {
return (
<a href={href || '#'}>
<slot></slot>
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
</a>
);
}