Skip to content

Commit

Permalink
rename reactive to responsive and add responsive event listener
Browse files Browse the repository at this point in the history
  • Loading branch information
soerenmeier committed Jan 14, 2024
1 parent 07fd1fe commit 97f6810
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 19 deletions.
14 changes: 7 additions & 7 deletions src/animation/animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ export default class Animation {
}
}

function maybeReactiveValue(prop, val) {
if (typeof val === 'object' && 'reactive' in val)
return val.reactive;
function maybeResponsiveValue(prop, val) {
if (typeof val === 'object' && 'responsive' in val)
return val.responsive;
return prop.parseValue(val);
}

Expand All @@ -110,12 +110,12 @@ class PropertyAnimation {

if (typeof value === 'object') {
if ('from' in value)
this.iniFrom = maybeReactiveValue(this.prop, value.from);
this.iniFrom = maybeResponsiveValue(this.prop, value.from);
if ('to' in value)
this.iniTo = maybeReactiveValue(this.prop, value.to);
this.iniTo = maybeResponsiveValue(this.prop, value.to);

if ('reactive' in value)
this.iniTo = value.reactive;
if ('responsive' in value)
this.iniTo = value.responsive;

if (!this.iniFrom && !this.iniTo)
throw new Error('from or to expected');
Expand Down
7 changes: 5 additions & 2 deletions src/chnobli.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import Animation from './animation/public.js';
import Timeline from './timeline/public.js';
import Scroll from './scroll/public.js';
import { stagger as _stagger } from './stagger/stagger.js';
import Stagger from './stagger/stagger.js';


// todo maybe add, to, from and fromTo to the animate function

/**
* Creates a simple animation
*
* ## Properties
*
*/
export function animate(targets, props = {}) {
return new Animation(targets, props);
Expand All @@ -18,7 +21,7 @@ export function timeline(props = {}) {
}

export function stagger(value) {
return _stagger(value);
return new Stagger(value);
}

export function scroll(props = {}) {
Expand Down
46 changes: 46 additions & 0 deletions src/responsive/event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export default class ResponsiveEvent {
constructor() {
this._listeners = new Set;

window.addEventListener('resize', e => this._onResize(e));
}

static global() {
// allow to define a test ticker
if (typeof globalThis !== 'undefined' && globalThis.chnobliResponsive)
return globalThis.chnobliResponsive;

if (typeof window === 'undefined')
return null;

if (typeof window.chnobliResponsive === 'undefined')
window.chnobliResponsive = new ResponsiveEvent;
return window.chnobliResponsive;
}

// fn({ width, height }, { remove() })
add(fn) {
this._listeners.add(fn);

return {
remove: () => {
this.remove(fn);
}
};
}

remove(fn) {
this._listeners.delete(fn);
}

_onResize(_e) {
for (const fn of this._listeners) {
fn({
width: window.innerWidth,
height: window.innerHeight
}, {
remove: () => this.remove(fn)
});
}
}
}
31 changes: 31 additions & 0 deletions src/responsive/testevent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export default class TestResponsiveEvent {
constructor() {
this._listeners = new Set;

globalThis.chnobliResponsive = this;
}

// fn({ width, height }, { remove() })
add(fn) {
this._listeners.add(fn);

return {
remove: () => {
this.remove(fn);
}
};
}

remove(fn) {
this._listeners.delete(fn);
}

resize(width, height) {
for (const fn of this._listeners) {
fn(
{ width, height },
{ remove: () => this.remove(fn) }
);
}
}
}
6 changes: 1 addition & 5 deletions src/stagger/stagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ export function staggerMap(value, fn) {
return fn(value);
}

export function stagger(value) {
return new Stagger(value);
}

class Stagger {
export default class Stagger {
constructor(value) {
if (typeof value === 'function') {
this.fn = value;
Expand Down
32 changes: 32 additions & 0 deletions src/tests/properties.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, it } from 'vitest';
import TestTicker from '../timing/testticker.js';
import TestResponsiveEvent from '../responsive/testevent.js';
import { animate, timeline } from '../chnobli.js';
import { el } from '../utils/testdomnode.js';

Expand All @@ -25,8 +26,30 @@ describe('properties', () => {
expect(div.style.width).toBe(undefined);
});

it('destroy', () => {
const ticker = new TestTicker;

const div = el();
const tl = timeline()
.add(div, {
x: 100,
width: 100,
duration: 10
})
.play();

ticker.run();
expect(div.style.transform).toBe('translateX(100.000px)');
expect(div.style.width).toBe('100.000px');

tl.resetProps();
expect(div.style.transform).toBe('');
expect(div.style.width).toBe(undefined);
});

it('update timeline', () => {
const ticker = new TestTicker;
const respEv = new TestResponsiveEvent;

const div = el();
div.computedStyle.width = '10px';
Expand Down Expand Up @@ -54,5 +77,14 @@ describe('properties', () => {
expect(div.style.width).toBe('36.000px');
ticker.run();
expect(div.style.width).toBe('100.000px');

tl.reverse();
tl.play();
ticker.run(5);
expect(div.style.width).toBe('60.000px');

div.computedStyle.width = '30px';
respEv.resize();
expect(div.style.width).toBe('65.000px');
});
});
8 changes: 8 additions & 0 deletions src/tests/timing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ describe('timing', () => {
timing2.reverse();
expect(timing2.state).toBe(STATE_START);
expect(timing2.position).toBe(1);

timing2.seek(-1);
expect(timing2.state).toBe(STATE_BEFORE);
expect(timing2.position).toBe(1);

timing2.seek(.25);
expect(timing2.state).toBe(STATE_RUNNING);
expect(timing2.position).toBe(.75);
});

it('repeat', () => {
Expand Down
11 changes: 9 additions & 2 deletions src/tests/usecases.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { describe, expect, it } from 'vitest';
import TestTicker from '../timing/testticker.js';
import TestResponsiveEvent from '../responsive/testevent.js';
import { animate, timeline } from '../chnobli.js';
import { reactive } from '../utils/utils.js';
import { responsive } from '../utils/utils.js';
import { el } from '../utils/testdomnode.js';

describe('usecases', () => {
it('accordion', () => {
const ticker = new TestTicker;
const respEv = new TestResponsiveEvent;

const itm = el();
const ctn = el();
Expand All @@ -18,7 +20,7 @@ describe('usecases', () => {
cls: 'open'
})
.add(ctn, {
maxHeight: reactive(el => el.scrollHeight),
maxHeight: responsive(el => el.scrollHeight),
duration: 100
}, 0);

Expand All @@ -45,6 +47,11 @@ describe('usecases', () => {
expect(ctn.style.maxHeight).toBe('176.000px');
expect(itm.classList.contains('open')).toBe(true);

ctn.scrollHeight = '150px';
respEv.resize(1000, 1000);
expect(ctn.style.maxHeight).toBe('132.000px');
expect(itm.classList.contains('open')).toBe(true);

ticker.run();
expect(ctn.style.maxHeight).toBe(undefined);
expect(itm.classList.contains('open')).toBe(false);
Expand Down
16 changes: 16 additions & 0 deletions src/timeline/public.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Timeline from './timeline.js';
import { STATE_ENDED } from '../timing/timing.js';
import { callStagger } from '../stagger/stagger.js';
import Events from '../utils/events.js';
import ResponsiveEvent from '../responsive/event.js';

const STATE_PAUSED = 0;
const STATE_RENDER_ONCE = 1;
Expand All @@ -21,6 +22,9 @@ export default class PublicTimeline {
this._state = STATE_PAUSED;
this._renderedOnce = false;
this._runningTicker = null;
this._responsiveEvent = ResponsiveEvent.global()?.add((...args) => {
this._onResponsive(...args);
});
}

/**
Expand Down Expand Up @@ -146,9 +150,14 @@ export default class PublicTimeline {
* Resets every used prop to it's previous value
*/
resetProps() {
const reversed = this._inner.timing.reverse;
this._inner.timing.reverse = false;
this._inner.seek(-1);
this._inner.render();
this._inner.ticker.applyTargets();

this._inner.timing.reverse = reversed;
this._inner.seek(-1);
}

/**
Expand Down Expand Up @@ -264,4 +273,11 @@ export default class PublicTimeline {
this._runningTicker.remove();
this._runningTicker = null;
}

_onResponsive(_obj) {
// // make sure we don't render something if we never did
// if (!this._renderedOnce)
// return;
this._inner.update();
}
}
10 changes: 9 additions & 1 deletion src/timeline/timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ export default class Timeline {
entry.value.init(reset);
}

this.timing.seek(-1);
this.timing.reversed = reversed;
this.timing.seek(-1);
startOrdered.forEach(e => {
e.value.seek(-1);
e.value.render();
Expand Down Expand Up @@ -218,15 +218,23 @@ export default class Timeline {
}

update() {
if (!this._initialized)
return;

const pos = this.timing.savePosition();
const reversed = this.timing.reversed;
this.timing.reversed = false;

this.timing.seek(-1);
this._updateTimings();
this.render();
this.ticker.applyTargets();

// we now have removed every style we set
// we should be able to recalculate everything now
this._initAnimations(true);

this.timing.reversed = reversed;
this.timing.restorePosition(pos);
this._updateTimings();
this.render();
Expand Down
4 changes: 2 additions & 2 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export function fromTo(from, to) {
/**
* makes a value reactive to `Timeline::update` calls or resizes
*/
export function reactive(fn) {
return { reactive: fn };
export function responsive(fn) {
return { responsive: fn };
}

/**
Expand Down

0 comments on commit 97f6810

Please sign in to comment.