@sigil-dev/runtime 0.9.2 → 0.9.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/README.md +140 -140
- package/async-boundary.ts +25 -25
- package/boundary.ts +44 -44
- package/easing.ts +66 -66
- package/index.test.ts +1618 -1618
- package/index.ts +655 -655
- package/jsr.json +8 -8
- package/package.json +1 -1
- package/reactivity/map.ts +98 -98
- package/reactivity/set.ts +74 -74
- package/test-preload.ts +9 -9
- package/tsconfig.json +30 -30
package/README.md
CHANGED
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
# @sigil-dev/runtime
|
|
2
|
-
|
|
3
|
-
Signals-based reactivity for the DOM using direct mutations.
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
bun add @sigil-dev/runtime
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
## What it is
|
|
10
|
-
|
|
11
|
-
A small reactive primitive library. Signals track dependencies automatically — when a value changes, only the effects that read it re-run.
|
|
12
|
-
Objects and arrays use Proxy for deep reactivity without any special syntax.
|
|
13
|
-
|
|
14
|
-
Inspired by Solid's reactive model.
|
|
15
|
-
|
|
16
|
-
## Primitives
|
|
17
|
-
|
|
18
|
-
### `createSignal`
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
import { createSignal } from "@sigil-dev/runtime";
|
|
22
|
-
|
|
23
|
-
const count = createSignal(0);
|
|
24
|
-
|
|
25
|
-
count() // read — 0
|
|
26
|
-
count.set(5) // write
|
|
27
|
-
count.peek() // read without tracking
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Objects and arrays are deeply reactive via Proxy and you mutate them directly:
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
const user = createSignal({ name: "Rei", score: 0 });
|
|
34
|
-
|
|
35
|
-
user().score++ // triggers effects that read score
|
|
36
|
-
user().name = "Asuka" // triggers effects that read name
|
|
37
|
-
|
|
38
|
-
user.set({ name: "Misato", score: 100 }) // replace entire object
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### `createEffect`
|
|
42
|
-
|
|
43
|
-
Runs immediately, re-runs when any signal it read changes. Returns a dispose function.
|
|
44
|
-
|
|
45
|
-
```typescript
|
|
46
|
-
import { createEffect } from "@sigil-dev/runtime";
|
|
47
|
-
|
|
48
|
-
const dispose = createEffect(() => {
|
|
49
|
-
document.title = `Score: ${user().score}`;
|
|
50
|
-
return () => console.log("cleanup before rerun");
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
dispose(); // stop tracking
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Dependencies are tracked automatically. If a signal is conditionally read, the dependency is updated on each run — no stale subscriptions.
|
|
57
|
-
|
|
58
|
-
### `createMemo`
|
|
59
|
-
|
|
60
|
-
A derived signal. Cached until its dependencies change.
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
63
|
-
import { createMemo } from "@sigil-dev/runtime";
|
|
64
|
-
|
|
65
|
-
const fullName = createMemo(() => `${first()} ${last()}`);
|
|
66
|
-
fullName() // read like any other signal
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### `batch`
|
|
70
|
-
|
|
71
|
-
Defer effect notifications until a block completes. Useful for multiple related writes.
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { batch } from "@sigil-dev/runtime";
|
|
75
|
-
|
|
76
|
-
batch(() => {
|
|
77
|
-
x.set(1);
|
|
78
|
-
y.set(2);
|
|
79
|
-
// effects fire once, not twice
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### `withEffectScope`
|
|
84
|
-
|
|
85
|
-
Group effects so they can all be torn down at once. Essential for component lifecycle.
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { withEffectScope } from "@sigil-dev/runtime";
|
|
89
|
-
|
|
90
|
-
const dispose = withEffectScope(() => {
|
|
91
|
-
createEffect(() => console.log(x()));
|
|
92
|
-
createEffect(() => console.log(y()));
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
dispose(); // kills both
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Scopes nest correctly. Inner dispose does not affect outer scope.
|
|
99
|
-
|
|
100
|
-
### Context
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { createContext, setContext, getContext } from "@sigil-dev/runtime";
|
|
104
|
-
|
|
105
|
-
const ThemeKey = createContext<"light" | "dark">();
|
|
106
|
-
|
|
107
|
-
setContext(ThemeKey, "dark");
|
|
108
|
-
getContext(ThemeKey); // "dark"
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Hydration utilities
|
|
112
|
-
> **NOTE:** You probably dont want to use this manually.
|
|
113
|
-
|
|
114
|
-
`claim`, `claimText`, `claimComment`, `reconcile`, `hydrateKeyedList` are used by the Sigil compiler for SSR hydration. Claim existing server-rendered DOM nodes instead of creating new ones.
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { claim, claimText, reconcile } from "@sigil-dev/runtime";
|
|
118
|
-
|
|
119
|
-
// claim an existing <div> from an SSR pool instead of createElement
|
|
120
|
-
const el = claim(nodes, "div", parent);
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Design
|
|
124
|
-
|
|
125
|
-
No virtual DOM. Effects write directly to DOM nodes. The update path is:
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
signal.set(newValue)
|
|
129
|
-
→ notify subscribers
|
|
130
|
-
→ effect re-runs
|
|
131
|
-
→ direct DOM mutation
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
If a signal changes, the effects that depend on it run synchronously (or are batched if inside `batch()`).
|
|
135
|
-
|
|
136
|
-
Deep reactivity on objects uses Proxy rather than explicit getter/setter pairs. This means you can pass a signal's value to any code that expects a plain object and mutations will still be tracked.
|
|
137
|
-
|
|
138
|
-
## Used by
|
|
139
|
-
|
|
140
|
-
`@sigil-dev/compiler` compiles `$state`, `$derived`, and `$effect` macros down to these primitives at build time. You can use this library directly if you want explicit control or are building outside the Sigil compiler pipeline.
|
|
1
|
+
# @sigil-dev/runtime
|
|
2
|
+
|
|
3
|
+
Signals-based reactivity for the DOM using direct mutations.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add @sigil-dev/runtime
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What it is
|
|
10
|
+
|
|
11
|
+
A small reactive primitive library. Signals track dependencies automatically — when a value changes, only the effects that read it re-run.
|
|
12
|
+
Objects and arrays use Proxy for deep reactivity without any special syntax.
|
|
13
|
+
|
|
14
|
+
Inspired by Solid's reactive model.
|
|
15
|
+
|
|
16
|
+
## Primitives
|
|
17
|
+
|
|
18
|
+
### `createSignal`
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { createSignal } from "@sigil-dev/runtime";
|
|
22
|
+
|
|
23
|
+
const count = createSignal(0);
|
|
24
|
+
|
|
25
|
+
count() // read — 0
|
|
26
|
+
count.set(5) // write
|
|
27
|
+
count.peek() // read without tracking
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Objects and arrays are deeply reactive via Proxy and you mutate them directly:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const user = createSignal({ name: "Rei", score: 0 });
|
|
34
|
+
|
|
35
|
+
user().score++ // triggers effects that read score
|
|
36
|
+
user().name = "Asuka" // triggers effects that read name
|
|
37
|
+
|
|
38
|
+
user.set({ name: "Misato", score: 100 }) // replace entire object
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `createEffect`
|
|
42
|
+
|
|
43
|
+
Runs immediately, re-runs when any signal it read changes. Returns a dispose function.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createEffect } from "@sigil-dev/runtime";
|
|
47
|
+
|
|
48
|
+
const dispose = createEffect(() => {
|
|
49
|
+
document.title = `Score: ${user().score}`;
|
|
50
|
+
return () => console.log("cleanup before rerun");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
dispose(); // stop tracking
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Dependencies are tracked automatically. If a signal is conditionally read, the dependency is updated on each run — no stale subscriptions.
|
|
57
|
+
|
|
58
|
+
### `createMemo`
|
|
59
|
+
|
|
60
|
+
A derived signal. Cached until its dependencies change.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { createMemo } from "@sigil-dev/runtime";
|
|
64
|
+
|
|
65
|
+
const fullName = createMemo(() => `${first()} ${last()}`);
|
|
66
|
+
fullName() // read like any other signal
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### `batch`
|
|
70
|
+
|
|
71
|
+
Defer effect notifications until a block completes. Useful for multiple related writes.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { batch } from "@sigil-dev/runtime";
|
|
75
|
+
|
|
76
|
+
batch(() => {
|
|
77
|
+
x.set(1);
|
|
78
|
+
y.set(2);
|
|
79
|
+
// effects fire once, not twice
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `withEffectScope`
|
|
84
|
+
|
|
85
|
+
Group effects so they can all be torn down at once. Essential for component lifecycle.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { withEffectScope } from "@sigil-dev/runtime";
|
|
89
|
+
|
|
90
|
+
const dispose = withEffectScope(() => {
|
|
91
|
+
createEffect(() => console.log(x()));
|
|
92
|
+
createEffect(() => console.log(y()));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
dispose(); // kills both
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Scopes nest correctly. Inner dispose does not affect outer scope.
|
|
99
|
+
|
|
100
|
+
### Context
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { createContext, setContext, getContext } from "@sigil-dev/runtime";
|
|
104
|
+
|
|
105
|
+
const ThemeKey = createContext<"light" | "dark">();
|
|
106
|
+
|
|
107
|
+
setContext(ThemeKey, "dark");
|
|
108
|
+
getContext(ThemeKey); // "dark"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Hydration utilities
|
|
112
|
+
> **NOTE:** You probably dont want to use this manually.
|
|
113
|
+
|
|
114
|
+
`claim`, `claimText`, `claimComment`, `reconcile`, `hydrateKeyedList` are used by the Sigil compiler for SSR hydration. Claim existing server-rendered DOM nodes instead of creating new ones.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { claim, claimText, reconcile } from "@sigil-dev/runtime";
|
|
118
|
+
|
|
119
|
+
// claim an existing <div> from an SSR pool instead of createElement
|
|
120
|
+
const el = claim(nodes, "div", parent);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Design
|
|
124
|
+
|
|
125
|
+
No virtual DOM. Effects write directly to DOM nodes. The update path is:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
signal.set(newValue)
|
|
129
|
+
→ notify subscribers
|
|
130
|
+
→ effect re-runs
|
|
131
|
+
→ direct DOM mutation
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
If a signal changes, the effects that depend on it run synchronously (or are batched if inside `batch()`).
|
|
135
|
+
|
|
136
|
+
Deep reactivity on objects uses Proxy rather than explicit getter/setter pairs. This means you can pass a signal's value to any code that expects a plain object and mutations will still be tracked.
|
|
137
|
+
|
|
138
|
+
## Used by
|
|
139
|
+
|
|
140
|
+
`@sigil-dev/compiler` compiles `$state`, `$derived`, and `$effect` macros down to these primitives at build time. You can use this library directly if you want explicit control or are building outside the Sigil compiler pipeline.
|
package/async-boundary.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
export function __asyncBoundary(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
factory: () => Promise<any>,
|
|
3
|
+
Loading?: () => any,
|
|
4
|
+
Err?: (props: { error: unknown }) => any,
|
|
5
5
|
): Node {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const container = document.createElement("div");
|
|
7
|
+
container.dataset.asyncBoundary = "1";
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
if (Loading) {
|
|
10
|
+
const node = Loading();
|
|
11
|
+
if (node) container.appendChild(node);
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
factory()
|
|
15
|
+
.then((node) => {
|
|
16
|
+
if (node) container.replaceChildren(node);
|
|
17
|
+
else container.replaceChildren();
|
|
18
|
+
})
|
|
19
|
+
.catch((err) => {
|
|
20
|
+
if (Err) {
|
|
21
|
+
const errNode = Err({ error: err });
|
|
22
|
+
if (errNode) container.replaceChildren(errNode);
|
|
23
|
+
} else {
|
|
24
|
+
console.error("[sigil] async component error:", err);
|
|
25
|
+
container.replaceChildren();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
}
|
|
29
|
+
return container;
|
|
30
|
+
}
|
package/boundary.ts
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error boundary for Sigil components.
|
|
3
|
-
*
|
|
4
|
-
* Wraps children so that errors during rendering are caught
|
|
5
|
-
* and handled instead of crashing the app.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* <Boundary
|
|
9
|
-
* fallbackError={({ error, reset }) => <button onClick={reset}>Retry</button>}
|
|
10
|
-
* onError={(e) => reportToSentry(e)}
|
|
11
|
-
* >
|
|
12
|
-
* <FlakyComponent />
|
|
13
|
-
* </Boundary>
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { createSignal } from "./index.js";
|
|
17
|
-
|
|
18
|
-
interface BoundaryProps {
|
|
19
|
-
children: any;
|
|
20
|
-
fallbackError?: (ctx: { error: Error; reset: () => void }) => any;
|
|
21
|
-
onError?: (error: Error) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function Boundary(props: BoundaryProps): any {
|
|
25
|
-
const error = createSignal<Error | null>(null);
|
|
26
|
-
|
|
27
|
-
const reset = () => error.set(null);
|
|
28
|
-
|
|
29
|
-
if (error()) {
|
|
30
|
-
return props.fallbackError
|
|
31
|
-
? props.fallbackError({ error: error()!, reset })
|
|
32
|
-
: null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
return props.children;
|
|
37
|
-
} catch (e) {
|
|
38
|
-
props.onError?.(e as Error);
|
|
39
|
-
error.set(e as Error);
|
|
40
|
-
return props.fallbackError
|
|
41
|
-
? props.fallbackError({ error: e as Error, reset })
|
|
42
|
-
: null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Error boundary for Sigil components.
|
|
3
|
+
*
|
|
4
|
+
* Wraps children so that errors during rendering are caught
|
|
5
|
+
* and handled instead of crashing the app.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <Boundary
|
|
9
|
+
* fallbackError={({ error, reset }) => <button onClick={reset}>Retry</button>}
|
|
10
|
+
* onError={(e) => reportToSentry(e)}
|
|
11
|
+
* >
|
|
12
|
+
* <FlakyComponent />
|
|
13
|
+
* </Boundary>
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createSignal } from "./index.js";
|
|
17
|
+
|
|
18
|
+
interface BoundaryProps {
|
|
19
|
+
children: any;
|
|
20
|
+
fallbackError?: (ctx: { error: Error; reset: () => void }) => any;
|
|
21
|
+
onError?: (error: Error) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function Boundary(props: BoundaryProps): any {
|
|
25
|
+
const error = createSignal<Error | null>(null);
|
|
26
|
+
|
|
27
|
+
const reset = () => error.set(null);
|
|
28
|
+
|
|
29
|
+
if (error()) {
|
|
30
|
+
return props.fallbackError
|
|
31
|
+
? props.fallbackError({ error: error()!, reset })
|
|
32
|
+
: null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
return props.children;
|
|
37
|
+
} catch (e) {
|
|
38
|
+
props.onError?.(e as Error);
|
|
39
|
+
error.set(e as Error);
|
|
40
|
+
return props.fallbackError
|
|
41
|
+
? props.fallbackError({ error: e as Error, reset })
|
|
42
|
+
: null;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/easing.ts
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
// A8: 15 standard easing functions (cubic bezier approximations)
|
|
2
|
-
// All take t in [0, 1] and return eased value in [0, 1].
|
|
3
|
-
|
|
4
|
-
export function linear(t: number): number {
|
|
5
|
-
return t;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export function easeInQuad(t: number): number {
|
|
9
|
-
return t * t;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function easeOutQuad(t: number): number {
|
|
13
|
-
return t * (2 - t);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function easeInOutQuad(t: number): number {
|
|
17
|
-
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function easeInCubic(t: number): number {
|
|
21
|
-
return t * t * t;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function easeOutCubic(t: number): number {
|
|
25
|
-
return --t * t * t + 1;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function easeInOutCubic(t: number): number {
|
|
29
|
-
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function easeInQuart(t: number): number {
|
|
33
|
-
return t * t * t * t;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function easeOutQuart(t: number): number {
|
|
37
|
-
return 1 - --t * t * t * t;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function easeInOutQuart(t: number): number {
|
|
41
|
-
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function easeInQuint(t: number): number {
|
|
45
|
-
return t * t * t * t * t;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function easeOutQuint(t: number): number {
|
|
49
|
-
return 1 + --t * t * t * t * t;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function easeInOutQuint(t: number): number {
|
|
53
|
-
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function easeInSine(t: number): number {
|
|
57
|
-
return 1 - Math.cos((t * Math.PI) / 2);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function easeOutSine(t: number): number {
|
|
61
|
-
return Math.sin((t * Math.PI) / 2);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function easeInOutSine(t: number): number {
|
|
65
|
-
return -(Math.cos(Math.PI * t) - 1) / 2;
|
|
66
|
-
}
|
|
1
|
+
// A8: 15 standard easing functions (cubic bezier approximations)
|
|
2
|
+
// All take t in [0, 1] and return eased value in [0, 1].
|
|
3
|
+
|
|
4
|
+
export function linear(t: number): number {
|
|
5
|
+
return t;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function easeInQuad(t: number): number {
|
|
9
|
+
return t * t;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function easeOutQuad(t: number): number {
|
|
13
|
+
return t * (2 - t);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function easeInOutQuad(t: number): number {
|
|
17
|
+
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function easeInCubic(t: number): number {
|
|
21
|
+
return t * t * t;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function easeOutCubic(t: number): number {
|
|
25
|
+
return --t * t * t + 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function easeInOutCubic(t: number): number {
|
|
29
|
+
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function easeInQuart(t: number): number {
|
|
33
|
+
return t * t * t * t;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function easeOutQuart(t: number): number {
|
|
37
|
+
return 1 - --t * t * t * t;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function easeInOutQuart(t: number): number {
|
|
41
|
+
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function easeInQuint(t: number): number {
|
|
45
|
+
return t * t * t * t * t;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function easeOutQuint(t: number): number {
|
|
49
|
+
return 1 + --t * t * t * t * t;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function easeInOutQuint(t: number): number {
|
|
53
|
+
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function easeInSine(t: number): number {
|
|
57
|
+
return 1 - Math.cos((t * Math.PI) / 2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function easeOutSine(t: number): number {
|
|
61
|
+
return Math.sin((t * Math.PI) / 2);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function easeInOutSine(t: number): number {
|
|
65
|
+
return -(Math.cos(Math.PI * t) - 1) / 2;
|
|
66
|
+
}
|