Skip to content

Commit

Permalink
[refactored] math operators to have shorthand signatures
Browse files Browse the repository at this point in the history
Summary:
This makes the common case (a single value and no options) more ergonomic.

Part of #230

Reviewers: O2 Material Motion, O3 Material JavaScript platform reviewers, #material_motion, vietanh

Reviewed By: #material_motion, vietanh

Tags: #material_motion

Differential Revision: http://codereview.cc/D3421
  • Loading branch information
appsforartists committed Oct 11, 2017
1 parent bd52ba1 commit cb16ebe
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 7 deletions.
6 changes: 3 additions & 3 deletions packages/core/src/interactions/Swipeable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export class Swipeable {
subscribe({
sink: tossable.resistanceFactor$,
source: when(tossableIsAtRest$).rewriteTo({
value$: tossable.resistanceBasis$.dividedBy({ value$: Swipeable.VISUAL_THRESHOLD }),
value$: tossable.resistanceBasis$.dividedBy(Swipeable.VISUAL_THRESHOLD),
onlyDispatchWithUpstream: true,
})
});
Expand Down Expand Up @@ -246,15 +246,15 @@ export class Swipeable {
}),
});

const destinationDistance$ = width$.addedBy({ value$: this.destinationMargin$ });
const destinationDistance$ = width$.addedBy(this.destinationMargin$);

subscribe({
sink: spring.destination$,
source: combineLatest<Point2D, MaybeReactive<Point2D>>({
x: this.swipeState$.rewrite({
mapping: {
[SwipeState.NONE]: 0,
[SwipeState.LEFT]: destinationDistance$.multipliedBy({ value$: -1 }),
[SwipeState.LEFT]: destinationDistance$.multipliedBy(-1),
[SwipeState.RIGHT]: destinationDistance$,
}
}),
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/operators/__tests__/addedBy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,37 @@ describe('motionObservable.addedBy',
expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({x: 10, y: 15 });
}
);

it('should have a shorthand signature for numeric constants',
() => {
subject.addedBy(10).subscribe(listener);

subject.next(3);

expect(listener).to.have.been.calledWith(13);
}
);

it('should have a shorthand signature for Point2D constants',
() => {
subject.addedBy({ x : 10, y: 20 }).subscribe(listener);

subject.next({x: 100, y: -40 });

expect(listener).to.have.been.calledWith({x: 110, y: -20 });
}
);

it('should have a shorthand signature for streams',
() => {
subject.addedBy(value$).subscribe(listener);

subject.next(3);
value$.next(10);
value$.next(20);

expect(listener).to.have.been.calledTwice.and.to.have.been.calledWith(13).and.to.have.been.calledWith(23);
}
);
}
);
31 changes: 31 additions & 0 deletions packages/core/src/operators/__tests__/dividedBy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,36 @@ describe('motionObservable.dividedBy',
expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 15, y: 20 });
}
);

it('should have a shorthand signature for numeric constants',
() => {
subject.dividedBy(5).subscribe(listener);

subject.next(10);

expect(listener).to.have.been.calledWith(2);
}
);

it('should have a shorthand signature for Point2D constants',
() => {
subject.dividedBy({ x : 10, y: 20 }).subscribe(listener);

subject.next({x: 100, y: 40 });

expect(listener).to.have.been.calledWith({x: 10, y: 2 });
}
);

it('should have a shorthand signature for streams',
() => {
subject.dividedBy(value$).subscribe(listener);

subject.next({ x: 30, y: 60 });
value$.next({ x: 2, y: 3 });

expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 15, y: 20 });
}
);
}
);
31 changes: 31 additions & 0 deletions packages/core/src/operators/__tests__/multipliedBy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,36 @@ describe('motionObservable.multipliedBy',
expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 12, y: 40 });
}
);

it('should have a shorthand signature for numeric constants',
() => {
subject.multipliedBy(10).subscribe(listener);

subject.next(3);

expect(listener).to.have.been.calledWith(30);
}
);

it('should have a shorthand signature for Point2D constants',
() => {
subject.multipliedBy({ x : 10, y: 20 }).subscribe(listener);

subject.next({ x: 2, y: 4 });

expect(listener).to.have.been.calledWith({ x: 20, y: 80 });
}
);

it('should have a shorthand signature for streams',
() => {
subject.multipliedBy(value$).subscribe(listener);

subject.next({ x: 3, y: 4 });
value$.next({ x: 4, y: 10 });

expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 12, y: 40 });
}
);
}
);
32 changes: 32 additions & 0 deletions packages/core/src/operators/__tests__/subtractedBy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,37 @@ describe('motionObservable.subtractedBy',
expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 10, y: -15 });
}
);

