chnobli 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.github/workflows/ci.yaml +14 -1
- package/LICENSE.md +1 -1
- package/docs/INDEX.md +15 -0
- package/jsdoc.conf.json +1 -1
- package/package.json +6 -3
- package/src/animation/animation.js +88 -25
- package/src/animation/property.js +408 -43
- package/src/animation/public.js +72 -2
- package/src/animator.js +2 -0
- package/src/chnobli.js +8 -3
- package/src/responsive/event.js +46 -0
- package/src/responsive/testevent.js +31 -0
- package/src/scroll/event.js +1 -1
- package/src/stagger/stagger.js +5 -8
- package/src/target/basetarget.js +92 -0
- package/src/target/domtarget.js +266 -0
- package/src/target/target.js +22 -0
- package/src/target/testdomnode.js +61 -0
- package/src/tests/properties.test.js +150 -0
- package/src/tests/timeline.test.js +234 -0
- package/src/tests/timing.test.js +270 -0
- package/src/tests/usecases.test.js +64 -0
- package/src/tests/values.test.js +162 -0
- package/src/timeline/public.js +192 -13
- package/src/timeline/timeline.js +76 -22
- package/src/timing/testticker.js +98 -0
- package/src/timing/ticker.js +49 -9
- package/src/timing/timing.js +121 -21
- package/src/utils/events.js +4 -0
- package/src/utils/motionpath.js +3 -0
- package/src/utils/utils.js +22 -2
- package/src/values/colorvalue.js +167 -0
- package/src/values/defaultcolors.js +148 -0
- package/src/values/stylevalue.js +148 -0
- package/src/{utils → values}/value.js +15 -7
- package/src/utils/target.js +0 -164
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import Value from './value.js';
|
|
2
|
+
import ColorValue from './colorvalue.js';
|
|
3
|
+
|
|
4
|
+
const AT_THE_END_VALUES = ['none', 'hidden'];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A value from a style property
|
|
8
|
+
*
|
|
9
|
+
* might be a textual representation like none|auto|block|var(--abc)
|
|
10
|
+
* might be a value with unit or not
|
|
11
|
+
* might be multiple values `10 20px 4rem`
|
|
12
|
+
*
|
|
13
|
+
* values like hidden|none|null|undefined are market as at the end
|
|
14
|
+
* which means they should be set at the end
|
|
15
|
+
*/
|
|
16
|
+
export default class StyleValue {
|
|
17
|
+
/**
|
|
18
|
+
* Creates a style value
|
|
19
|
+
*
|
|
20
|
+
* ## value must be one of the following
|
|
21
|
+
* - string (meaning this is of kind text)
|
|
22
|
+
* - number (meaning this is of kind values with one value)
|
|
23
|
+
* - array (meaning this is of kind values and each array element needs to
|
|
24
|
+
* be a Value)
|
|
25
|
+
* - ColorValue
|
|
26
|
+
*/
|
|
27
|
+
constructor(value) {
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
this.kind = 'text';
|
|
30
|
+
value = value.trim();
|
|
31
|
+
} else if (typeof value === 'number') {
|
|
32
|
+
this.kind = 'values';
|
|
33
|
+
value = [Value.parse(value)];
|
|
34
|
+
} else if (Array.isArray(value)) {
|
|
35
|
+
this.kind = 'values';
|
|
36
|
+
} else if (value instanceof ColorValue) {
|
|
37
|
+
this.kind = 'color';
|
|
38
|
+
} else {
|
|
39
|
+
throw new Error('unknown style value ' + value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.values = value;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* If this is true the value should be set at the end of a animation
|
|
46
|
+
* this only works with kind === text
|
|
47
|
+
*/
|
|
48
|
+
this.textAtTheEnd = this.kind === 'text'
|
|
49
|
+
? AT_THE_END_VALUES.includes(this.values)
|
|
50
|
+
: false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
static parse(v) {
|
|
55
|
+
if (typeof v === 'number')
|
|
56
|
+
return new StyleValue(v);
|
|
57
|
+
|
|
58
|
+
if (Array.isArray(v)) {
|
|
59
|
+
const val = v.map(v => Value.parse(v));
|
|
60
|
+
return new StyleValue(val);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (typeof v !== 'string')
|
|
64
|
+
throw new Error('expected a string as style value ' + v);
|
|
65
|
+
|
|
66
|
+
// let's first try to make it a color
|
|
67
|
+
if (ColorValue.mightBeAColor(v))
|
|
68
|
+
return new StyleValue(ColorValue.parse(v));
|
|
69
|
+
|
|
70
|
+
const split = v.split(' ').map(v => v.trim()).filter(v => !!v);
|
|
71
|
+
if (split.length === 0)
|
|
72
|
+
throw new Error('style value cannot be empty');
|
|
73
|
+
|
|
74
|
+
if (split.length === 1) {
|
|
75
|
+
try {
|
|
76
|
+
const val = Value.parse(split[0]);
|
|
77
|
+
return new StyleValue([val]);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
// console.log('failed to parse first style value ', e);
|
|
80
|
+
return new StyleValue(split[0]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return new StyleValue(split.map(v => Value.parse(v)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// only works if the kind is values
|
|
88
|
+
get length() {
|
|
89
|
+
if (this.kind !== 'values')
|
|
90
|
+
throw new Error('only works with kind values');
|
|
91
|
+
|
|
92
|
+
return this.values.length;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
extendToLength(length) {
|
|
96
|
+
if (this.length >= length)
|
|
97
|
+
return;
|
|
98
|
+
|
|
99
|
+
this.values = Array(length).fill(this.values).flat();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Throws if the this does not contain exactly one value
|
|
104
|
+
*/
|
|
105
|
+
intoValue() {
|
|
106
|
+
if (this.length !== 1)
|
|
107
|
+
throw new Error('style value does not contain only one value');
|
|
108
|
+
|
|
109
|
+
return this.values[0];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
clone() {
|
|
113
|
+
if (this.kind === 'text')
|
|
114
|
+
return new StyleValue(this.values);
|
|
115
|
+
|
|
116
|
+
if (this.kind === 'color')
|
|
117
|
+
return new StyleValue(this.values.clone());
|
|
118
|
+
|
|
119
|
+
return new StyleValue(this.values.map(v => v.clone()));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// if this is called with a text value nothing happens
|
|
123
|
+
withDefaultUnit(unit) {
|
|
124
|
+
if (this.kind === 'text')
|
|
125
|
+
return new StyleValue(this.values);
|
|
126
|
+
|
|
127
|
+
if (this.kind === 'color')
|
|
128
|
+
return new StyleValue(this.values.clone());
|
|
129
|
+
|
|
130
|
+
return new StyleValue(this.values.map(v => v.withDefaultUnit(unit)));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
toString() {
|
|
134
|
+
switch (this.kind) {
|
|
135
|
+
case 'text':
|
|
136
|
+
return this.values;
|
|
137
|
+
|
|
138
|
+
case 'color':
|
|
139
|
+
return this.values.toString();
|
|
140
|
+
|
|
141
|
+
case 'values':
|
|
142
|
+
return this.values.join(' ');
|
|
143
|
+
|
|
144
|
+
default:
|
|
145
|
+
throw new Error('unknown kind ' + this.kind);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const REGEX = /^(\d+\.?\d*|\.\d+)(\w*|%)$/;
|
|
2
2
|
|
|
3
|
-
const REGEX = /^(\d*\.?\d*)(\w*)$/;
|
|
4
3
|
|
|
5
4
|
export default class Value {
|
|
6
5
|
constructor(num, unit = null) {
|
|
@@ -8,19 +7,20 @@ export default class Value {
|
|
|
8
7
|
this.unit = unit;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
static parse(v
|
|
10
|
+
static parse(v) {
|
|
12
11
|
if (typeof v === 'number') {
|
|
13
|
-
return new Value(v
|
|
12
|
+
return new Value(v);
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
const [_v, num, unit] = REGEX.exec(v);
|
|
17
16
|
|
|
18
|
-
if (unit && !UNITS.includes(unit))
|
|
19
|
-
throw new Error('unknown unit ' + unit);
|
|
20
|
-
|
|
21
17
|
return new Value(parseFloat(num), unit ? unit : null);
|
|
22
18
|
}
|
|
23
19
|
|
|
20
|
+
eq(other) {
|
|
21
|
+
return this.unit === other.unit && this.num === other.num;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
24
|
clone(newNum = null) {
|
|
25
25
|
if (newNum !== null)
|
|
26
26
|
return new Value(newNum, this.unit);
|
|
@@ -32,6 +32,14 @@ export default class Value {
|
|
|
32
32
|
return new Value(this.num + add, this.unit);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
cloneMul(mul) {
|
|
36
|
+
return new Value(this.num * mul, this.unit);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
withDefaultUnit(unit) {
|
|
40
|
+
return new Value(this.num, this.unit ?? unit);
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
toString() {
|
|
36
44
|
return this.num.toFixed(3) + (this.unit ?? '');
|
|
37
45
|
}
|
package/src/utils/target.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import Value from './value.js';
|
|
2
|
-
|
|
3
|
-
const DEBUG_SET_GET = false;
|
|
4
|
-
|
|
5
|
-
export default class Target {
|
|
6
|
-
constructor(target) {
|
|
7
|
-
this.target = target;
|
|
8
|
-
|
|
9
|
-
// this might be an object, a dom node
|
|
10
|
-
// what about arrays?
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type() {
|
|
14
|
-
return 'unknown';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
getValue(name) {
|
|
18
|
-
throw new Error('cannot get value of ' + name);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
setValue(name, value) {
|
|
22
|
-
throw new Error('cannot set value of ' + name);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
removeValue(name) {
|
|
26
|
-
throw new Error('cannot remove value of ' + name);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
getTransformValue(name) {
|
|
30
|
-
return this.getValue(name);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
setTransformValue(name, value) {
|
|
34
|
-
return this.setValue(name, value);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
removeTransformValue(name) {
|
|
38
|
-
return this.removeValue(name);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
getStyleValue(name) {
|
|
42
|
-
return this.getValue(name);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
setStyleValue(name, value) {
|
|
46
|
-
return this.setValue(name, value);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
removeStyleValue(name) {
|
|
50
|
-
return this.removeValue(name);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
apply() {}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export class DomTarget extends Target {
|
|
57
|
-
constructor(target) {
|
|
58
|
-
super(target);
|
|
59
|
-
|
|
60
|
-
// for the moment
|
|
61
|
-
|
|
62
|
-
this.transformValues = new Map;
|
|
63
|
-
this.styleValues = new Map;
|
|
64
|
-
this.values = new Map;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
type() {
|
|
68
|
-
return 'dom';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
getValue(name) {
|
|
72
|
-
if (DEBUG_SET_GET)
|
|
73
|
-
console.log('get', name);
|
|
74
|
-
|
|
75
|
-
return this.values.get(name);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
setValue(name, value) {
|
|
79
|
-
if (DEBUG_SET_GET)
|
|
80
|
-
console.log('set', name, value);
|
|
81
|
-
|
|
82
|
-
this.values.set(name, value);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
removeValue(name) {
|
|
86
|
-
this.values.delete(name);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
getTransformValue(name) {
|
|
90
|
-
if (DEBUG_SET_GET)
|
|
91
|
-
console.log('get', name);
|
|
92
|
-
|
|
93
|
-
return this.transformValues.get(name);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
setTransformValue(name, value) {
|
|
97
|
-
if (DEBUG_SET_GET)
|
|
98
|
-
console.log('set', name, value);
|
|
99
|
-
|
|
100
|
-
this.transformValues.set(name, value);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
removeTransformValue(name) {
|
|
104
|
-
this.transformValues.delete(name);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
getStyleValue(name) {
|
|
108
|
-
if (DEBUG_SET_GET)
|
|
109
|
-
console.log('get', name);
|
|
110
|
-
|
|
111
|
-
const v = this.styleValues.get(name);
|
|
112
|
-
|
|
113
|
-
if (typeof v === 'undefined' || v === null) {
|
|
114
|
-
// let's try to get it from the dom
|
|
115
|
-
const style = getComputedStyle(this.target);
|
|
116
|
-
const styleV = style[name];
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const value = Value.parse(styleV);
|
|
120
|
-
this.styleValues.set(name, value);
|
|
121
|
-
|
|
122
|
-
return value;
|
|
123
|
-
} catch (e) {
|
|
124
|
-
console.log('could not parse value', styleV);
|
|
125
|
-
return v;
|
|
126
|
-
}
|
|
127
|
-
} else
|
|
128
|
-
return v;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
setStyleValue(name, value) {
|
|
132
|
-
if (DEBUG_SET_GET)
|
|
133
|
-
console.log('set', name, value);
|
|
134
|
-
|
|
135
|
-
this.styleValues.set(name, value);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
removeStyleValue(name) {
|
|
139
|
-
this.styleValues.delete(name);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
apply() {
|
|
143
|
-
this.target.style.transform = Array.from(this.transformValues.entries())
|
|
144
|
-
.map(([k, v]) => `${k}(${v})`)
|
|
145
|
-
.join(' ');
|
|
146
|
-
|
|
147
|
-
// style
|
|
148
|
-
for (const [k, v] of this.styleValues.entries()) {
|
|
149
|
-
this.target.style[k] = v;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// values
|
|
153
|
-
for (const [k, v] of this.values.entries()) {
|
|
154
|
-
console.log('what todo with this ' + k);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function newTarget(target) {
|
|
160
|
-
if (target instanceof HTMLElement || target instanceof SVGElement)
|
|
161
|
-
return new DomTarget(target);
|
|
162
|
-
|
|
163
|
-
throw new Error('unknown target');
|
|
164
|
-
}
|