hyperapp-is 0.1.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/LICENSE +21 -0
- package/README.md +1254 -0
- package/README.npm.md +107 -0
- package/dist/hyperapp-is/animation/easing.d.ts +15 -0
- package/dist/hyperapp-is/animation/easing.js +57 -0
- package/dist/hyperapp-is/animation/index.d.ts +5 -0
- package/dist/hyperapp-is/animation/index.js +3 -0
- package/dist/hyperapp-is/animation/properties.d.ts +64 -0
- package/dist/hyperapp-is/animation/properties.js +108 -0
- package/dist/hyperapp-is/animation/raf.d.ts +71 -0
- package/dist/hyperapp-is/animation/raf.js +202 -0
- package/dist/hyperapp-is/animationView/carousel.d.ts +95 -0
- package/dist/hyperapp-is/animationView/carousel.js +472 -0
- package/dist/hyperapp-is/animationView/index.d.ts +2 -0
- package/dist/hyperapp-is/animationView/index.js +1 -0
- package/dist/hyperapp-is/core/component.d.ts +95 -0
- package/dist/hyperapp-is/core/component.js +193 -0
- package/dist/hyperapp-is/core/index.d.ts +2 -0
- package/dist/hyperapp-is/core/index.js +2 -0
- package/dist/hyperapp-is/core/state.d.ts +54 -0
- package/dist/hyperapp-is/core/state.js +118 -0
- package/dist/hyperapp-is/dom/index.d.ts +2 -0
- package/dist/hyperapp-is/dom/index.js +1 -0
- package/dist/hyperapp-is/dom/utils.d.ts +68 -0
- package/dist/hyperapp-is/dom/utils.js +159 -0
- package/dist/hyperapp-is/index.d.ts +7 -0
- package/dist/hyperapp-is/index.js +5 -0
- package/package.json +40 -0
package/README.npm.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# hyperapp-is
|
|
2
|
+
|
|
3
|
+
Lightweight. Declarative. Composable.
|
|
4
|
+
|
|
5
|
+
Reusable component foundation library for Hyperapp v2.
|
|
6
|
+
|
|
7
|
+
State-structure independent design + RAF-based animation system.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- State-path based reusable component design
|
|
14
|
+
- Local state helpers
|
|
15
|
+
`getLocalState`, `setLocalState`, `createLocalKey`
|
|
16
|
+
- Action composition utility
|
|
17
|
+
`concatAction`
|
|
18
|
+
- Class / props utilities
|
|
19
|
+
`getClassList`, `deleteKeys`
|
|
20
|
+
- requestAnimationFrame task system
|
|
21
|
+
`RAFTask`, `subscription_RAFManager`
|
|
22
|
+
- Built-in animated Carousel component
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
``` bash
|
|
29
|
+
npm install hyperapp-is
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Peer dependencies:
|
|
33
|
+
|
|
34
|
+
- hyperapp v2
|
|
35
|
+
- hyperapp-jsx-pragma (when using JSX)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Basic Usage (Carousel Example)
|
|
40
|
+
|
|
41
|
+
``` ts
|
|
42
|
+
import { app } from "hyperapp"
|
|
43
|
+
import h from "hyperapp-jsx-pragma"
|
|
44
|
+
import {
|
|
45
|
+
RAFTask, subscription_RAFManager,
|
|
46
|
+
Carousel, effect_InitCarousel
|
|
47
|
+
} from "hyperapp-is"
|
|
48
|
+
|
|
49
|
+
interface State {
|
|
50
|
+
tasks: RAFTask<State>[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const initState: State = {
|
|
54
|
+
tasks: []
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
app({
|
|
58
|
+
node: document.getElementById("app") as HTMLElement,
|
|
59
|
+
init: [initState, effect_InitCarousel(["tasks"], {
|
|
60
|
+
id : "carousel",
|
|
61
|
+
duration: 2000,
|
|
62
|
+
delay : 1000,
|
|
63
|
+
step : 1
|
|
64
|
+
})],
|
|
65
|
+
|
|
66
|
+
subscriptions: (state) => [
|
|
67
|
+
subscription_RAFManager(state, ["tasks"])
|
|
68
|
+
],
|
|
69
|
+
|
|
70
|
+
view: (state) => (<Carousel
|
|
71
|
+
state = { state }
|
|
72
|
+
id = "carousel"
|
|
73
|
+
keyNames = { ["tasks"] }
|
|
74
|
+
>
|
|
75
|
+
<div>Slide 1</div>
|
|
76
|
+
<div>Slide 2</div>
|
|
77
|
+
<div>Slide 3</div>
|
|
78
|
+
</Carousel>)
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Concept
|
|
85
|
+
|
|
86
|
+
hyperapp-is allows components to:
|
|
87
|
+
|
|
88
|
+
- Remain independent from root state structure
|
|
89
|
+
- Store internal state without polluting user state
|
|
90
|
+
- Compose actions safely
|
|
91
|
+
- Manage animations declaratively via RAFTask
|
|
92
|
+
|
|
93
|
+
Designed for building reusable UI components on top of Hyperapp.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Documentation
|
|
98
|
+
|
|
99
|
+
Full documentation and detailed design notes are available on GitHub:
|
|
100
|
+
|
|
101
|
+
https://github.com/is4416/hyperapp-is
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const progress_easing: {
|
|
2
|
+
linear: (t: number) => number;
|
|
3
|
+
easeInQuad: (t: number) => number;
|
|
4
|
+
easeOutQuad: (t: number) => number;
|
|
5
|
+
easeInOutQuad: (t: number) => number;
|
|
6
|
+
easeInCubic: (t: number) => number;
|
|
7
|
+
easeOutCubic: (t: number) => number;
|
|
8
|
+
easeInOutCubic: (t: number) => number;
|
|
9
|
+
easeInQuart: (t: number) => number;
|
|
10
|
+
easeOutQuart: (t: number) => number;
|
|
11
|
+
easeInOutQuart: (t: number) => number;
|
|
12
|
+
easeOutBack: (t: number) => number;
|
|
13
|
+
easeOutBounce: (t: number) => number;
|
|
14
|
+
easeOutElastic: (t: number) => number;
|
|
15
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// hyperapp-ui / animation / easing.ts
|
|
2
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
3
|
+
// progress_easing
|
|
4
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
5
|
+
export const progress_easing = {
|
|
6
|
+
// basic
|
|
7
|
+
linear: (t) => t,
|
|
8
|
+
easeInQuad: (t) => t * t,
|
|
9
|
+
easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
|
|
10
|
+
easeInOutQuad: (t) => t < 0.5
|
|
11
|
+
? 2 * t * t
|
|
12
|
+
: 1 - Math.pow(-2 * t + 2, 2) / 2,
|
|
13
|
+
// cubic
|
|
14
|
+
easeInCubic: (t) => t * t * t,
|
|
15
|
+
easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
|
|
16
|
+
easeInOutCubic: (t) => t < 0.5
|
|
17
|
+
? 4 * t * t * t
|
|
18
|
+
: 1 - Math.pow(-2 * t + 2, 3) / 2,
|
|
19
|
+
// quart
|
|
20
|
+
easeInQuart: (t) => t * t * t * t,
|
|
21
|
+
easeOutQuart: (t) => 1 - Math.pow(1 - t, 4),
|
|
22
|
+
easeInOutQuart: (t) => t < 0.5
|
|
23
|
+
? 8 * t * t * t * t
|
|
24
|
+
: 1 - Math.pow(-2 * t + 2, 4) / 2,
|
|
25
|
+
// back (跳ねる)
|
|
26
|
+
easeOutBack: (t) => {
|
|
27
|
+
const c1 = 1.70158;
|
|
28
|
+
const c3 = c1 + 1;
|
|
29
|
+
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
|
|
30
|
+
},
|
|
31
|
+
// bounce
|
|
32
|
+
easeOutBounce: (t) => {
|
|
33
|
+
const n1 = 7.5625;
|
|
34
|
+
const d1 = 2.75;
|
|
35
|
+
if (t < 1 / d1) {
|
|
36
|
+
return n1 * t * t;
|
|
37
|
+
}
|
|
38
|
+
else if (t < 2 / d1) {
|
|
39
|
+
return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
40
|
+
}
|
|
41
|
+
else if (t < 2.5 / d1) {
|
|
42
|
+
return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
// elastic
|
|
49
|
+
easeOutElastic: (t) => {
|
|
50
|
+
const c4 = (2 * Math.PI) / 3;
|
|
51
|
+
return t === 0
|
|
52
|
+
? 0
|
|
53
|
+
: t === 1
|
|
54
|
+
? 1
|
|
55
|
+
: Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { InternalEffect, RAFEvent } from "./raf";
|
|
2
|
+
export type { CSSProperty } from "./properties";
|
|
3
|
+
export { RAFTask, subscription_RAFManager } from "./raf";
|
|
4
|
+
export { progress_easing } from "./easing";
|
|
5
|
+
export { createUnits, createRAFProperties, effect_RAFProperties } from "./properties";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Dispatch } from "hyperapp";
|
|
2
|
+
import { InternalEffect, RAFTask } from "./raf";
|
|
3
|
+
/**
|
|
4
|
+
* アニメーション進捗 (0〜1) を受け取り CSS 値を返す関数
|
|
5
|
+
*
|
|
6
|
+
* @type {Object.<string, Object.<string, (progress: number) => string>>} CSSProperty
|
|
7
|
+
* @property {Object.<string, (progress: number) => string>} [selector]
|
|
8
|
+
* @param {number} progress
|
|
9
|
+
*/
|
|
10
|
+
export interface CSSProperty {
|
|
11
|
+
[selector: string]: {
|
|
12
|
+
[name: string]: (progress: number) => string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* CSSProperty[] から、doms と styles のセットに変換
|
|
17
|
+
*
|
|
18
|
+
* @param {CSSProperty[]} properties - プロパティ配列
|
|
19
|
+
* @returns {doms: HTMLElement[], styles:{ [name: string]: (progress: number) => string}}
|
|
20
|
+
*/
|
|
21
|
+
export declare const createUnits: (properties: CSSProperty[]) => {
|
|
22
|
+
doms: HTMLElement[];
|
|
23
|
+
styles: {
|
|
24
|
+
[name: string]: (progress: number) => string;
|
|
25
|
+
};
|
|
26
|
+
}[];
|
|
27
|
+
/**
|
|
28
|
+
* subscription_RAFManager をベースにした CSS アニメーション RAFTask を作成する
|
|
29
|
+
* props は基本的に RAFTask の値
|
|
30
|
+
*
|
|
31
|
+
* @param {CSSProperty[]} props.properties - セレクタとスタイル設定のセット配列
|
|
32
|
+
*/
|
|
33
|
+
export declare const createRAFProperties: <S>(props: {
|
|
34
|
+
id: string;
|
|
35
|
+
groupID?: string;
|
|
36
|
+
duration: number;
|
|
37
|
+
delay?: number;
|
|
38
|
+
finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
|
|
39
|
+
priority?: number;
|
|
40
|
+
extension?: {
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
};
|
|
43
|
+
properties: CSSProperty[];
|
|
44
|
+
}) => RAFTask<S>;
|
|
45
|
+
/**
|
|
46
|
+
* subscription_RAFManager をベースにした CSS アニメーションエフェクト
|
|
47
|
+
* props は基本的に RAFTask の値
|
|
48
|
+
*
|
|
49
|
+
* @param {CSSProperty[]} props.properties - セレクタとスタイル設定のセット配列
|
|
50
|
+
* @param {string[]} props.keyNames - RAFTask 配列までのパス
|
|
51
|
+
*/
|
|
52
|
+
export declare const effect_RAFProperties: <S>(props: {
|
|
53
|
+
id: string;
|
|
54
|
+
groupID?: string;
|
|
55
|
+
duration: number;
|
|
56
|
+
delay?: number;
|
|
57
|
+
finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
|
|
58
|
+
priority?: number;
|
|
59
|
+
extension?: {
|
|
60
|
+
[key: string]: any;
|
|
61
|
+
};
|
|
62
|
+
properties: CSSProperty[];
|
|
63
|
+
keyNames: string[];
|
|
64
|
+
}) => (dispatch: Dispatch<S>) => void;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// hyperapp-ui / animation / properties.ts
|
|
2
|
+
import { getValue, setValue } from "../core/state";
|
|
3
|
+
import { RAFTask } from "./raf";
|
|
4
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
5
|
+
// createUnits
|
|
6
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
7
|
+
/**
|
|
8
|
+
* CSSProperty[] から、doms と styles のセットに変換
|
|
9
|
+
*
|
|
10
|
+
* @param {CSSProperty[]} properties - プロパティ配列
|
|
11
|
+
* @returns {doms: HTMLElement[], styles:{ [name: string]: (progress: number) => string}}
|
|
12
|
+
*/
|
|
13
|
+
export const createUnits = function (properties) {
|
|
14
|
+
return properties.map(p => {
|
|
15
|
+
const selector = Object.keys(p)[0];
|
|
16
|
+
return {
|
|
17
|
+
doms: Array.from(document.querySelectorAll(selector)),
|
|
18
|
+
styles: p[selector]
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
23
|
+
// createRAFProperties
|
|
24
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
25
|
+
/**
|
|
26
|
+
* subscription_RAFManager をベースにした CSS アニメーション RAFTask を作成する
|
|
27
|
+
* props は基本的に RAFTask の値
|
|
28
|
+
*
|
|
29
|
+
* @param {CSSProperty[]} props.properties - セレクタとスタイル設定のセット配列
|
|
30
|
+
*/
|
|
31
|
+
export const createRAFProperties = function (props) {
|
|
32
|
+
const { id, groupID, duration, delay, priority, extension, properties } = props;
|
|
33
|
+
// action
|
|
34
|
+
const action = (state, rafTask) => {
|
|
35
|
+
var _a;
|
|
36
|
+
const progress = (_a = rafTask.progress) !== null && _a !== void 0 ? _a : 0;
|
|
37
|
+
const units = createUnits(properties);
|
|
38
|
+
// set styles
|
|
39
|
+
units.forEach(unit => {
|
|
40
|
+
for (const [name, fn] of Object.entries(unit.styles)) {
|
|
41
|
+
unit.doms.forEach(dom => dom.style.setProperty(name, fn(progress)));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return state;
|
|
45
|
+
};
|
|
46
|
+
// finish
|
|
47
|
+
const finish = (state, rafTask) => {
|
|
48
|
+
const units = createUnits(properties);
|
|
49
|
+
// release gpu layer
|
|
50
|
+
units.forEach(unit => {
|
|
51
|
+
unit.doms.forEach(dom => dom.style.willChange = "");
|
|
52
|
+
});
|
|
53
|
+
return [
|
|
54
|
+
state,
|
|
55
|
+
(dispatch) => {
|
|
56
|
+
const fn = props.finish;
|
|
57
|
+
if (fn) {
|
|
58
|
+
requestAnimationFrame(() => requestAnimationFrame(() => dispatch((state) => fn(state, rafTask))));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
};
|
|
63
|
+
return new RAFTask({
|
|
64
|
+
id, groupID, duration, delay,
|
|
65
|
+
action, finish,
|
|
66
|
+
priority,
|
|
67
|
+
extension: {
|
|
68
|
+
...extension,
|
|
69
|
+
properties
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
74
|
+
// effect_RAFProperties
|
|
75
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
76
|
+
const GPU_LAYER = new Set(["transform", "opacity"]);
|
|
77
|
+
/**
|
|
78
|
+
* subscription_RAFManager をベースにした CSS アニメーションエフェクト
|
|
79
|
+
* props は基本的に RAFTask の値
|
|
80
|
+
*
|
|
81
|
+
* @param {CSSProperty[]} props.properties - セレクタとスタイル設定のセット配列
|
|
82
|
+
* @param {string[]} props.keyNames - RAFTask 配列までのパス
|
|
83
|
+
*/
|
|
84
|
+
export const effect_RAFProperties = function (props) {
|
|
85
|
+
const { id, groupID, duration, delay, finish, priority, extension, properties, keyNames } = props;
|
|
86
|
+
// get doms
|
|
87
|
+
const units = createUnits(properties);
|
|
88
|
+
// set GPU Layer
|
|
89
|
+
units.forEach(unit => {
|
|
90
|
+
const val = [...new Set(Object.keys(unit.styles))].filter(name => GPU_LAYER.has(name)).join(",");
|
|
91
|
+
unit.doms.forEach(dom => dom.style.willChange = val);
|
|
92
|
+
});
|
|
93
|
+
// newTask
|
|
94
|
+
const newTask = createRAFProperties({
|
|
95
|
+
id, groupID, duration, delay, finish, priority, extension, properties
|
|
96
|
+
});
|
|
97
|
+
// set newTask
|
|
98
|
+
return (dispatch) => {
|
|
99
|
+
requestAnimationFrame(() => {
|
|
100
|
+
dispatch((state) => {
|
|
101
|
+
const tasks = getValue(state, keyNames, [])
|
|
102
|
+
.filter(task => task.id !== id)
|
|
103
|
+
.concat(newTask);
|
|
104
|
+
return setValue(state, keyNames, tasks);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Effect, Subscription } from "hyperapp";
|
|
2
|
+
/**
|
|
3
|
+
* 戻値としては返されないことを示したエフェクト
|
|
4
|
+
* Effect の型エイリアス
|
|
5
|
+
*/
|
|
6
|
+
export type InternalEffect<S> = Effect<S>;
|
|
7
|
+
/**
|
|
8
|
+
* RAFTask の action, finish
|
|
9
|
+
* 型エイリアス
|
|
10
|
+
*/
|
|
11
|
+
export type RAFEvent<S> = (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
|
|
12
|
+
declare const _isStart: unique symbol;
|
|
13
|
+
export declare class RAFTask<S> {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(props: {
|
|
16
|
+
id: string;
|
|
17
|
+
groupID?: string;
|
|
18
|
+
duration: number;
|
|
19
|
+
delay?: number;
|
|
20
|
+
action: RAFEvent<S>;
|
|
21
|
+
finish?: RAFEvent<S>;
|
|
22
|
+
priority?: number;
|
|
23
|
+
extension?: {
|
|
24
|
+
[key: string]: any;
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
get id(): string;
|
|
28
|
+
get groupID(): string | undefined;
|
|
29
|
+
get duration(): number;
|
|
30
|
+
get delay(): number;
|
|
31
|
+
get action(): RAFEvent<S>;
|
|
32
|
+
get finish(): RAFEvent<S> | undefined;
|
|
33
|
+
get priority(): number;
|
|
34
|
+
get extension(): {
|
|
35
|
+
[key: string]: any;
|
|
36
|
+
};
|
|
37
|
+
get progress(): number;
|
|
38
|
+
get deltaTime(): number;
|
|
39
|
+
get isDone(): boolean;
|
|
40
|
+
get paused(): boolean;
|
|
41
|
+
set groupID(val: string | undefined);
|
|
42
|
+
set priority(val: number);
|
|
43
|
+
set extension(val: {
|
|
44
|
+
[key: string]: any;
|
|
45
|
+
});
|
|
46
|
+
set isDone(val: boolean);
|
|
47
|
+
set paused(val: boolean);
|
|
48
|
+
/**
|
|
49
|
+
* アクションを開始して良いか判定する
|
|
50
|
+
* 現在時間等のアップデートも同時に行われる
|
|
51
|
+
* subscription_RAFManager でのみ使用される
|
|
52
|
+
*
|
|
53
|
+
* @param {number} now - requestAnimatinFrame が返す絶対時間
|
|
54
|
+
* @returns {boolan} - アクションを実行して良いか判定
|
|
55
|
+
*/
|
|
56
|
+
private [_isStart];
|
|
57
|
+
/**
|
|
58
|
+
* 時間を初期化したクローンを作成して返す
|
|
59
|
+
*/
|
|
60
|
+
clone(): RAFTask<S>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* RAFTask 配列をフレームごとに実行するサブスクリプション
|
|
64
|
+
*
|
|
65
|
+
* @template S
|
|
66
|
+
* @param {S} state - ステート
|
|
67
|
+
* @param {string[]} keyNames - RAFTask 配列までのパス
|
|
68
|
+
* @returns {Subscription<S>}
|
|
69
|
+
*/
|
|
70
|
+
export declare const subscription_RAFManager: <S>(state: S, keyNames: string[]) => Subscription<S>;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// hyperapp-ui / animation / raf.ts
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _RAFTask_id, _RAFTask_groupID, _RAFTask_duration, _RAFTask_delay, _RAFTask_action, _RAFTask_finish, _RAFTask_priority, _RAFTask_extension, _RAFTask_startTime, _RAFTask_currentTime, _RAFTask_pausedTime, _RAFTask_paused, _RAFTask_deltaTime, _RAFTask_isDone;
|
|
14
|
+
import { getValue, setValue } from "../core/state";
|
|
15
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
16
|
+
// class RAFTask
|
|
17
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
18
|
+
// Symbol
|
|
19
|
+
// subscription_RAFManager のみで使用される専用メソッド
|
|
20
|
+
// Symbol を知らない限り、モジュールの外からは呼べない
|
|
21
|
+
const _isStart = Symbol("RAFTask.isStart");
|
|
22
|
+
export class RAFTask {
|
|
23
|
+
// constructor
|
|
24
|
+
constructor(props) {
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
// field
|
|
27
|
+
_RAFTask_id.set(this, void 0);
|
|
28
|
+
_RAFTask_groupID.set(this, void 0);
|
|
29
|
+
_RAFTask_duration.set(this, void 0);
|
|
30
|
+
_RAFTask_delay.set(this, void 0);
|
|
31
|
+
_RAFTask_action.set(this, void 0);
|
|
32
|
+
_RAFTask_finish.set(this, void 0);
|
|
33
|
+
_RAFTask_priority.set(this, void 0);
|
|
34
|
+
_RAFTask_extension.set(this, void 0);
|
|
35
|
+
_RAFTask_startTime.set(this, void 0);
|
|
36
|
+
_RAFTask_currentTime.set(this, void 0);
|
|
37
|
+
_RAFTask_pausedTime.set(this, void 0);
|
|
38
|
+
_RAFTask_paused.set(this, void 0);
|
|
39
|
+
_RAFTask_deltaTime.set(this, void 0);
|
|
40
|
+
_RAFTask_isDone.set(this, void 0);
|
|
41
|
+
__classPrivateFieldSet(this, _RAFTask_id, props.id, "f");
|
|
42
|
+
__classPrivateFieldSet(this, _RAFTask_groupID, props.groupID, "f");
|
|
43
|
+
__classPrivateFieldSet(this, _RAFTask_duration, props.duration, "f");
|
|
44
|
+
__classPrivateFieldSet(this, _RAFTask_delay, (_a = props.delay) !== null && _a !== void 0 ? _a : 0, "f");
|
|
45
|
+
__classPrivateFieldSet(this, _RAFTask_action, props.action, "f");
|
|
46
|
+
__classPrivateFieldSet(this, _RAFTask_finish, props.finish, "f");
|
|
47
|
+
__classPrivateFieldSet(this, _RAFTask_priority, (_b = props.priority) !== null && _b !== void 0 ? _b : 0, "f");
|
|
48
|
+
__classPrivateFieldSet(this, _RAFTask_extension, (_c = props.extension) !== null && _c !== void 0 ? _c : {}, "f");
|
|
49
|
+
__classPrivateFieldSet(this, _RAFTask_isDone, false, "f");
|
|
50
|
+
__classPrivateFieldSet(this, _RAFTask_paused, false, "f");
|
|
51
|
+
}
|
|
52
|
+
// getter
|
|
53
|
+
get id() { return __classPrivateFieldGet(this, _RAFTask_id, "f"); }
|
|
54
|
+
get groupID() { return __classPrivateFieldGet(this, _RAFTask_groupID, "f"); }
|
|
55
|
+
get duration() { return __classPrivateFieldGet(this, _RAFTask_duration, "f"); }
|
|
56
|
+
get delay() { return __classPrivateFieldGet(this, _RAFTask_delay, "f"); }
|
|
57
|
+
get action() { return __classPrivateFieldGet(this, _RAFTask_action, "f"); }
|
|
58
|
+
get finish() { return __classPrivateFieldGet(this, _RAFTask_finish, "f"); }
|
|
59
|
+
get priority() { return __classPrivateFieldGet(this, _RAFTask_priority, "f"); }
|
|
60
|
+
get extension() { return __classPrivateFieldGet(this, _RAFTask_extension, "f"); }
|
|
61
|
+
get progress() {
|
|
62
|
+
if (__classPrivateFieldGet(this, _RAFTask_startTime, "f") === undefined || __classPrivateFieldGet(this, _RAFTask_currentTime, "f") === undefined)
|
|
63
|
+
return 0;
|
|
64
|
+
return Math.min(1, Math.max(0, (__classPrivateFieldGet(this, _RAFTask_currentTime, "f") - __classPrivateFieldGet(this, _RAFTask_startTime, "f")) /
|
|
65
|
+
Math.max(1, __classPrivateFieldGet(this, _RAFTask_duration, "f"))));
|
|
66
|
+
}
|
|
67
|
+
get deltaTime() { var _a; return (_a = __classPrivateFieldGet(this, _RAFTask_deltaTime, "f")) !== null && _a !== void 0 ? _a : 0; }
|
|
68
|
+
get isDone() {
|
|
69
|
+
if (__classPrivateFieldGet(this, _RAFTask_isDone, "f"))
|
|
70
|
+
return true;
|
|
71
|
+
if (__classPrivateFieldGet(this, _RAFTask_pausedTime, "f") !== undefined)
|
|
72
|
+
return false;
|
|
73
|
+
return this.progress === 1;
|
|
74
|
+
}
|
|
75
|
+
get paused() { return __classPrivateFieldGet(this, _RAFTask_paused, "f"); }
|
|
76
|
+
// setter
|
|
77
|
+
set groupID(val) { __classPrivateFieldSet(this, _RAFTask_groupID, val, "f"); }
|
|
78
|
+
set priority(val) { __classPrivateFieldSet(this, _RAFTask_priority, val, "f"); }
|
|
79
|
+
set extension(val) { __classPrivateFieldSet(this, _RAFTask_extension, val, "f"); }
|
|
80
|
+
set isDone(val) { __classPrivateFieldSet(this, _RAFTask_isDone, val, "f"); }
|
|
81
|
+
set paused(val) { __classPrivateFieldSet(this, _RAFTask_paused, val, "f"); }
|
|
82
|
+
// private method: _isStart
|
|
83
|
+
/**
|
|
84
|
+
* アクションを開始して良いか判定する
|
|
85
|
+
* 現在時間等のアップデートも同時に行われる
|
|
86
|
+
* subscription_RAFManager でのみ使用される
|
|
87
|
+
*
|
|
88
|
+
* @param {number} now - requestAnimatinFrame が返す絶対時間
|
|
89
|
+
* @returns {boolan} - アクションを実行して良いか判定
|
|
90
|
+
*/
|
|
91
|
+
[(_RAFTask_id = new WeakMap(), _RAFTask_groupID = new WeakMap(), _RAFTask_duration = new WeakMap(), _RAFTask_delay = new WeakMap(), _RAFTask_action = new WeakMap(), _RAFTask_finish = new WeakMap(), _RAFTask_priority = new WeakMap(), _RAFTask_extension = new WeakMap(), _RAFTask_startTime = new WeakMap(), _RAFTask_currentTime = new WeakMap(), _RAFTask_pausedTime = new WeakMap(), _RAFTask_paused = new WeakMap(), _RAFTask_deltaTime = new WeakMap(), _RAFTask_isDone = new WeakMap(), _isStart)](now) {
|
|
92
|
+
var _a;
|
|
93
|
+
// done
|
|
94
|
+
if (this.isDone)
|
|
95
|
+
return false;
|
|
96
|
+
// startTime
|
|
97
|
+
if (__classPrivateFieldGet(this, _RAFTask_startTime, "f") === undefined)
|
|
98
|
+
__classPrivateFieldSet(this, _RAFTask_startTime, now + __classPrivateFieldGet(this, _RAFTask_delay, "f"), "f");
|
|
99
|
+
// pause
|
|
100
|
+
if (this.paused) {
|
|
101
|
+
if (__classPrivateFieldGet(this, _RAFTask_pausedTime, "f") === undefined)
|
|
102
|
+
__classPrivateFieldSet(this, _RAFTask_pausedTime, now, "f");
|
|
103
|
+
__classPrivateFieldSet(this, _RAFTask_deltaTime, 0, "f");
|
|
104
|
+
__classPrivateFieldSet(this, _RAFTask_currentTime, now, "f");
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
// resume
|
|
108
|
+
if (!this.paused && __classPrivateFieldGet(this, _RAFTask_pausedTime, "f") !== undefined) {
|
|
109
|
+
__classPrivateFieldSet(this, _RAFTask_startTime, __classPrivateFieldGet(this, _RAFTask_startTime, "f") + now - __classPrivateFieldGet(this, _RAFTask_pausedTime, "f"), "f");
|
|
110
|
+
__classPrivateFieldSet(this, _RAFTask_pausedTime, undefined, "f");
|
|
111
|
+
}
|
|
112
|
+
// deltaTime
|
|
113
|
+
__classPrivateFieldSet(this, _RAFTask_deltaTime, now < __classPrivateFieldGet(this, _RAFTask_startTime, "f")
|
|
114
|
+
? 0
|
|
115
|
+
: now - ((_a = __classPrivateFieldGet(this, _RAFTask_currentTime, "f")) !== null && _a !== void 0 ? _a : now), "f");
|
|
116
|
+
// currentTime
|
|
117
|
+
__classPrivateFieldSet(this, _RAFTask_currentTime, now, "f");
|
|
118
|
+
// result
|
|
119
|
+
__classPrivateFieldSet(this, _RAFTask_isDone, this.progress === 1, "f");
|
|
120
|
+
return !__classPrivateFieldGet(this, _RAFTask_isDone, "f");
|
|
121
|
+
}
|
|
122
|
+
// method: clone
|
|
123
|
+
/**
|
|
124
|
+
* 時間を初期化したクローンを作成して返す
|
|
125
|
+
*/
|
|
126
|
+
clone() {
|
|
127
|
+
return new RAFTask({
|
|
128
|
+
id: this.id,
|
|
129
|
+
groupID: this.groupID,
|
|
130
|
+
duration: this.duration,
|
|
131
|
+
delay: this.delay,
|
|
132
|
+
action: this.action,
|
|
133
|
+
finish: this.finish,
|
|
134
|
+
priority: this.priority,
|
|
135
|
+
extension: this.extension
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
140
|
+
// subscription_RAFManager
|
|
141
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
142
|
+
/**
|
|
143
|
+
* RAFTask 配列をフレームごとに実行するサブスクリプション
|
|
144
|
+
*
|
|
145
|
+
* @template S
|
|
146
|
+
* @param {S} state - ステート
|
|
147
|
+
* @param {string[]} keyNames - RAFTask 配列までのパス
|
|
148
|
+
* @returns {Subscription<S>}
|
|
149
|
+
*/
|
|
150
|
+
export const subscription_RAFManager = function (state, keyNames) {
|
|
151
|
+
let rID = 0; // rAF timerID
|
|
152
|
+
// result
|
|
153
|
+
return [
|
|
154
|
+
(dispatch, payload) => {
|
|
155
|
+
if (payload.length === 0)
|
|
156
|
+
return () => {
|
|
157
|
+
if (rID !== 0)
|
|
158
|
+
cancelAnimationFrame(rID);
|
|
159
|
+
};
|
|
160
|
+
// rAF callback
|
|
161
|
+
const loop = (now) => {
|
|
162
|
+
dispatch((state) => {
|
|
163
|
+
const tasks = getValue(state, keyNames, []);
|
|
164
|
+
const newTasks = tasks.map(task => {
|
|
165
|
+
if (task.isDone)
|
|
166
|
+
return null;
|
|
167
|
+
// action
|
|
168
|
+
if (task[_isStart](now)) {
|
|
169
|
+
requestAnimationFrame(() => dispatch((state) => task.action(state, task)));
|
|
170
|
+
}
|
|
171
|
+
// finish
|
|
172
|
+
if (task.isDone) {
|
|
173
|
+
const fn = task.finish;
|
|
174
|
+
if (fn) {
|
|
175
|
+
requestAnimationFrame(() => dispatch((state) => fn(state, task)));
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
// next
|
|
180
|
+
return task;
|
|
181
|
+
}).filter(task => task !== null);
|
|
182
|
+
// next loop
|
|
183
|
+
if (newTasks.length !== 0)
|
|
184
|
+
rID = requestAnimationFrame(loop);
|
|
185
|
+
// set state
|
|
186
|
+
return setValue(state, keyNames, newTasks);
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
// set animation
|
|
190
|
+
rID = requestAnimationFrame(loop);
|
|
191
|
+
// finalize
|
|
192
|
+
return () => {
|
|
193
|
+
if (rID !== 0)
|
|
194
|
+
cancelAnimationFrame(rID);
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
// payload
|
|
198
|
+
getValue(state, keyNames, [])
|
|
199
|
+
.filter(task => !task.isDone)
|
|
200
|
+
.sort((a, b) => b.priority - a.priority)
|
|
201
|
+
];
|
|
202
|
+
};
|