@tempots/dom 5.0.2 → 6.0.0
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/components/FadeIn.d.ts +3 -1
- package/components/FadeIn.js +7 -5
- package/components/For.d.ts +3 -1
- package/components/For.js +5 -5
- package/components/HiddenWhenEmpty.js +2 -1
- package/components/If.js +3 -3
- package/components/Lifecycle.d.ts +2 -2
- package/components/Lifecycle.js +2 -2
- package/components/NotEmpty.d.ts +1 -2
- package/components/OnRemove.d.ts +2 -7
- package/components/OnRemove.js +2 -12
- package/components/OneOf.d.ts +48 -6
- package/components/OneOf.js +28 -8
- package/components/Repeat.d.ts +14 -3
- package/components/Repeat.js +89 -4
- package/components/animatable.d.ts +20 -0
- package/components/animatable.js +128 -2
- package/dom-context.d.ts +1 -0
- package/dom-context.js +3 -0
- package/index.d.ts +33 -36
- package/index.js +30 -32
- package/package.json +1 -1
- package/prop.d.ts +2 -0
- package/prop.js +41 -0
package/components/FadeIn.d.ts
CHANGED
|
@@ -5,14 +5,16 @@ import { Animatable } from "./animatable";
|
|
|
5
5
|
export declare class FadeInImpl implements Renderable {
|
|
6
6
|
private readonly end;
|
|
7
7
|
private readonly start;
|
|
8
|
+
private readonly easing;
|
|
8
9
|
private readonly duration;
|
|
9
10
|
private readonly delay;
|
|
10
|
-
constructor(end: Animatable, start: Animatable | undefined, duration: number, delay: number);
|
|
11
|
+
constructor(end: Animatable, start: Animatable | undefined, easing: (t: number) => number, duration: number, delay: number);
|
|
11
12
|
appendTo(ctx: DOMContext): Clear;
|
|
12
13
|
}
|
|
13
14
|
export interface FadeInProps extends Animatable {
|
|
14
15
|
start?: Animatable;
|
|
15
16
|
duration?: number;
|
|
17
|
+
easing?: (t: number) => number;
|
|
16
18
|
delay?: number;
|
|
17
19
|
}
|
|
18
20
|
export declare function FadeIn(props: FadeInProps): Renderable;
|
package/components/FadeIn.js
CHANGED
|
@@ -2,11 +2,13 @@ import { getComputedAnimatable, applyInterpolatedAnimatable, applyAnimatable } f
|
|
|
2
2
|
export class FadeInImpl {
|
|
3
3
|
end;
|
|
4
4
|
start;
|
|
5
|
+
easing;
|
|
5
6
|
duration;
|
|
6
7
|
delay;
|
|
7
|
-
constructor(end, start, duration, delay) {
|
|
8
|
+
constructor(end, start, easing, duration, delay) {
|
|
8
9
|
this.end = end;
|
|
9
10
|
this.start = start;
|
|
11
|
+
this.easing = easing;
|
|
10
12
|
this.duration = duration;
|
|
11
13
|
this.delay = delay;
|
|
12
14
|
}
|
|
@@ -22,7 +24,7 @@ export class FadeInImpl {
|
|
|
22
24
|
}
|
|
23
25
|
})();
|
|
24
26
|
const startTime = Date.now() + this.delay;
|
|
25
|
-
const { duration, end } = this;
|
|
27
|
+
const { duration, end, easing } = this;
|
|
26
28
|
let nextFrameId = null;
|
|
27
29
|
function frame() {
|
|
28
30
|
const now = Date.now();
|
|
@@ -31,7 +33,7 @@ export class FadeInImpl {
|
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
35
|
const progress = Math.min((now - startTime) / duration, 1);
|
|
34
|
-
applyInterpolatedAnimatable(el, start, end, progress);
|
|
36
|
+
applyInterpolatedAnimatable(el, start, end, easing(progress));
|
|
35
37
|
if (progress < 1) {
|
|
36
38
|
nextFrameId = requestAnimationFrame(frame);
|
|
37
39
|
}
|
|
@@ -47,6 +49,6 @@ export class FadeInImpl {
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
export function FadeIn(props) {
|
|
50
|
-
const { start, duration, delay, ...end } = props;
|
|
51
|
-
return new FadeInImpl(end, start, duration ?? 200, delay ?? 0);
|
|
52
|
+
const { start, duration, easing, delay, ...end } = props;
|
|
53
|
+
return new FadeInImpl(end, start, easing ?? (v => v), duration ?? 200, delay ?? 0);
|
|
52
54
|
}
|
package/components/For.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type Signal } from '../prop';
|
|
2
|
+
import { SeparatorProps } from './Repeat';
|
|
2
3
|
import { type JSX } from '../jsx-runtime';
|
|
3
4
|
export interface ForProps<T> {
|
|
4
5
|
of: Signal<T[]>;
|
|
6
|
+
separator?: (value: Signal<SeparatorProps>) => JSX.DOMNode;
|
|
5
7
|
children?: (value: Signal<T>, index: number) => JSX.DOMNode;
|
|
6
8
|
}
|
|
7
|
-
export declare function For<T>({ of, children: render }: ForProps<T>): JSX.DOMNode;
|
|
9
|
+
export declare function For<T>({ of, children: render, separator }: ForProps<T>): JSX.DOMNode;
|
package/components/For.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { RepeatImpl } from './Repeat';
|
|
2
2
|
import { makeRenderable } from '../jsx-runtime';
|
|
3
3
|
import { FragmentImpl } from './Fragment';
|
|
4
|
-
import {
|
|
5
|
-
// <For of={values}>{(value) => <span>{value}</span>}</For>
|
|
6
|
-
export function For({ of, children: render }) {
|
|
4
|
+
import { OnRemove } from './OnRemove';
|
|
5
|
+
// <For of={values} separator={() => ", "}>{(value) => <span>{value}</span>}</For>
|
|
6
|
+
export function For({ of, children: render, separator }) {
|
|
7
7
|
const times = of.map(v => v.length);
|
|
8
8
|
return new RepeatImpl(times, (index) => {
|
|
9
9
|
const value = of.at(index);
|
|
10
10
|
return new FragmentImpl([
|
|
11
11
|
makeRenderable(render?.(value, index)),
|
|
12
|
-
|
|
12
|
+
OnRemove({ clear: value.clean })
|
|
13
13
|
]);
|
|
14
|
-
});
|
|
14
|
+
}, separator);
|
|
15
15
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export class HiddenWhenEmptyImpl {
|
|
2
2
|
appendTo(ctx) {
|
|
3
|
+
const initial = ctx.getStyle(':empty');
|
|
3
4
|
ctx.setStyle(':empty', 'display: none');
|
|
4
5
|
return (removeTree) => {
|
|
5
6
|
if (removeTree)
|
|
6
|
-
ctx.setStyle(':empty',
|
|
7
|
+
ctx.setStyle(':empty', initial);
|
|
7
8
|
};
|
|
8
9
|
}
|
|
9
10
|
}
|
package/components/If.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { OneOfImpl } from './OneOf';
|
|
2
2
|
export function If({ is, then, otherwise }) {
|
|
3
|
-
return new OneOfImpl(is.map(v => v ?
|
|
3
|
+
return new OneOfImpl(is.map(v => v ? { 1: true } : { 2: false }), {
|
|
4
4
|
1: () => then,
|
|
5
5
|
2: () => otherwise
|
|
6
6
|
});
|
|
7
7
|
}
|
|
8
8
|
export function When({ is, children }) {
|
|
9
|
-
return new OneOfImpl(is.map(v => v ?
|
|
9
|
+
return new OneOfImpl(is.map(v => v ? { 1: true } : { 2: false }), {
|
|
10
10
|
1: () => children,
|
|
11
11
|
2: () => null
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
export function Unless({ is, children }) {
|
|
15
|
-
return new OneOfImpl(is.map(v => v ?
|
|
15
|
+
return new OneOfImpl(is.map(v => v ? { 1: true } : { 2: false }), {
|
|
16
16
|
1: () => null,
|
|
17
17
|
2: () => children
|
|
18
18
|
});
|
|
@@ -4,11 +4,11 @@ import { type Renderable } from '../renderable';
|
|
|
4
4
|
export declare class LifecycleImpl implements Renderable {
|
|
5
5
|
private readonly onMount;
|
|
6
6
|
private readonly onUnmount;
|
|
7
|
-
constructor(onMount: (el: HTMLElement) => void, onUnmount: (el: HTMLElement) => void);
|
|
7
|
+
constructor(onMount: (el: HTMLElement) => void, onUnmount: (el: HTMLElement, removeTree: boolean) => void);
|
|
8
8
|
readonly appendTo: (ctx: DOMContext) => Clear;
|
|
9
9
|
}
|
|
10
10
|
export interface LifecycleProps {
|
|
11
11
|
onMount?: (el: HTMLElement) => void;
|
|
12
|
-
onUnmount?: (el: HTMLElement) => void;
|
|
12
|
+
onUnmount?: (el: HTMLElement, removeTree: boolean) => void;
|
|
13
13
|
}
|
|
14
14
|
export declare function Lifecycle({ onMount, onUnmount }: LifecycleProps): Renderable;
|
package/components/Lifecycle.js
CHANGED
package/components/NotEmpty.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/** @jsxImportSource .. */
|
|
2
2
|
import { type Signal } from '../prop';
|
|
3
|
-
import { type AnyKey } from './OneOf';
|
|
4
3
|
import { type JSX } from '../jsx-runtime';
|
|
5
4
|
export interface NotEmptyProps<T> {
|
|
6
5
|
on: Signal<T>;
|
|
7
6
|
whenEmpty?: JSX.DOMNode;
|
|
8
7
|
display: JSX.DOMNode;
|
|
9
8
|
}
|
|
10
|
-
export declare function NotEmpty<T extends unknown[] | Record<
|
|
9
|
+
export declare function NotEmpty<T extends unknown[] | Record<any, unknown>>({ on, display, whenEmpty }: NotEmptyProps<T>): JSX.DOMNode;
|
package/components/OnRemove.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { type Clear } from '../clean';
|
|
2
|
-
import {
|
|
3
|
-
export declare class OnRemoveImpl implements Renderable {
|
|
4
|
-
private readonly clear;
|
|
5
|
-
constructor(clear: Clear);
|
|
6
|
-
readonly appendTo: () => Clear;
|
|
7
|
-
}
|
|
2
|
+
import { LifecycleImpl } from './Lifecycle';
|
|
8
3
|
export interface OnRemoveProps {
|
|
9
4
|
clear: Clear;
|
|
10
5
|
}
|
|
11
|
-
export declare function OnRemove(props: OnRemoveProps):
|
|
6
|
+
export declare function OnRemove(props: OnRemoveProps): LifecycleImpl;
|
package/components/OnRemove.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
clear;
|
|
3
|
-
constructor(clear) {
|
|
4
|
-
this.clear = clear;
|
|
5
|
-
}
|
|
6
|
-
appendTo = () => {
|
|
7
|
-
return (removeTree) => {
|
|
8
|
-
this.clear(removeTree);
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
}
|
|
1
|
+
import { LifecycleImpl } from './Lifecycle';
|
|
12
2
|
export function OnRemove(props) {
|
|
13
|
-
return new
|
|
3
|
+
return new LifecycleImpl(() => { }, (_, removeTree) => props.clear(removeTree));
|
|
14
4
|
}
|
package/components/OneOf.d.ts
CHANGED
|
@@ -3,18 +3,60 @@ import { type Clear } from '../clean';
|
|
|
3
3
|
import { type DOMContext } from '../dom-context';
|
|
4
4
|
import { type Renderable } from '../renderable';
|
|
5
5
|
import { type JSX } from '../jsx';
|
|
6
|
-
export
|
|
7
|
-
export declare class OneOfImpl<T extends [AnyKey, unknown]> implements Renderable {
|
|
6
|
+
export declare class OneOfImpl<T extends Record<string, unknown>> implements Renderable {
|
|
8
7
|
private readonly match;
|
|
9
8
|
private readonly cases;
|
|
10
9
|
constructor(match: Signal<T>, cases: {
|
|
11
|
-
[KK in T
|
|
10
|
+
[KK in keyof T]: (value: Signal<T[KK]>) => JSX.DOMNode;
|
|
12
11
|
});
|
|
13
12
|
readonly appendTo: (ctx: DOMContext) => Clear;
|
|
14
13
|
}
|
|
15
|
-
export type OneOfProps<T extends
|
|
14
|
+
export type OneOfProps<T extends Record<string, unknown>> = {
|
|
16
15
|
match: Signal<T>;
|
|
17
16
|
} & {
|
|
18
|
-
[KK in T
|
|
17
|
+
[KK in keyof T]: (value: Signal<T[KK]>) => JSX.DOMNode;
|
|
19
18
|
};
|
|
20
|
-
export declare function OneOf<T extends
|
|
19
|
+
export declare function OneOf<T extends Record<string, unknown>>(props: OneOfProps<T>): JSX.DOMNode;
|
|
20
|
+
export type OneOfLiteralProps<K extends string> = {
|
|
21
|
+
match: Signal<K>;
|
|
22
|
+
} & {
|
|
23
|
+
[KK in K]: JSX.DOMNode;
|
|
24
|
+
};
|
|
25
|
+
export declare function OneOfLiteral<K extends string>(props: OneOfLiteralProps<K>): JSX.DOMNode;
|
|
26
|
+
export type OneOfUnionProps<T extends {
|
|
27
|
+
[_ in K]: string;
|
|
28
|
+
}, K extends string> = {
|
|
29
|
+
match: Signal<T>;
|
|
30
|
+
using: K;
|
|
31
|
+
} & {
|
|
32
|
+
[KK in T[K]]: (value: Signal<T extends {
|
|
33
|
+
[_ in K]: KK;
|
|
34
|
+
} ? T : never>) => JSX.DOMNode;
|
|
35
|
+
};
|
|
36
|
+
export declare function OneOfUnion<T extends {
|
|
37
|
+
[_ in K]: string;
|
|
38
|
+
}, K extends string>(props: OneOfUnionProps<T, K>): JSX.DOMNode;
|
|
39
|
+
export type OneOfUnionTypeProps<T extends {
|
|
40
|
+
[_ in "type"]: string;
|
|
41
|
+
}> = {
|
|
42
|
+
match: Signal<T>;
|
|
43
|
+
} & {
|
|
44
|
+
[KK in T["type"]]: (value: Signal<T extends {
|
|
45
|
+
[_ in "type"]: KK;
|
|
46
|
+
} ? T : never>) => JSX.DOMNode;
|
|
47
|
+
};
|
|
48
|
+
export declare function OneOfUnionType<T extends {
|
|
49
|
+
type: string;
|
|
50
|
+
}>(props: OneOfUnionTypeProps<T>): JSX.DOMNode;
|
|
51
|
+
export type OneOfUnionKindProps<T extends {
|
|
52
|
+
[_ in "kind"]: string;
|
|
53
|
+
}> = {
|
|
54
|
+
match: Signal<T>;
|
|
55
|
+
} & {
|
|
56
|
+
[KK in T["kind"]]: (value: Signal<T extends {
|
|
57
|
+
[_ in "kind"]: KK;
|
|
58
|
+
} ? T : never>) => JSX.DOMNode;
|
|
59
|
+
};
|
|
60
|
+
export declare function OneOfUnionKind<T extends {
|
|
61
|
+
kind: string;
|
|
62
|
+
}>(props: OneOfUnionKindProps<T>): JSX.DOMNode;
|
package/components/OneOf.js
CHANGED
|
@@ -9,16 +9,17 @@ export class OneOfImpl {
|
|
|
9
9
|
}
|
|
10
10
|
appendTo = (ctx) => {
|
|
11
11
|
const pair = this.match.get();
|
|
12
|
-
let key = pair[0];
|
|
13
|
-
const value = pair[
|
|
14
|
-
const stableCtx = ctx.makeReference();
|
|
12
|
+
let key = Object.keys(pair)[0];
|
|
13
|
+
const value = pair[key];
|
|
15
14
|
let prop = new Prop(value);
|
|
16
|
-
let newCtx =
|
|
15
|
+
let newCtx = ctx.makeReference();
|
|
17
16
|
let clear = makeRenderable(this.cases[key](prop)).appendTo(newCtx);
|
|
18
|
-
const cancel = this.match.subscribe((
|
|
17
|
+
const cancel = this.match.subscribe((newPair) => {
|
|
18
|
+
const newKey = Object.keys(newPair)[0];
|
|
19
|
+
const newValue = newPair[newKey];
|
|
19
20
|
if (newKey !== key) {
|
|
20
21
|
newCtx.requestClear(true, () => {
|
|
21
|
-
newCtx =
|
|
22
|
+
newCtx = newCtx.makeReference();
|
|
22
23
|
key = newKey;
|
|
23
24
|
prop.clean();
|
|
24
25
|
prop = new Prop(newValue);
|
|
@@ -32,14 +33,33 @@ export class OneOfImpl {
|
|
|
32
33
|
});
|
|
33
34
|
return (removeTree) => {
|
|
34
35
|
newCtx.requestClear(removeTree, () => {
|
|
36
|
+
clear(removeTree);
|
|
35
37
|
cancel();
|
|
36
38
|
prop.clean();
|
|
37
|
-
stableCtx.requestClear(removeTree, () => { });
|
|
38
39
|
});
|
|
39
40
|
};
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
|
-
// <OneOf match={counter.map(v => v % 2 == 0 ?
|
|
43
|
+
// <OneOf match={counter.map(v => v % 2 == 0 ? {1: "odd"} : {2: "even"})} 1={t => <b>{t}</b>} 2={t => <i>{t}</i>} /
|
|
43
44
|
export function OneOf(props) {
|
|
44
45
|
return new OneOfImpl(props.match, props);
|
|
45
46
|
}
|
|
47
|
+
export function OneOfLiteral(props) {
|
|
48
|
+
const { match, ...cases } = props;
|
|
49
|
+
const keys = Object.keys(cases);
|
|
50
|
+
const obj = keys.reduce((acc, k) => {
|
|
51
|
+
acc[k] = () => cases[k];
|
|
52
|
+
return acc;
|
|
53
|
+
}, {});
|
|
54
|
+
return new OneOfImpl(match.map(k => ({ [k]: null })), obj);
|
|
55
|
+
}
|
|
56
|
+
export function OneOfUnion(props) {
|
|
57
|
+
const { match, using, ...cases } = props;
|
|
58
|
+
return new OneOfImpl(match.map(t => ({ [t[using]]: t })), cases);
|
|
59
|
+
}
|
|
60
|
+
export function OneOfUnionType(props) {
|
|
61
|
+
return OneOfUnion({ ...props, using: "type" });
|
|
62
|
+
}
|
|
63
|
+
export function OneOfUnionKind(props) {
|
|
64
|
+
return OneOfUnion({ ...props, using: "kind" });
|
|
65
|
+
}
|
package/components/Repeat.d.ts
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Signal } from '../prop';
|
|
2
2
|
import { type Clear } from '../clean';
|
|
3
3
|
import { type DOMContext } from '../dom-context';
|
|
4
4
|
import { type Renderable } from '../renderable';
|
|
5
|
+
import { JSX } from '../jsx';
|
|
6
|
+
export interface SeparatorProps {
|
|
7
|
+
first: boolean;
|
|
8
|
+
last: boolean;
|
|
9
|
+
index: number;
|
|
10
|
+
}
|
|
5
11
|
export declare class RepeatImpl implements Renderable {
|
|
6
12
|
private readonly times;
|
|
7
13
|
private readonly children;
|
|
8
|
-
|
|
14
|
+
private readonly separator?;
|
|
15
|
+
constructor(times: Signal<number>, children: (index: number) => JSX.DOMNode, separator?: ((sep: Signal<SeparatorProps>) => JSX.DOMNode) | undefined);
|
|
9
16
|
readonly appendTo: (ctx: DOMContext) => Clear;
|
|
17
|
+
readonly appendToWithoutSeparator: (ctx: DOMContext) => Clear;
|
|
18
|
+
readonly appendToWithSeparator: (ctx: DOMContext, separator: (sep: Signal<SeparatorProps>) => JSX.DOMNode) => Clear;
|
|
10
19
|
}
|
|
11
20
|
export interface RepeatProps {
|
|
12
21
|
times: Signal<number>;
|
|
13
|
-
children?: (index: number) =>
|
|
22
|
+
children?: (index: number) => JSX.DOMNode;
|
|
23
|
+
separator?: (sep: Signal<SeparatorProps>) => JSX.DOMNode;
|
|
14
24
|
}
|
|
15
25
|
export declare function Repeat(props: RepeatProps): Renderable;
|
|
26
|
+
export declare function conjuctions(other: JSX.DOMNode, lastConjunction?: JSX.DOMNode, firstConjunction?: JSX.DOMNode): (sep: Signal<SeparatorProps>) => JSX.DOMNode;
|
package/components/Repeat.js
CHANGED
|
@@ -1,33 +1,118 @@
|
|
|
1
|
+
import { Prop } from '../prop';
|
|
1
2
|
import { Fragment } from './Fragment';
|
|
3
|
+
import { makeRenderable } from '../jsx-runtime';
|
|
2
4
|
export class RepeatImpl {
|
|
3
5
|
times;
|
|
4
6
|
children;
|
|
5
|
-
|
|
7
|
+
separator;
|
|
8
|
+
constructor(times, children, separator) {
|
|
6
9
|
this.times = times;
|
|
7
10
|
this.children = children;
|
|
11
|
+
this.separator = separator;
|
|
8
12
|
}
|
|
9
13
|
appendTo = (ctx) => {
|
|
14
|
+
if (!this.separator) {
|
|
15
|
+
return this.appendToWithoutSeparator(ctx);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return this.appendToWithSeparator(ctx, this.separator);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
appendToWithoutSeparator = (ctx) => {
|
|
22
|
+
const newCtx = ctx.makeReference();
|
|
23
|
+
const count = this.times.get();
|
|
24
|
+
const clears = new Array(count);
|
|
25
|
+
for (let i = 0; i < count; i++) {
|
|
26
|
+
clears[i] = makeRenderable(this.children(i)).appendTo(newCtx);
|
|
27
|
+
}
|
|
28
|
+
const cancel = this.times.subscribe((newCount) => {
|
|
29
|
+
while (newCount < clears.length) {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
31
|
+
clears.pop()(true);
|
|
32
|
+
}
|
|
33
|
+
for (let i = clears.length; i < newCount; i++) {
|
|
34
|
+
clears[i] = makeRenderable(this.children(i)).appendTo(newCtx);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return (removeTree) => {
|
|
38
|
+
newCtx.requestClear(removeTree, () => {
|
|
39
|
+
cancel();
|
|
40
|
+
clears.forEach(clear => { clear(removeTree); });
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
appendToWithSeparator = (ctx, separator) => {
|
|
10
45
|
const newCtx = ctx.makeReference();
|
|
11
46
|
const count = this.times.get();
|
|
47
|
+
const separatorProps = new Array(Math.max(0, count - 1));
|
|
48
|
+
const separatorClears = new Array(Math.max(0, count - 1));
|
|
12
49
|
const clears = new Array(count);
|
|
13
50
|
for (let i = 0; i < count; i++) {
|
|
14
|
-
clears[i] = this.children(i).appendTo(newCtx);
|
|
51
|
+
clears[i] = makeRenderable(this.children(i)).appendTo(newCtx);
|
|
52
|
+
if (i < count - 1) {
|
|
53
|
+
separatorProps[i] = Prop.of({
|
|
54
|
+
first: i === 0,
|
|
55
|
+
last: i === count - 2,
|
|
56
|
+
index: i
|
|
57
|
+
});
|
|
58
|
+
separatorClears[i] = makeRenderable(separator(separatorProps[i])).appendTo(newCtx);
|
|
59
|
+
}
|
|
15
60
|
}
|
|
16
61
|
const cancel = this.times.subscribe((newCount) => {
|
|
17
62
|
while (newCount < clears.length) {
|
|
18
63
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
19
64
|
clears.pop()(true);
|
|
65
|
+
if (separatorClears.length > 0) {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
67
|
+
separatorClears.pop()(true);
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
69
|
+
separatorProps.pop().clean();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (let i = 0; i < separatorProps.length; i++) {
|
|
73
|
+
separatorProps[i].set({
|
|
74
|
+
first: i === 0,
|
|
75
|
+
last: i === newCount - 2,
|
|
76
|
+
index: i
|
|
77
|
+
});
|
|
20
78
|
}
|
|
21
79
|
for (let i = clears.length; i < newCount; i++) {
|
|
22
|
-
clears[i] = this.children(i).appendTo(newCtx);
|
|
80
|
+
clears[i] = makeRenderable(this.children(i)).appendTo(newCtx);
|
|
81
|
+
if (i < newCount - 1) {
|
|
82
|
+
separatorProps[i] = Prop.of({
|
|
83
|
+
first: i === 0,
|
|
84
|
+
last: i === newCount - 2,
|
|
85
|
+
index: i
|
|
86
|
+
});
|
|
87
|
+
separatorClears[i] = makeRenderable(separator(separatorProps[i])).appendTo(newCtx);
|
|
88
|
+
}
|
|
23
89
|
}
|
|
24
90
|
});
|
|
25
91
|
return (removeTree) => {
|
|
26
92
|
newCtx.requestClear(removeTree, () => {
|
|
27
93
|
cancel();
|
|
28
94
|
clears.forEach(clear => { clear(removeTree); });
|
|
95
|
+
separatorClears.forEach(clear => { clear(removeTree); });
|
|
96
|
+
separatorProps.forEach(signal => { signal.clean(); });
|
|
29
97
|
});
|
|
30
98
|
};
|
|
31
99
|
};
|
|
32
100
|
}
|
|
33
|
-
export function Repeat(props) {
|
|
101
|
+
export function Repeat(props) {
|
|
102
|
+
return new RepeatImpl(props.times, props.children ?? (() => Fragment({ children: [] })), props.separator);
|
|
103
|
+
}
|
|
104
|
+
export function conjuctions(other, lastConjunction, firstConjunction) {
|
|
105
|
+
return (sep) => {
|
|
106
|
+
return sep.map(({ first, last }) => {
|
|
107
|
+
if (last) {
|
|
108
|
+
return lastConjunction ?? other;
|
|
109
|
+
}
|
|
110
|
+
else if (first) {
|
|
111
|
+
return firstConjunction ?? other;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return other;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -23,8 +23,15 @@ export interface Animatable {
|
|
|
23
23
|
marginRight?: number;
|
|
24
24
|
fontSize?: number;
|
|
25
25
|
letterSpacing?: number;
|
|
26
|
+
color?: string;
|
|
27
|
+
backgroundColor?: string;
|
|
28
|
+
borderColor?: string;
|
|
26
29
|
borderWidth?: number;
|
|
27
30
|
borderRadius?: number;
|
|
31
|
+
boxShadow?: string;
|
|
32
|
+
textShadow?: string;
|
|
33
|
+
outlineWidth?: number;
|
|
34
|
+
outlineColor?: string;
|
|
28
35
|
translateX?: number;
|
|
29
36
|
translateY?: number;
|
|
30
37
|
translateZ?: number;
|
|
@@ -45,6 +52,19 @@ export interface Animatable {
|
|
|
45
52
|
contrast?: number;
|
|
46
53
|
blur?: number;
|
|
47
54
|
}
|
|
55
|
+
export type ColorChannels = [number, number, number, number, 'rgba' | 'hex' | 'hsla'];
|
|
56
|
+
export declare function parseColorChannels(color: string): ColorChannels;
|
|
57
|
+
export interface BoxShadow {
|
|
58
|
+
inset: boolean;
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
blur: number;
|
|
62
|
+
spread: number;
|
|
63
|
+
color: string;
|
|
64
|
+
}
|
|
65
|
+
export declare function colorChannelsToString(channels: ColorChannels): string;
|
|
66
|
+
export declare function interpolateColor(startColor: string, endColor: string): (t: number) => string;
|
|
67
|
+
export declare function interpolateShadow(startShadow: string, endShadow: string): (t: number) => string;
|
|
48
68
|
export declare function getComputedAnimatableProp(styles: CSSStyleDeclaration, key: keyof Animatable): Animatable[typeof key];
|
|
49
69
|
export declare function getComputedAnimatable(el: HTMLElement, styles: Animatable): Animatable;
|
|
50
70
|
export declare function applyAnimatableProp(el: HTMLElement, key: keyof Animatable, value: Animatable[typeof key]): void;
|
package/components/animatable.js
CHANGED
|
@@ -1,3 +1,104 @@
|
|
|
1
|
+
export function parseColorChannels(color) {
|
|
2
|
+
let match = color.match(/rgba?\((\d+), (\d+), (\d+)(, (\d+))?\)/);
|
|
3
|
+
if (match) {
|
|
4
|
+
return [
|
|
5
|
+
Number(match[1]),
|
|
6
|
+
Number(match[2]),
|
|
7
|
+
Number(match[3]),
|
|
8
|
+
match[4] ? Number(match[5]) : 1,
|
|
9
|
+
'rgba'
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
match = color.match(/#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/);
|
|
14
|
+
if (match) {
|
|
15
|
+
return [
|
|
16
|
+
parseInt(match[1], 16),
|
|
17
|
+
parseInt(match[2], 16),
|
|
18
|
+
parseInt(match[3], 16),
|
|
19
|
+
1,
|
|
20
|
+
'hex'
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
match = color.match(/hsla?\((\d+), (\d+)%?, (\d+)%?(, (\d+))?\)/);
|
|
25
|
+
if (match) {
|
|
26
|
+
return [
|
|
27
|
+
Number(match[1]),
|
|
28
|
+
Number(match[2]),
|
|
29
|
+
Number(match[3]),
|
|
30
|
+
match[4] ? Number(match[5]) : 1,
|
|
31
|
+
'hsla'
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return [0, 0, 0, 1, 'rgba'];
|
|
37
|
+
}
|
|
38
|
+
function parseBoxShadow(cssString) {
|
|
39
|
+
const boxShadowRegex = /^(inset\s)?(-?\d+)([a-zA-Z]*)(\s+)(-?\d+)([a-zA-Z]*)(?:\s+(-?\d+)([a-zA-Z]*))?(?:\s+(-?\d+)([a-zA-Z]*))?(?:\s+(-?\d+)([a-zA-Z]*))?(?:\s+)([a-zA-Z0-9(),.]+)$/i;
|
|
40
|
+
const match = cssString.match(boxShadowRegex);
|
|
41
|
+
if (!match) {
|
|
42
|
+
return {
|
|
43
|
+
inset: false,
|
|
44
|
+
x: 0,
|
|
45
|
+
y: 0,
|
|
46
|
+
blur: 0,
|
|
47
|
+
spread: 0,
|
|
48
|
+
color: 'rgba(0, 0, 0, 0)'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const [, inset, x, , , y, , blur, , spread, , color] = match;
|
|
52
|
+
const parsedBlur = blur ? parseInt(blur, 10) : 0;
|
|
53
|
+
const parsedSpread = spread ? parseInt(spread, 10) : 0;
|
|
54
|
+
return {
|
|
55
|
+
inset: !!inset,
|
|
56
|
+
x: parseInt(x, 10),
|
|
57
|
+
y: parseInt(y, 10),
|
|
58
|
+
blur: parsedBlur,
|
|
59
|
+
spread: parsedSpread,
|
|
60
|
+
color
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function boxShadowToString(shadow) {
|
|
64
|
+
const { inset, x, y, blur, spread, color } = shadow;
|
|
65
|
+
return `${inset ? 'inset ' : ''}${x}px ${y}px ${blur}px ${spread}px ${color}`;
|
|
66
|
+
}
|
|
67
|
+
export function colorChannelsToString(channels) {
|
|
68
|
+
if (channels[4] === 'rgba') {
|
|
69
|
+
return `rgba(${channels[0]}, ${channels[1]}, ${channels[2]}, ${channels[3]})`;
|
|
70
|
+
}
|
|
71
|
+
else if (channels[4] === 'hex') {
|
|
72
|
+
return `#${channels[0].toString(16).padStart(2, '0')}${channels[1].toString(16).padStart(2, '0')}${channels[2].toString(16).padStart(2, '0')}`;
|
|
73
|
+
}
|
|
74
|
+
else if (channels[4] === 'hsla') {
|
|
75
|
+
return `hsla(${channels[0]}, ${channels[1]}%, ${channels[2]}%, ${channels[3]})`;
|
|
76
|
+
}
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
export function interpolateColor(startColor, endColor) {
|
|
80
|
+
const [startR, startG, startB, startA, startType] = parseColorChannels(startColor);
|
|
81
|
+
const [endR, endG, endB, endA, endType] = parseColorChannels(endColor);
|
|
82
|
+
return (t) => {
|
|
83
|
+
const r = startR + (endR - startR) * t;
|
|
84
|
+
const g = startG + (endG - startG) * t;
|
|
85
|
+
const b = startB + (endB - startB) * t;
|
|
86
|
+
const a = startA + (endA - startA) * t;
|
|
87
|
+
return colorChannelsToString([r, g, b, a, startType]);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export function interpolateShadow(startShadow, endShadow) {
|
|
91
|
+
const start = parseBoxShadow(startShadow);
|
|
92
|
+
const end = parseBoxShadow(endShadow);
|
|
93
|
+
return (t) => {
|
|
94
|
+
const x = start.x + (end.x - start.x) * t;
|
|
95
|
+
const y = start.y + (end.y - start.y) * t;
|
|
96
|
+
const blur = start.blur + (end.blur - start.blur) * t;
|
|
97
|
+
const spread = start.spread + (end.spread - start.spread) * t;
|
|
98
|
+
const color = getColorInterpolation(start.color, end.color)(t);
|
|
99
|
+
return boxShadowToString({ inset: start.inset, x, y, blur, spread, color });
|
|
100
|
+
};
|
|
101
|
+
}
|
|
1
102
|
export function getComputedAnimatableProp(styles, key) {
|
|
2
103
|
if (key === 'translateX') {
|
|
3
104
|
return new WebKitCSSMatrix(styles.transform).m41;
|
|
@@ -131,10 +232,35 @@ export function applyAnimatableProp(el, key, value) {
|
|
|
131
232
|
}
|
|
132
233
|
el.style.setProperty(key, String(value));
|
|
133
234
|
}
|
|
235
|
+
const interpolationCache = new Map();
|
|
236
|
+
function getInterpolate(from, to, type) {
|
|
237
|
+
if (interpolationCache.has(type + ":" + from + to)) {
|
|
238
|
+
return interpolationCache.get(from + to);
|
|
239
|
+
}
|
|
240
|
+
const f = interpolateColor(from, to);
|
|
241
|
+
interpolationCache.set(type + ":" + from + to, f);
|
|
242
|
+
return f;
|
|
243
|
+
}
|
|
244
|
+
function getColorInterpolation(from, to) {
|
|
245
|
+
return getInterpolate(from, to, 'c');
|
|
246
|
+
}
|
|
247
|
+
function getShadowInterpolation(from, to) {
|
|
248
|
+
return getInterpolate(from, to, 's');
|
|
249
|
+
}
|
|
134
250
|
export function applyInterpolatedAnimatableProp(el, key, from, to, progress) {
|
|
135
251
|
if (from != null && to != null) {
|
|
136
|
-
|
|
137
|
-
|
|
252
|
+
if (typeof from === 'number' && typeof to === 'number') {
|
|
253
|
+
const value = from + (to - from) * progress;
|
|
254
|
+
applyAnimatableProp(el, key, value);
|
|
255
|
+
}
|
|
256
|
+
else if (key === 'boxShadow' || key === 'textShadow') {
|
|
257
|
+
const value = getShadowInterpolation(from, to)(progress);
|
|
258
|
+
applyAnimatableProp(el, key, value);
|
|
259
|
+
}
|
|
260
|
+
else if (key === 'color' || key === 'backgroundColor' || key === 'borderColor' || key === 'outlineColor') {
|
|
261
|
+
const value = getColorInterpolation(from, to)(progress);
|
|
262
|
+
applyAnimatableProp(el, key, value);
|
|
263
|
+
}
|
|
138
264
|
}
|
|
139
265
|
}
|
|
140
266
|
export function applyInterpolatedAnimatable(el, from, to, progress) {
|
package/dom-context.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare class DOMContext {
|
|
|
33
33
|
private clear;
|
|
34
34
|
withProvider<T>(mark: ProviderMark<T>, provider: T): DOMContext;
|
|
35
35
|
getProvider<T>(mark: ProviderMark<T>): T;
|
|
36
|
+
getStyle(name: string): string | undefined | null;
|
|
36
37
|
setStyle(name: string, value: string | undefined | null): void;
|
|
37
38
|
createStyle(name: string, value: string | undefined | null): [(newValue: string) => void, Clear];
|
|
38
39
|
}
|
package/dom-context.js
CHANGED
|
@@ -235,6 +235,9 @@ export class DOMContext {
|
|
|
235
235
|
getProvider(mark) {
|
|
236
236
|
return this.providers[mark];
|
|
237
237
|
}
|
|
238
|
+
getStyle(name) {
|
|
239
|
+
return this.element.style.getPropertyValue(name);
|
|
240
|
+
}
|
|
238
241
|
setStyle(name, value) {
|
|
239
242
|
if (value == null) {
|
|
240
243
|
this.element.style.removeProperty(name);
|
package/index.d.ts
CHANGED
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
import type { JSX } from './jsx-runtime';
|
|
35
|
-
export { applyInterpolatedAnimatableProp, applyInterpolatedAnimatable, applyAnimatableProp, applyAnimatable, getComputedAnimatableProp, getComputedAnimatable, AttributeImpl, Attribute, BooleanAttributeImpl, BooleanAttribute, ClassNameImpl, ClassName, ConsumerImpl, Consumer, DOMContext, ElImpl, El, FadeIn, FadeInImpl, FadeOut, FadeOutImpl, For, FragmentImpl, Fragment, handleTextInput, handleAnchorClick, HiddenWhenEmptyImpl, HiddenWhenEmpty, If, InnerHTMLImpl, InnerHTML, isEmptyElement, Lifecycle, LifecycleImpl, makeProviderMark, MatchImpl, Match, NotEmpty, OnImpl, On, OnRemoveImpl, OnRemove, OneOfImpl, OneOf, PortalImpl, Portal, Prop, PropertyImpl, Property, ProviderImpl, Provider, render, RepeatImpl, Repeat, ShowImpl, Show, Signal, TextImpl, Text, TextContentImpl, TextContent, Unless, When };
|
|
36
|
-
export type { AttributeProps, BooleanAttributeProps, ClassNameProps, Clean, Clear, ConsumerProps, ElProps, FadeInProps, FadeOutProps, ForProps, InnerHTMLProps, IfProps, JSX, LifecycleProps, MatchProps, NotEmptyProps, OnProps, OnRemoveProps, OneOfProps, PortalProps, PropertyProps, ProviderMark, ProviderProps, Renderable, RepeatProps, ShowProps, TextProps, TextContentProps, Animatable, WhenProps };
|
|
1
|
+
export { type Clear, type Clean } from './clean';
|
|
2
|
+
export { makeProviderMark, DOMContext, type ProviderMark } from './dom-context';
|
|
3
|
+
export { Prop, Signal } from './prop';
|
|
4
|
+
export { render } from './render';
|
|
5
|
+
export { type Renderable } from './renderable';
|
|
6
|
+
export { isEmptyElement } from './helpers/is-empty-element';
|
|
7
|
+
export { handleTextInput } from './helpers/handle-text-input';
|
|
8
|
+
export { handleAnchorClick } from './helpers/handle-anchor-click';
|
|
9
|
+
export { type Animatable, applyInterpolatedAnimatableProp, applyInterpolatedAnimatable, applyAnimatableProp, applyAnimatable, getComputedAnimatableProp, getComputedAnimatable } from './components/animatable';
|
|
10
|
+
export { AttributeImpl, Attribute, type AttributeProps } from './components/Attribute';
|
|
11
|
+
export { BooleanAttributeImpl, BooleanAttribute, type BooleanAttributeProps } from './components/BooleanAttribute';
|
|
12
|
+
export { ClassNameImpl, ClassName, type ClassNameProps } from './components/ClassName';
|
|
13
|
+
export { ConsumerImpl, Consumer, type ConsumerProps, ProviderImpl, Provider, type ProviderProps } from './components/Provider';
|
|
14
|
+
export { ElImpl, El, type ElProps } from './components/El';
|
|
15
|
+
export { FadeIn, FadeInImpl, type FadeInProps } from './components/FadeIn';
|
|
16
|
+
export { FadeOut, FadeOutImpl, type FadeOutProps } from './components/FadeOut';
|
|
17
|
+
export { For, type ForProps } from './components/For';
|
|
18
|
+
export { FragmentImpl, Fragment } from './components/Fragment';
|
|
19
|
+
export { HiddenWhenEmptyImpl, HiddenWhenEmpty } from './components/HiddenWhenEmpty';
|
|
20
|
+
export { If, type IfProps, Unless, When, type WhenProps } from './components/If';
|
|
21
|
+
export { InnerHTMLImpl, InnerHTML, type InnerHTMLProps } from './components/InnerHTML';
|
|
22
|
+
export { Lifecycle, LifecycleImpl, type LifecycleProps } from './components/Lifecycle';
|
|
23
|
+
export { NotEmpty, type NotEmptyProps } from './components/NotEmpty';
|
|
24
|
+
export { OnImpl, On, type OnProps } from './components/On';
|
|
25
|
+
export { OnRemove, type OnRemoveProps } from './components/OnRemove';
|
|
26
|
+
export { OneOfImpl, OneOf, type OneOfProps, OneOfLiteral, type OneOfLiteralProps, OneOfUnion, type OneOfUnionProps, OneOfUnionKind, type OneOfUnionKindProps, OneOfUnionType, type OneOfUnionTypeProps } from './components/OneOf';
|
|
27
|
+
export { PortalImpl, Portal, type PortalProps } from './components/Portal';
|
|
28
|
+
export { PropertyImpl, Property, type PropertyProps } from './components/Property';
|
|
29
|
+
export { RepeatImpl, Repeat, type RepeatProps, conjuctions } from './components/Repeat';
|
|
30
|
+
export { ShowImpl, Show, type ShowProps } from './components/Show';
|
|
31
|
+
export { TextImpl, Text, type TextProps } from './components/Text';
|
|
32
|
+
export { TextContentImpl, TextContent, type TextContentProps } from './components/TextContent';
|
|
33
|
+
export type { JSX } from './jsx-runtime';
|
package/index.js
CHANGED
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import { TextContentImpl, TextContent } from './components/TextContent';
|
|
32
|
-
export { applyInterpolatedAnimatableProp, applyInterpolatedAnimatable, applyAnimatableProp, applyAnimatable, getComputedAnimatableProp, getComputedAnimatable, AttributeImpl, Attribute, BooleanAttributeImpl, BooleanAttribute, ClassNameImpl, ClassName, ConsumerImpl, Consumer, DOMContext, ElImpl, El, FadeIn, FadeInImpl, FadeOut, FadeOutImpl, For, FragmentImpl, Fragment, handleTextInput, handleAnchorClick, HiddenWhenEmptyImpl, HiddenWhenEmpty, If, InnerHTMLImpl, InnerHTML, isEmptyElement, Lifecycle, LifecycleImpl, makeProviderMark, MatchImpl, Match, NotEmpty, OnImpl, On, OnRemoveImpl, OnRemove, OneOfImpl, OneOf, PortalImpl, Portal, Prop, PropertyImpl, Property, ProviderImpl, Provider, render, RepeatImpl, Repeat, ShowImpl, Show, Signal, TextImpl, Text, TextContentImpl, TextContent, Unless, When };
|
|
1
|
+
export { makeProviderMark, DOMContext } from './dom-context';
|
|
2
|
+
export { Prop, Signal } from './prop';
|
|
3
|
+
export { render } from './render';
|
|
4
|
+
export { isEmptyElement } from './helpers/is-empty-element';
|
|
5
|
+
export { handleTextInput } from './helpers/handle-text-input';
|
|
6
|
+
export { handleAnchorClick } from './helpers/handle-anchor-click';
|
|
7
|
+
export { applyInterpolatedAnimatableProp, applyInterpolatedAnimatable, applyAnimatableProp, applyAnimatable, getComputedAnimatableProp, getComputedAnimatable } from './components/animatable';
|
|
8
|
+
export { AttributeImpl, Attribute } from './components/Attribute';
|
|
9
|
+
export { BooleanAttributeImpl, BooleanAttribute } from './components/BooleanAttribute';
|
|
10
|
+
export { ClassNameImpl, ClassName } from './components/ClassName';
|
|
11
|
+
export { ConsumerImpl, Consumer, ProviderImpl, Provider } from './components/Provider';
|
|
12
|
+
export { ElImpl, El } from './components/El';
|
|
13
|
+
export { FadeIn, FadeInImpl } from './components/FadeIn';
|
|
14
|
+
export { FadeOut, FadeOutImpl } from './components/FadeOut';
|
|
15
|
+
export { For } from './components/For';
|
|
16
|
+
export { FragmentImpl, Fragment } from './components/Fragment';
|
|
17
|
+
export { HiddenWhenEmptyImpl, HiddenWhenEmpty } from './components/HiddenWhenEmpty';
|
|
18
|
+
export { If, Unless, When } from './components/If';
|
|
19
|
+
export { InnerHTMLImpl, InnerHTML } from './components/InnerHTML';
|
|
20
|
+
export { Lifecycle, LifecycleImpl } from './components/Lifecycle';
|
|
21
|
+
export { NotEmpty } from './components/NotEmpty';
|
|
22
|
+
export { OnImpl, On } from './components/On';
|
|
23
|
+
export { OnRemove } from './components/OnRemove';
|
|
24
|
+
export { OneOfImpl, OneOf, OneOfLiteral, OneOfUnion, OneOfUnionKind, OneOfUnionType } from './components/OneOf';
|
|
25
|
+
export { PortalImpl, Portal } from './components/Portal';
|
|
26
|
+
export { PropertyImpl, Property } from './components/Property';
|
|
27
|
+
export { RepeatImpl, Repeat, conjuctions } from './components/Repeat';
|
|
28
|
+
export { ShowImpl, Show } from './components/Show';
|
|
29
|
+
export { TextImpl, Text } from './components/Text';
|
|
30
|
+
export { TextContentImpl, TextContent } from './components/TextContent';
|
package/package.json
CHANGED
package/prop.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare class Signal<T> {
|
|
|
29
29
|
readonly feed: (prop: Prop<T>) => Prop<T>;
|
|
30
30
|
readonly deriveProp: () => Prop<T>;
|
|
31
31
|
readonly clean: () => void;
|
|
32
|
+
readonly count: () => Signal<number>;
|
|
33
|
+
readonly animate: (duration: number, interpolate: (start: T, end: T, delta: number) => T, initialValue?: T | null, easing?: (t: number) => number) => Signal<T>;
|
|
32
34
|
}
|
|
33
35
|
export declare class Prop<T> extends Signal<T> {
|
|
34
36
|
static isProp<T = unknown>(x: unknown): x is Prop<T>;
|
package/prop.js
CHANGED
|
@@ -137,6 +137,47 @@ export class Signal {
|
|
|
137
137
|
clean = () => {
|
|
138
138
|
this._listeners.length = 0;
|
|
139
139
|
};
|
|
140
|
+
count = () => {
|
|
141
|
+
let count = 0;
|
|
142
|
+
return this.map(() => ++count);
|
|
143
|
+
};
|
|
144
|
+
animate = (duration, interpolate, initialValue = null, easing = t => t) => {
|
|
145
|
+
let startValue = initialValue ?? this.get();
|
|
146
|
+
let endValue = this.get();
|
|
147
|
+
const prop = new Prop(startValue);
|
|
148
|
+
let startTime = 0;
|
|
149
|
+
let endTime = 0;
|
|
150
|
+
let animationFrame = null;
|
|
151
|
+
const animate = (time) => {
|
|
152
|
+
if (this._listeners.length === 0) {
|
|
153
|
+
animationFrame = null;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (time < endTime) {
|
|
157
|
+
const delta = (time - startTime) / (endTime - startTime);
|
|
158
|
+
prop.set(interpolate(startValue, endValue, easing(delta)));
|
|
159
|
+
animationFrame = requestAnimationFrame(animate);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
prop.set(endValue);
|
|
163
|
+
animationFrame = null;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
this.subscribe(value => {
|
|
167
|
+
if (animationFrame != null)
|
|
168
|
+
cancelAnimationFrame(animationFrame);
|
|
169
|
+
if (this._listeners.length === 0) {
|
|
170
|
+
animationFrame = null;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
startValue = prop.get();
|
|
174
|
+
endValue = value;
|
|
175
|
+
startTime = performance.now();
|
|
176
|
+
endTime = startTime + duration;
|
|
177
|
+
animationFrame = requestAnimationFrame(animate);
|
|
178
|
+
});
|
|
179
|
+
return prop;
|
|
180
|
+
};
|
|
140
181
|
}
|
|
141
182
|
export class Prop extends Signal {
|
|
142
183
|
static isProp(x) {
|