it('should have a shorthand signature for numeric constants',
() => {
subject.subtractedBy(10).subscribe(listener);

subject.next(3);

expect(listener).to.have.been.calledWith(-7);
}
);

it('should have a shorthand signature for Point2D constants',
() => {
subject.subtractedBy({ x: 10, y: 20 }).subscribe(listener);

subject.next({ x: 100, y: -40 });

expect(listener).to.have.been.calledWith({ x: 90, y: -60 });
}
);

it('should have a shorthand signature for streams',
() => {
subject.subtractedBy(value$).subscribe(listener);

subject.next({ x: 100, y: -40 });
subject.next({ x: 10, y: 0 });
value$.next({ x: 0, y: 15 });

expect(listener).to.have.been.calledOnce.and.to.have.been.calledWith({ x: 10, y: -15 });
}
);
}
);
13 changes: 12 additions & 1 deletion packages/core/src/operators/addedBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {
isDefined,
isPoint2D,
} from '../typeGuards';

Expand All @@ -30,8 +31,10 @@ import {
_ReactiveMapOptions,
} from './foundation/_reactiveMap';

export type AddedByValue<U> = U | Observable<U>;

export type AddedByArgs<U> = _ReactiveMapOptions & {
value$: U | Observable<U>
value$: AddedByValue<U>,
};

