JSConf Iceland 2016
+
Custom Properties
RxJS & Observables
.modal {
animation: modal-enter 0.6s ease-in-out both;
}
@keyframes modal-enter {
from {
opacity: 0;
transform: translateY(50%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
const modal = document.querySelector('.modal');
modal.animate([
{
opacity: 0,
transform: 'translateY(50%)',
},
{
opacity: 1,
transform: 'translateY(0)',
}
], {
duration: 600,
easing: 'ease-in-out',
direction: 'both'
});
const box = document.querySelector('.box');
document.addEventListener('mousemove', (event) => {
requestAnimationFrame(() => {
box.style.transform = `
translateX(${event.pageX})
translateY(${event.pageY})
`;
});
});
--my-color: blue;
:root {
}
.lagoon {
}
color: var(--my-color);
const docStyle = document.documentElement.style;
docStyle.setProperty('--color-primary', 'blue')
docStyle.getPropertyValue('--color-primary');
// => 'blue'
docStyle.removeProperty('--color-primary');
Sets the custom property
Gets the custom property
Removes the custom property
Big surprise
[
]
Rx.Observable.from([1, 2, 3, 4, 5]);
Rx.Observable.fromPromise(fetch(url));
Rx.Observable.fromEvent(document, 'mousemove');
Rx.Observable.fromEventPattern((h) =>
hammerFoo.on('pan', h));
Creates Observable from iterable (array, set, etc.)
Creates Observable from promise
Creates Observable from DOM node and event name
Creates Observable from passing handler to event pattern
const ball = document.querySelector('#ball');
const hBall = new Hammer(ball);
const pan$ = Rx.Observable.fromEventPattern((handler) =>
hBall.on('pan', handler));
const logger = ticker$.subscribe(
(value) => { console.log(value); },
(error) => { console.error(e); },
() => {
console.log('You have reached the end of time');
}
);
executes on every pushed (next) value
executes on error
executes on completion
event$.subscribe((event) =>
doSomething(event));
Aggregate, All, Amb, and_, And, Any, apply, as_blocking, asObservable, AssertEqual, asyncAction, asyncFunc, Average, averageDouble, averageFloat, averageInteger, averageLong, blocking, Buffer, bufferWithCount, bufferWithTime, bufferWithTimeOrCount, byLine, cache, case, Cast, Catch, catchError, catchException, collect, collect (RxScala version of Filter), CombineLatest, combineLatestWith, Concat, concat_all, concatMap, concatMapObserver, concatMapTo, concatAll, concatWith, Connect, connect_forever, cons, Contains, controlled, Count, countLong, Create, cycle, Debounce, decode, DefaultIfEmpty, Defer, deferFuture, Delay, delaySubscription, delayWithSelector, Dematerialize, Distinct, distinctKey, distinctUntilChanged, distinctUntilKeyChanged, Do, doAction, doAfterTerminate, doOnCompleted, doOnEach, doOnError, doOnRequest, doOnSubscribe, doOnTerminate, doOnUnsubscribe, doseq, doWhile, drop, dropRight, dropUntil, dropWhile, ElementAt, ElementAtOrDefault, Empty, emptyObservable, empty?, encode, ensures, error, every, exclusive, exists, expand, failWith, Filter, filterNot, Finally, finallyAction, finallyDo, find, findIndex, First, FirstOrDefault, firstOrElse, FlatMap, flatMapFirst, flatMapIterable, flatMapIterableWith, flatMapLatest, flatMapObserver, flatMapWith, flatMapWithMaxConcurrent, flat_map_with_index, flatten, flattenDelayError, foldl, foldLeft, for, forall, ForEach, forEachFuture, forIn, forkJoin, From, fromAction, fromArray, FromAsyncPattern, fromCallable, fromCallback, FromEvent, FromEventPattern, fromFunc0, from_future, from_iterable, fromIterator, from_list, fromNodeCallback, fromPromise, fromRunnable, Generate, generateWithAbsoluteTime, generateWithRelativeTime, generator, GetEnumerator, getIterator, GroupBy, GroupByUntil, GroupJoin, head, headOption, headOrElse, if, ifThen, IgnoreElements, indexOf, interleave, interpose, Interval, into, isEmpty, items, Join, join (string), jortSort, jortSortUntil, Just, keep, keep-indexed, Last, lastOption, LastOrDefault, lastOrElse, Latest, latest (Rx.rb version of Switch), length, let, letBind, limit, LongCount, ManySelect, Map, map (RxClojure version of Zip), MapCat, mapCat (RxClojure version of Zip), map-indexed, mapTo, mapWithIndex, Materialize, Max, MaxBy, Merge, mergeAll, merge_concurrent, mergeDelayError, mergeObservable, mergeWith, Min, MinBy, MostRecent, Multicast, multicastWithSelector, nest, Never, Next, Next (BlockingObservable version), none, nonEmpty, nth, ObserveOn, ObserveOnDispatcher, observeSingleOn, of, of_array, ofArrayChanges, of_enumerable, of_enumerator, ofObjectChanges, OfType, ofWithScheduler, onBackpressureBlock, onBackpressureBuffer, onBackpressureDrop, OnErrorResumeNext, onErrorReturn, onExceptionResumeNext, orElse, pairs, pairwise, partition, partition-all, pausable, pausableBuffered, pluck, product, Publish, PublishLast, publish_synchronized, publishValue, raise_error, Range, Reduce, reductions, RefCount, Repeat, repeat_infinitely, repeatWhen, Replay, rescue_error, rest, Retry, retry_infinitely, retryWhen, Return, returnElement, returnValue, runAsync, Sample, Scan, scope, Select (alternate name of Map), select (alternate name of Filter), selectConcat, selectConcatObserver, SelectMany, selectManyObserver, select_switch, selectSwitch, selectSwitchFirst, selectWithMaxConcurrent, select_with_index, seq, SequenceEqual, sequence_eql?, SequenceEqualWith, Serialize, share, shareReplay, shareValue, Single, SingleOrDefault, singleOption, singleOrElse, size, Skip, SkipLast, skipLastWithTime, SkipUntil, skipUntilWithTime, SkipWhile, skipWhileWithIndex, skip_with_time, slice, sliding, slidingBuffer, some, sort, sort-by, sorted-list-by, split, split-with, Start, startAsync, startFuture, StartWith, startWithArray, stringConcat, stopAndWait, subscribe, SubscribeOn, SubscribeOnDispatcher, subscribeOnCompleted, subscribeOnError, subscribeOnNext, Sum, sumDouble, sumFloat, sumInteger, sumLong, Switch, switchCase, switchIfEmpty, switchLatest, switchMap, switchOnNext, Synchronize, Take, take_with_time, takeFirst, TakeLast, takeLastBuffer, takeLastBufferWithTime, takeLastWithTime, takeRight (see also: TakeLast), TakeUntil, takeUntilWithTime, TakeWhile, takeWhileWithIndex, tail, tap, tapOnCompleted, tapOnError, tapOnNext, Then, thenDo, Throttle, throttleFirst, throttleLast, throttleWithSelector, throttleWithTimeout, Throw, throwError, throwException, TimeInterval, Timeout, timeoutWithSelector, Timer, Timestamp, To, to_a, ToArray, ToAsync, toBlocking, toBuffer, to_dict, ToDictionary, ToEnumerable, ToEvent, ToEventPattern, ToFuture, to_h, toIndexedSeq, toIterable, toIterator, ToList, ToLookup, toMap, toMultiMap, ToObservable, toSet, toSortedList, toStream, ToTask, toTraversable, toVector, tumbling, tumblingBuffer, unsubscribeOn, Using, When, Where, while, whileDo, Window, windowWithCount, windowWithTime, windowWithTimeOrCount, windowed, withFilter, withLatestFrom, Zip, zipArray, zipWith, zipWithIndex
.filter(ball => ball.color === 'green')
.map(ball => makeSquare(ball))
.debounce(1000)
.scan((a, b) => a + b)
1
2
3
5
6
8
1
1
1
2
1
2
.mergeAll()
Before we go to the next slide, I want you to take a moment and forget everything you've read about CSS-in-JS.
Keep an open mind.
A "reactive animation" is one involving discrete changes, due to events.
By allowing programmers to express the "what" of an interactive animation, one can hope to then automate the "how" of its presentation.
Rx.Subject()
CSS Variables
mouseMove$
scroll$
tap$
swipe$
timer$
...etc.
(Observers)
An Rx.Subjectย is both
an observable and an observer.
const mouse$ = Rx.Observable
.fromEvent(document, 'mousemove')
.map(({ x, y }) => ({ x, y }));
const style$ = RxCSS({
mouse: mouse$,
});
style$.subscribe(...);
npm install rxcss --save
:root {
--mouse-x: 0;
--mouse-y: 0;
}
.ball {
transform:
translateX(var(--mouse-x))
translateY(var(--mouse-y));
}
โ scroll$ Observable
Easily debuggable
DOM node independent
Theming
Progressive enhancement
calc() FTW
They work in SVG!