export interface MotionAddable<T> {
Expand All @@ -42,7 +45,9 @@ export interface MotionAddable<T> {
// To work around this, we overload the method signature. When `T` is a
// number, we explicitly return an `Observable<number>`. Otherwise, we can
// use the type variable `U`.
addedBy<U extends T & number>(value$: AddedByValue<U>): ObservableWithMotionOperators<number>;
addedBy<U extends T & number>(kwargs: AddedByArgs<U>): ObservableWithMotionOperators<number>;
addedBy<U extends T & Point2D>(value$: AddedByValue<U>): ObservableWithMotionOperators<U>;
addedBy<U extends T & Point2D>(kwargs: AddedByArgs<U>): ObservableWithMotionOperators<U>;
}

Expand All @@ -51,7 +56,13 @@ export function withAddedBy<T, S extends Constructor<MotionMathOperable<T>>>(sup
/**
* Adds the provided value to the upstream value and dispatches the result.
*/
addedBy<U extends T & (Point2D | number)>(value$: AddedByValue<U>): ObservableWithMotionOperators<U>;
addedBy<U extends T & (Point2D | number)>(kwargs: AddedByArgs<U>): ObservableWithMotionOperators<U>;
addedBy<U extends T & (Point2D | number)>({ value$, ...reactiveMapOptions }: AddedByArgs<U>): ObservableWithMotionOperators<U> {
if (!isDefined(value$)) {
value$ = arguments[0];
}

return this._mathOperator({
operation: (upstream, value) => upstream + value,
value$,
Expand Down
13 changes: 12 additions & 1 deletion packages/core/src/operators/dividedBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {
isDefined,
isPoint2D,
} from '../typeGuards';

Expand All @@ -30,8 +31,10 @@ import {
_ReactiveMapOptions,
} from './foundation/_reactiveMap';

export type DividedByValue<U> = U | Observable<U>;

export type DividedByArgs<U> = _ReactiveMapOptions & {
value$: U | Observable<U>
value$: DividedByValue<U>,
};

export interface MotionDivisible<T> {
Expand All @@ -43,7 +46,9 @@ export interface MotionDivisible<T> {
// To work around this, we overload the method signature. When `T` is a
// number, we explicitly return an `Observable<number>`. Otherwise, we can
// use the type variable `U`.
dividedBy<U extends T & number>(value$: DividedByValue<U>): ObservableWithMotionOperators<number>;
dividedBy<U extends T & number>(kwargs: DividedByArgs<U>): ObservableWithMotionOperators<number>;
dividedBy<U extends T & Point2D>(value$: DividedByValue<U>): ObservableWithMotionOperators<U>;
dividedBy<U extends T & Point2D>(kwargs: DividedByArgs<U>): ObservableWithMotionOperators<U>;
}

Expand All @@ -53,7 +58,13 @@ export function withDividedBy<T, S extends Constructor<MotionMathOperable<T>>>(s
* Divides the upstream value by the provided value and dispatches the
* result.
*/
dividedBy<U extends T & (Point2D | number)>(value$: DividedByValue<U>): ObservableWithMotionOperators<U>;
dividedBy<U extends T & (Point2D | number)>(kwargs: DividedByArgs<U>): ObservableWithMotionOperators<U>;
dividedBy<U extends T & (Point2D | number)>({ value$, ...reactiveMapOptions }: DividedByArgs<U>): ObservableWithMotionOperators<U> {
if (!isDefined(value$)) {
value$ = arguments[0];
}

return this._mathOperator({
operation: (upstream, value) => upstream / value,
value$,
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/operators/multipliedBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {
isDefined,
isPoint2D,
} from '../typeGuards';

Expand All @@ -30,8 +31,9 @@ import {
_ReactiveMapOptions,
} from './foundation/_reactiveMap';

export type MultipliedByValue<U> = U | Observable<U>;
export type MultipliedByArgs<U> = _ReactiveMapOptions & {
value$: U | Observable<U>
value$: MultipliedByValue<U>,
};

export interface MotionMultipliable<T> {
Expand All @@ -42,7 +44,9 @@ export interface MotionMultipliable<T> {
// To work around this, we overload the method signature. When `T` is a
// number, we explicitly return an `Observable<number>`. Otherwise, we can
// use the type variable `U`.
multipliedBy<U extends T & number>(value$: MultipliedByValue<U>): ObservableWithMotionOperators<number>;
multipliedBy<U extends T & number>(kwargs: MultipliedByArgs<U>): ObservableWithMotionOperators<number>;
multipliedBy<U extends T & Point2D>(value$: MultipliedByValue<U>): ObservableWithMotionOperators<U>;
multipliedBy<U extends T & Point2D>(kwargs: MultipliedByArgs<U>): ObservableWithMotionOperators<U>;
}

Expand All @@ -52,7 +56,13 @@ export function withMultipliedBy<T, S extends Constructor<MotionMathOperable<T>>
* Multiplies the upstream value by the provided value and dispatches the
* result.
*/
multipliedBy<U extends T & (Point2D | number)>(value$: MultipliedByValue<U>): ObservableWithMotionOperators<U>;
multipliedBy<U extends T & (Point2D | number)>(kwargs: MultipliedByArgs<U>): ObservableWithMotionOperators<U>;
multipliedBy<U extends T & (Point2D | number)>({ value$, ...reactiveMapOptions }: MultipliedByArgs<U>): ObservableWithMotionOperators<U> {
if (!isDefined(value$)) {
value$ = arguments[0];
}

return this._mathOperator({
operation: (upstream, value) => upstream * value,
value$,
Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/operators/subtractedBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import {
isDefined,
isPoint2D,
} from '../typeGuards';

Expand All @@ -30,8 +31,9 @@ import {
_ReactiveMapOptions,
} from './foundation/_reactiveMap';

export type SubtractedByValue<U> = U | Observable<U>;
export type SubtractedByArgs<U> = _ReactiveMapOptions & {
value$: U | Observable<U>
value$: SubtractedByValue<U>,
};
export interface MotionSubtractable<T> {
// Since number literals get their own types, `U extends T & number` will
Expand All @@ -41,7 +43,9 @@ export interface MotionSubtractable<T> {
// To work around this, we overload the method signature. When `T` is a
// number, we explicitly return an `Observable<number>`. Otherwise, we can
// use the type variable `U`.
subtractedBy<U extends T & number>(value$: SubtractedByValue<U>): ObservableWithMotionOperators<number>;
subtractedBy<U extends T & number>(kwargs: SubtractedByArgs<U>): ObservableWithMotionOperators<number>;
subtractedBy<U extends T & Point2D>(value$: SubtractedByValue<U>): ObservableWithMotionOperators<U>;
subtractedBy<U extends T & (Point2D | number)>(kwargs: SubtractedByArgs<U>): ObservableWithMotionOperators<U>;
}

Expand All @@ -51,7 +55,13 @@ export function withSubtractedBy<T, S extends Constructor<MotionMathOperable<T>>
* Subtracts the provided value from the upstream value and dispatches the
* result.
*/
subtractedBy<U extends T & (Point2D | number)>(value$: SubtractedByValue<U>): ObservableWithMotionOperators<U>;
subtractedBy<U extends T & (Point2D | number)>(kwargs: SubtractedByArgs<U>): ObservableWithMotionOperators<U>;
subtractedBy<U extends T & (Point2D | number)>({ value$, ...reactiveMapOptions }: SubtractedByArgs<U>): ObservableWithMotionOperators<U> {
if (!isDefined(value$)) {
value$ = arguments[0];
}

return this._mathOperator({
operation: (upstream, value) => upstream - value,
value$,
Expand Down

0 comments on commit cb16ebe

Please sign in to comment.