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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { VNode, Dispatch } from "hyperapp";
|
|
2
|
+
import { RAFEvent, RAFTask } from "../animation/raf";
|
|
3
|
+
/**
|
|
4
|
+
* Carousel コンポーネント情報
|
|
5
|
+
* RAFTask.extension に保存する
|
|
6
|
+
*
|
|
7
|
+
* 実行後に id を変更しても、反映されません
|
|
8
|
+
* 実行後に step, duration, delay を変更した場合、次のタスクに反映されます
|
|
9
|
+
* groupID, priority は未実装であり、値を設定しても動作に反映されません
|
|
10
|
+
*
|
|
11
|
+
* @template S
|
|
12
|
+
* @typedef {Object} CarouselState
|
|
13
|
+
*
|
|
14
|
+
* @property {string} id - ユニークID
|
|
15
|
+
* @property {number} step - 移動するページ数。負で逆順。0で停止
|
|
16
|
+
*
|
|
17
|
+
* option
|
|
18
|
+
* @property {string} [groupID] - 任意のグループナンバー (未実装)
|
|
19
|
+
* @property {number} [duration] - 1回あたりの実行時間 (ms)
|
|
20
|
+
* @property {number} [delay] - 待機時間 (ms)
|
|
21
|
+
* @property {number} [priority] - 処理優先巡視 (未実装)
|
|
22
|
+
* @property {{ [key: string]: any}} [extension] - 拡張用プロパティ
|
|
23
|
+
*
|
|
24
|
+
* event
|
|
25
|
+
* @property {RAFEvent<S>} [action] - 毎フレーム発生するイベント
|
|
26
|
+
* @property {RAFEvent<S>} [finish] - ページ切替後に発生するイベント
|
|
27
|
+
*
|
|
28
|
+
* animation
|
|
29
|
+
* @property {(t: number) => number} easing - easing 関数
|
|
30
|
+
*
|
|
31
|
+
* report
|
|
32
|
+
* @property {string[]} [reportPageIndex] - 現在表示中インデックスの出力パス
|
|
33
|
+
*/
|
|
34
|
+
export interface CarouselState<S> {
|
|
35
|
+
id: string;
|
|
36
|
+
step: number;
|
|
37
|
+
groupID?: string;
|
|
38
|
+
duration?: number;
|
|
39
|
+
delay?: number;
|
|
40
|
+
priority?: number;
|
|
41
|
+
extension?: {
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
};
|
|
44
|
+
action?: RAFEvent<S>;
|
|
45
|
+
finish?: RAFEvent<S>;
|
|
46
|
+
easing?: (t: number) => number;
|
|
47
|
+
reportPageIndex?: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 外部から Carousel コンポーネントを操作するためのクラス
|
|
51
|
+
* RAFTask.extension に保存する
|
|
52
|
+
*
|
|
53
|
+
* @template S
|
|
54
|
+
* @typedef {Object} CarouselController
|
|
55
|
+
*
|
|
56
|
+
* - ページ移動を行う (移動中の場合は割り込む)
|
|
57
|
+
* @property {(rafTask: RAFTask<S>, delta: number, skipSpeedRate?: number) => Promise<RAFTask<S>>} step
|
|
58
|
+
*
|
|
59
|
+
* @property {(rafTask: RAFTask<S>, index: number, skipSpeedRate?: number) => Pronise<RAFTask<S>>} moveTo
|
|
60
|
+
* - 指定インデックス番号に移動する (移動中の場合は割り込む)
|
|
61
|
+
*/
|
|
62
|
+
export interface CarouselController<S> {
|
|
63
|
+
step: (rafTask: RAFTask<S>, delta: number, skipSpeedRate?: number) => Promise<RAFTask<S>>;
|
|
64
|
+
moveTo: (RAFTask: RAFTask<S>, index: number, skipSpeedRate?: number) => Promise<RAFTask<S>>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Carousel Component
|
|
68
|
+
*
|
|
69
|
+
* @template S
|
|
70
|
+
* @param {Object} props - props
|
|
71
|
+
* @param {S} props.state - ステート
|
|
72
|
+
* @param {string} props.id - ユニークID (DOM id)
|
|
73
|
+
* @param {string[]} props.keyNames - RAFTask 配列までのパス
|
|
74
|
+
* @param {boolean} [props.controlButton] - ページ切り替えボタンを表示する (未実装)
|
|
75
|
+
* @param {boolean} [props.controlBar] - 現在位置を示すステータスバーを表示する
|
|
76
|
+
* @param {number} [skipSpeedRate] - skip 時に duration に乗じる値
|
|
77
|
+
* @param {any} children - 表示するページ (HTMLLIElement の子になる)
|
|
78
|
+
*/
|
|
79
|
+
export declare const Carousel: <S>(props: {
|
|
80
|
+
state: S;
|
|
81
|
+
id: string;
|
|
82
|
+
keyNames: string[];
|
|
83
|
+
controlButton?: boolean;
|
|
84
|
+
controlBar?: boolean;
|
|
85
|
+
skipSpeedRate?: number;
|
|
86
|
+
[key: string]: any;
|
|
87
|
+
}, children: any) => VNode<S>;
|
|
88
|
+
/**
|
|
89
|
+
* カルーセルを初期化し起動するエフェクト
|
|
90
|
+
*
|
|
91
|
+
* @param {string[]} keyNames - RAFTask 配列までのパス
|
|
92
|
+
* @param {CarouselState} carouselState - カルーセル情報
|
|
93
|
+
* @returns {(dispatch: Dispatch<S>) => void}
|
|
94
|
+
*/
|
|
95
|
+
export declare const effect_InitCarousel: <S>(keyNames: string[], carouselState: CarouselState<S>) => (dispatch: Dispatch<S>) => void;
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
2
|
+
// import
|
|
3
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
4
|
+
import { getValue, setValue, createLocalKey } from "../core/state";
|
|
5
|
+
import { el, deleteKeys } from "../core/component";
|
|
6
|
+
import { RAFTask } from "../animation/raf";
|
|
7
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
8
|
+
// Carousel Component
|
|
9
|
+
// ---------- ---------- ---------- ---------- ----------
|
|
10
|
+
// element
|
|
11
|
+
const div = el("div");
|
|
12
|
+
const ul = el("ul");
|
|
13
|
+
const li = el("li");
|
|
14
|
+
const button = el("button");
|
|
15
|
+
/**
|
|
16
|
+
* Carousel Component
|
|
17
|
+
*
|
|
18
|
+
* @template S
|
|
19
|
+
* @param {Object} props - props
|
|
20
|
+
* @param {S} props.state - ステート
|
|
21
|
+
* @param {string} props.id - ユニークID (DOM id)
|
|
22
|
+
* @param {string[]} props.keyNames - RAFTask 配列までのパス
|
|
23
|
+
* @param {boolean} [props.controlButton] - ページ切り替えボタンを表示する (未実装)
|
|
24
|
+
* @param {boolean} [props.controlBar] - 現在位置を示すステータスバーを表示する
|
|
25
|
+
* @param {number} [skipSpeedRate] - skip 時に duration に乗じる値
|
|
26
|
+
* @param {any} children - 表示するページ (HTMLLIElement の子になる)
|
|
27
|
+
*/
|
|
28
|
+
export const Carousel = function (props, children) {
|
|
29
|
+
var _a;
|
|
30
|
+
const { state, id, keyNames, controlButton, controlBar, skipSpeedRate } = props;
|
|
31
|
+
// get task
|
|
32
|
+
const task = getValue(state, keyNames, [])
|
|
33
|
+
.find(task => task.id === id);
|
|
34
|
+
// get carouselState and carouselController
|
|
35
|
+
const param = (_a = task === null || task === void 0 ? void 0 : task.extension) === null || _a === void 0 ? void 0 : _a.carouselState;
|
|
36
|
+
const controller = task === null || task === void 0 ? void 0 : task.extension.carouselController;
|
|
37
|
+
// get index
|
|
38
|
+
const index = (param === null || param === void 0 ? void 0 : param.reportPageIndex)
|
|
39
|
+
? getValue(state, param.reportPageIndex, 0)
|
|
40
|
+
: getValue(state, [createLocalKey(id), "reportPageIndex"], 0);
|
|
41
|
+
// children
|
|
42
|
+
const items = Array.isArray(children) ? children : [children];
|
|
43
|
+
// ---------- ---------- ----------
|
|
44
|
+
// action_mouseenter
|
|
45
|
+
// ---------- ---------- ----------
|
|
46
|
+
const action_mouseenter = (state) => {
|
|
47
|
+
const task = getValue(state, keyNames, [])
|
|
48
|
+
.find(task => task.id === id);
|
|
49
|
+
if (!task)
|
|
50
|
+
return state;
|
|
51
|
+
// 一時停止
|
|
52
|
+
task.paused = true;
|
|
53
|
+
return state;
|
|
54
|
+
};
|
|
55
|
+
// ---------- ---------- ----------
|
|
56
|
+
// action_mouseleave
|
|
57
|
+
// ---------- ---------- ----------
|
|
58
|
+
const action_mouseleave = (state) => {
|
|
59
|
+
const task = getValue(state, keyNames, [])
|
|
60
|
+
.find(task => task.id === id);
|
|
61
|
+
if (!task)
|
|
62
|
+
return state;
|
|
63
|
+
// 一時停止解除
|
|
64
|
+
task.paused = false;
|
|
65
|
+
return state;
|
|
66
|
+
};
|
|
67
|
+
// ---------- ---------- ----------
|
|
68
|
+
// action_prevPage
|
|
69
|
+
// ---------- ---------- ----------
|
|
70
|
+
const action_prevPage = (state) => {
|
|
71
|
+
const task = getValue(state, keyNames, [])
|
|
72
|
+
.find(task => task.id === id);
|
|
73
|
+
if (!task)
|
|
74
|
+
return state;
|
|
75
|
+
controller.step(task, -1, skipSpeedRate !== null && skipSpeedRate !== void 0 ? skipSpeedRate : 0.3);
|
|
76
|
+
return state;
|
|
77
|
+
};
|
|
78
|
+
// ---------- ---------- ----------
|
|
79
|
+
// action_nextPage
|
|
80
|
+
// ---------- ---------- ----------
|
|
81
|
+
const action_nextPage = (state) => {
|
|
82
|
+
const task = getValue(state, keyNames, [])
|
|
83
|
+
.find(task => task.id === id);
|
|
84
|
+
if (!task)
|
|
85
|
+
return state;
|
|
86
|
+
controller.step(task, 1, skipSpeedRate !== null && skipSpeedRate !== void 0 ? skipSpeedRate : 0.3);
|
|
87
|
+
return state;
|
|
88
|
+
};
|
|
89
|
+
// ---------- ---------- ----------
|
|
90
|
+
// action_controlBarClick
|
|
91
|
+
// ---------- ---------- ----------
|
|
92
|
+
const action_ControlBarClick = (state, absoluteIndex) => {
|
|
93
|
+
var _a;
|
|
94
|
+
const task = getValue(state, keyNames, [])
|
|
95
|
+
.find(task => task.id === id);
|
|
96
|
+
if (!task)
|
|
97
|
+
return state;
|
|
98
|
+
const param = (_a = task.extension) === null || _a === void 0 ? void 0 : _a.carouselState;
|
|
99
|
+
if (!param)
|
|
100
|
+
return state;
|
|
101
|
+
controller.moveTo(task, absoluteIndex, skipSpeedRate !== null && skipSpeedRate !== void 0 ? skipSpeedRate : 0.3);
|
|
102
|
+
return state;
|
|
103
|
+
};
|
|
104
|
+
// ---------- ---------- ----------
|
|
105
|
+
// VNode
|
|
106
|
+
// ---------- ---------- ----------
|
|
107
|
+
return div({
|
|
108
|
+
...deleteKeys(props, "state", "keyNames")
|
|
109
|
+
}, ul({
|
|
110
|
+
onmouseenter: action_mouseenter,
|
|
111
|
+
onmouseleave: action_mouseleave
|
|
112
|
+
}, items.map(item => li({}, item))),
|
|
113
|
+
// controlButton, controlBar
|
|
114
|
+
(controlButton || controlBar) && div({}, controlButton
|
|
115
|
+
? button({ onclick: action_prevPage }, "<")
|
|
116
|
+
: null, controlBar
|
|
117
|
+
? ul({}, items.map((_, i) => li({
|
|
118
|
+
class: i === index && "select",
|
|
119
|
+
onclick: [action_ControlBarClick, i]
|
|
120
|
+
},
|
|
121
|
+
// param が取れない場合、選択なしにする
|
|
122
|
+
param
|
|
123
|
+
? i === index ? "◉" : "・"
|
|
124
|
+
: "・")))
|
|
125
|
+
: ul({}), controlButton
|
|
126
|
+
? button({ onclick: action_nextPage }, ">")
|
|
127
|
+
: null));
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* カルーセルを初期化し起動するエフェクト
|
|
131
|
+
*
|
|
132
|
+
* @param {string[]} keyNames - RAFTask 配列までのパス
|
|
133
|
+
* @param {CarouselState} carouselState - カルーセル情報
|
|
134
|
+
* @returns {(dispatch: Dispatch<S>) => void}
|
|
135
|
+
*/
|
|
136
|
+
export const effect_InitCarousel = function (keyNames, carouselState) {
|
|
137
|
+
return (dispatch) => {
|
|
138
|
+
// どうしても画像ロードを待つ必要があるため、非同期処理に閉じ込めます
|
|
139
|
+
(async () => {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
// CarouselState, easing
|
|
142
|
+
const param = carouselState;
|
|
143
|
+
const easing = (_a = param.easing) !== null && _a !== void 0 ? _a : ((t) => t);
|
|
144
|
+
// check dom
|
|
145
|
+
const div = document.getElementById(param.id);
|
|
146
|
+
if (!div)
|
|
147
|
+
return;
|
|
148
|
+
const ul = div.querySelector("ul");
|
|
149
|
+
if (!ul)
|
|
150
|
+
return;
|
|
151
|
+
// cloneNode className
|
|
152
|
+
const cloneClass = `${param.id}_clone`;
|
|
153
|
+
// clear cloneNodes
|
|
154
|
+
const children = Array.from(ul.children)
|
|
155
|
+
.filter((li, i) => {
|
|
156
|
+
if (li.classList.contains(cloneClass)) {
|
|
157
|
+
li.remove();
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
li.setAttribute("absoluteIndex", `${i}`); // もう面倒だから、DOMに絶対値情報保存する
|
|
161
|
+
return true;
|
|
162
|
+
});
|
|
163
|
+
if (!children || children.length === 0)
|
|
164
|
+
return;
|
|
165
|
+
// 画像読み込み待機
|
|
166
|
+
const waitImages = async () => {
|
|
167
|
+
const images = Array.from(ul.querySelectorAll("img"));
|
|
168
|
+
return Promise.all(images.map(img => {
|
|
169
|
+
if (img.complete)
|
|
170
|
+
return Promise.resolve();
|
|
171
|
+
return new Promise(resolve => {
|
|
172
|
+
img.onload = () => resolve();
|
|
173
|
+
img.onerror = () => resolve();
|
|
174
|
+
});
|
|
175
|
+
}));
|
|
176
|
+
};
|
|
177
|
+
await waitImages();
|
|
178
|
+
// get widths (幅 + Margin)
|
|
179
|
+
const widths = children.map(child => {
|
|
180
|
+
const width = child.getBoundingClientRect().width;
|
|
181
|
+
const style = getComputedStyle(child);
|
|
182
|
+
const marginLeft = parseFloat(style.marginLeft);
|
|
183
|
+
const marginRight = parseFloat(style.marginRight);
|
|
184
|
+
return width + marginLeft + marginRight;
|
|
185
|
+
});
|
|
186
|
+
// get ul gap
|
|
187
|
+
const ulStyle = getComputedStyle(ul);
|
|
188
|
+
const gap = parseFloat(ulStyle.columnGap || ulStyle.gap || "0");
|
|
189
|
+
const ulGap = isNaN(gap) ? 0 : gap;
|
|
190
|
+
// reportIndex path
|
|
191
|
+
const reportPageIndex = (_b = param.reportPageIndex) !== null && _b !== void 0 ? _b : [createLocalKey(param.id), "reportPageIndex"];
|
|
192
|
+
// dispatch
|
|
193
|
+
dispatch((state) => {
|
|
194
|
+
// ---------- ---------- ----------
|
|
195
|
+
// CarouselPrivateState
|
|
196
|
+
// ---------- ---------- ----------
|
|
197
|
+
const privateParam = {
|
|
198
|
+
ul,
|
|
199
|
+
step: 0,
|
|
200
|
+
index: 0,
|
|
201
|
+
startOffset: 0,
|
|
202
|
+
targetOffset: 0,
|
|
203
|
+
currentOffset: 0,
|
|
204
|
+
cloneNodes: []
|
|
205
|
+
};
|
|
206
|
+
// ---------- ---------- ----------
|
|
207
|
+
// function getCurrentState
|
|
208
|
+
// ---------- ---------- ----------
|
|
209
|
+
/**
|
|
210
|
+
* 相対、絶対インデックスの取得
|
|
211
|
+
* 先頭オフセット値の取得
|
|
212
|
+
* 入れ替えが必要な DOM の数を取得
|
|
213
|
+
*/
|
|
214
|
+
const getCurrentState = () => {
|
|
215
|
+
let relativeIndex = -1;
|
|
216
|
+
let absoluteIndex = -1;
|
|
217
|
+
let offset = 0;
|
|
218
|
+
for (let i = 0, width = offset; i < privateParam.ul.children.length; i++) {
|
|
219
|
+
const li = privateParam.ul.children[i];
|
|
220
|
+
const index = Number(li.getAttribute("absoluteIndex"));
|
|
221
|
+
if (Math.abs(privateParam.currentOffset) >= width) {
|
|
222
|
+
relativeIndex = i;
|
|
223
|
+
absoluteIndex = index;
|
|
224
|
+
offset = privateParam.currentOffset + width;
|
|
225
|
+
}
|
|
226
|
+
// next
|
|
227
|
+
width += widths[absoluteIndex];
|
|
228
|
+
if (i !== 0)
|
|
229
|
+
width += ulGap;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
relativeIndex: relativeIndex,
|
|
233
|
+
absoluteIndex: absoluteIndex,
|
|
234
|
+
offset: offset,
|
|
235
|
+
toggleCount: privateParam.step < 0
|
|
236
|
+
? Math.abs(privateParam.step) - relativeIndex
|
|
237
|
+
: relativeIndex
|
|
238
|
+
};
|
|
239
|
+
}; // end getCurrentState
|
|
240
|
+
// ---------- ---------- ----------
|
|
241
|
+
// controller
|
|
242
|
+
// ---------- ---------- ----------
|
|
243
|
+
const controller = {
|
|
244
|
+
// ---------- ---------- ----------
|
|
245
|
+
// controller.step
|
|
246
|
+
// ---------- ---------- ----------
|
|
247
|
+
step: (rafTask, delta, skipSpeedRate) => {
|
|
248
|
+
// 一時停止
|
|
249
|
+
const paused = rafTask.paused;
|
|
250
|
+
rafTask.paused = true;
|
|
251
|
+
// result
|
|
252
|
+
return new Promise((resolve, reject) => {
|
|
253
|
+
// currentState
|
|
254
|
+
const currentState = getCurrentState();
|
|
255
|
+
// delete cloneNodes
|
|
256
|
+
privateParam.cloneNodes.forEach(node => node.remove());
|
|
257
|
+
privateParam.cloneNodes = [];
|
|
258
|
+
// DOM の入れ替え
|
|
259
|
+
for (let i = 0; i < currentState.toggleCount; i++) {
|
|
260
|
+
const node = privateParam.step < 0
|
|
261
|
+
? privateParam.ul.lastChild
|
|
262
|
+
: privateParam.ul.firstChild;
|
|
263
|
+
if (node) {
|
|
264
|
+
if (privateParam.step < 0) {
|
|
265
|
+
privateParam.ul.insertBefore(node, privateParam.ul.firstChild);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
privateParam.ul.appendChild(node);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// create cloneNodes
|
|
273
|
+
let cloneWidth = 0;
|
|
274
|
+
for (let i = 0; i < Math.abs(delta); i++) {
|
|
275
|
+
const index = delta < 0
|
|
276
|
+
? privateParam.ul.children.length - 1 - i
|
|
277
|
+
: i;
|
|
278
|
+
const cloneNode = privateParam.ul.children[index].cloneNode(true);
|
|
279
|
+
cloneNode.classList.add(cloneClass);
|
|
280
|
+
privateParam.cloneNodes.push(cloneNode);
|
|
281
|
+
if (delta < 0) {
|
|
282
|
+
privateParam.ul.insertBefore(cloneNode, privateParam.ul.firstChild);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
privateParam.ul.appendChild(cloneNode);
|
|
286
|
+
}
|
|
287
|
+
// get width
|
|
288
|
+
const absoluteIndex = Number(cloneNode.getAttribute("absoluteIndex"));
|
|
289
|
+
cloneWidth += widths[absoluteIndex];
|
|
290
|
+
// add gap
|
|
291
|
+
if (i !== 0)
|
|
292
|
+
cloneWidth += ulGap;
|
|
293
|
+
} // end create cloneNodes
|
|
294
|
+
// privateParamの調整
|
|
295
|
+
privateParam.step = delta;
|
|
296
|
+
privateParam.index = ((currentState.absoluteIndex + delta) % children.length + children.length) % children.length;
|
|
297
|
+
privateParam.startOffset = delta < 0
|
|
298
|
+
? currentState.offset - cloneWidth
|
|
299
|
+
: currentState.offset;
|
|
300
|
+
privateParam.currentOffset = privateParam.startOffset;
|
|
301
|
+
privateParam.targetOffset = delta < 0
|
|
302
|
+
? 0
|
|
303
|
+
: -cloneWidth;
|
|
304
|
+
// スタイル適用
|
|
305
|
+
privateParam.ul.style.transform = `translateX(${privateParam.currentOffset}px)`;
|
|
306
|
+
// newTask
|
|
307
|
+
const newTask = new RAFTask({
|
|
308
|
+
id: `${param.id}_step`,
|
|
309
|
+
duration: rafTask.duration * (skipSpeedRate !== null && skipSpeedRate !== void 0 ? skipSpeedRate : 0.1),
|
|
310
|
+
action,
|
|
311
|
+
finish: (state, rafTask) => {
|
|
312
|
+
rafTask.paused = paused;
|
|
313
|
+
const res = finish(state, rafTask);
|
|
314
|
+
const newState = Array.isArray(res)
|
|
315
|
+
? res[0]
|
|
316
|
+
: res;
|
|
317
|
+
// 一時停止状況の復元
|
|
318
|
+
rafTask.paused = paused;
|
|
319
|
+
resolve(rafTask);
|
|
320
|
+
return newState;
|
|
321
|
+
},
|
|
322
|
+
}); // end newTask
|
|
323
|
+
// dispatch
|
|
324
|
+
requestAnimationFrame(() => dispatch((state) => {
|
|
325
|
+
const tasks = getValue(state, keyNames, [])
|
|
326
|
+
.filter(task => task.id !== `${param.id}_step` && task.id !== param.id)
|
|
327
|
+
.concat(newTask);
|
|
328
|
+
return setValue(state, keyNames, tasks);
|
|
329
|
+
}));
|
|
330
|
+
});
|
|
331
|
+
}, // end controller.step
|
|
332
|
+
// ---------- ---------- ----------
|
|
333
|
+
// controller.moveTo
|
|
334
|
+
// ---------- ---------- ----------
|
|
335
|
+
moveTo: (rafTask, index, skipSpeedRate) => {
|
|
336
|
+
return controller.step(rafTask, index - getCurrentState().absoluteIndex, skipSpeedRate);
|
|
337
|
+
}
|
|
338
|
+
}; // end controller
|
|
339
|
+
// ---------- ---------- ----------
|
|
340
|
+
// task_action
|
|
341
|
+
// ---------- ---------- ----------
|
|
342
|
+
const action = (state, rafTask) => {
|
|
343
|
+
if (!privateParam.ul.isConnected)
|
|
344
|
+
return state;
|
|
345
|
+
if (rafTask.paused)
|
|
346
|
+
return state;
|
|
347
|
+
// privateParam.currentOffset の調整
|
|
348
|
+
privateParam.currentOffset = privateParam.startOffset
|
|
349
|
+
+ (privateParam.targetOffset - privateParam.startOffset)
|
|
350
|
+
* easing(rafTask.progress);
|
|
351
|
+
// style 適用
|
|
352
|
+
privateParam.ul.style.transform = `translateX(${privateParam.currentOffset}px)`;
|
|
353
|
+
return [state, (dispatch) => {
|
|
354
|
+
// action 割り込み
|
|
355
|
+
const fn = param.action;
|
|
356
|
+
if (fn)
|
|
357
|
+
requestAnimationFrame(() => dispatch((state) => [fn, rafTask]));
|
|
358
|
+
}];
|
|
359
|
+
};
|
|
360
|
+
// ---------- ---------- ----------
|
|
361
|
+
// task_finish
|
|
362
|
+
// ---------- ---------- ----------
|
|
363
|
+
const finish = (state, rafTask) => {
|
|
364
|
+
if (!privateParam.ul.isConnected)
|
|
365
|
+
return state;
|
|
366
|
+
// set reportPageIndex
|
|
367
|
+
let newState = setValue(state, reportPageIndex, privateParam.index);
|
|
368
|
+
// delete cloneNodes
|
|
369
|
+
privateParam.cloneNodes.forEach(node => node.remove());
|
|
370
|
+
privateParam.cloneNodes = [];
|
|
371
|
+
// DOM の入れ替え
|
|
372
|
+
for (let i = 0; i < Math.abs(privateParam.step); i++) {
|
|
373
|
+
const node = privateParam.step < 0
|
|
374
|
+
? privateParam.ul.lastChild
|
|
375
|
+
: privateParam.ul.firstChild;
|
|
376
|
+
if (privateParam.step < 0) {
|
|
377
|
+
privateParam.ul.insertBefore(node, privateParam.ul.firstChild);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
privateParam.ul.appendChild(node);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// set index
|
|
384
|
+
privateParam.step = param.step;
|
|
385
|
+
privateParam.index = ((privateParam.index + privateParam.step) % children.length + children.length) % children.length;
|
|
386
|
+
// add cloneNodes
|
|
387
|
+
let cloneWidth = 0;
|
|
388
|
+
for (let i = 0; i < Math.abs(privateParam.step); i++) {
|
|
389
|
+
const index = privateParam.step < 0
|
|
390
|
+
? privateParam.ul.children.length - 1 - i
|
|
391
|
+
: i;
|
|
392
|
+
const cloneNode = privateParam.ul.children[index].cloneNode(true);
|
|
393
|
+
cloneNode.classList.add(cloneClass);
|
|
394
|
+
privateParam.cloneNodes.push(cloneNode);
|
|
395
|
+
if (privateParam.step < 0) {
|
|
396
|
+
privateParam.ul.insertBefore(cloneNode, privateParam.ul.firstChild);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
privateParam.ul.appendChild(cloneNode);
|
|
400
|
+
}
|
|
401
|
+
// get width
|
|
402
|
+
const absoluteIndex = Number(cloneNode.getAttribute("absoluteIndex"));
|
|
403
|
+
cloneWidth += widths[absoluteIndex];
|
|
404
|
+
// add gap
|
|
405
|
+
if (i !== 0)
|
|
406
|
+
cloneWidth += ulGap;
|
|
407
|
+
}
|
|
408
|
+
// privateParam の調整
|
|
409
|
+
privateParam.startOffset = privateParam.step < 0
|
|
410
|
+
? -cloneWidth
|
|
411
|
+
: 0;
|
|
412
|
+
privateParam.targetOffset = privateParam.step < 0
|
|
413
|
+
? 0
|
|
414
|
+
: -cloneWidth;
|
|
415
|
+
privateParam.currentOffset = privateParam.startOffset;
|
|
416
|
+
// set dom
|
|
417
|
+
privateParam.ul.style.transform = `translateX(${privateParam.currentOffset}px)`;
|
|
418
|
+
newState = setValue(newState, keyNames, getValue(newState, keyNames, [])
|
|
419
|
+
.filter(task => task.id !== param.id)
|
|
420
|
+
.concat(createTask()));
|
|
421
|
+
return [newState, (dispatch) => {
|
|
422
|
+
// finish 割り込み
|
|
423
|
+
const fn = param.finish;
|
|
424
|
+
if (fn)
|
|
425
|
+
requestAnimationFrame(() => dispatch((state) => [fn, rafTask]));
|
|
426
|
+
}];
|
|
427
|
+
};
|
|
428
|
+
// ---------- ---------- ----------
|
|
429
|
+
// createTask
|
|
430
|
+
// ---------- ---------- ----------
|
|
431
|
+
const createTask = () => {
|
|
432
|
+
var _a, _b, _c;
|
|
433
|
+
return new RAFTask({
|
|
434
|
+
id: param.id,
|
|
435
|
+
groupID: param.groupID,
|
|
436
|
+
duration: (_a = param.duration) !== null && _a !== void 0 ? _a : 1000,
|
|
437
|
+
delay: (_b = param.delay) !== null && _b !== void 0 ? _b : 2000,
|
|
438
|
+
action,
|
|
439
|
+
finish,
|
|
440
|
+
priority: (_c = param.priority) !== null && _c !== void 0 ? _c : 0,
|
|
441
|
+
extension: {
|
|
442
|
+
...param.extension,
|
|
443
|
+
carouselState: param,
|
|
444
|
+
carouselController: controller
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}; // end createTask
|
|
448
|
+
// ---------- ---------- ----------
|
|
449
|
+
// startTask
|
|
450
|
+
// ---------- ---------- ----------
|
|
451
|
+
const startTask = new RAFTask({
|
|
452
|
+
id: param.id,
|
|
453
|
+
groupID: param.groupID,
|
|
454
|
+
duration: 0,
|
|
455
|
+
delay: 0,
|
|
456
|
+
action: (state, rafTask) => state,
|
|
457
|
+
finish,
|
|
458
|
+
extension: {
|
|
459
|
+
carouselState: param,
|
|
460
|
+
carouselController: controller
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
// ---------- ---------- ----------
|
|
464
|
+
// result
|
|
465
|
+
// ---------- ---------- ----------
|
|
466
|
+
return setValue(state, keyNames, getValue(state, keyNames, [])
|
|
467
|
+
.filter(task => task.id !== param.id)
|
|
468
|
+
.concat(startTask));
|
|
469
|
+
}); // end dispatch
|
|
470
|
+
})(); // end sync
|
|
471
|
+
}; // end result
|
|
472
|
+
}; // end effect
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Carousel, effect_InitCarousel } from "./carousel";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { VNode, Effect } from "hyperapp";
|
|
2
|
+
/**
|
|
3
|
+
* h 関数のラッパー
|
|
4
|
+
* 他でjsxを使用した場合、hが競合する可能性があるので作成した
|
|
5
|
+
*
|
|
6
|
+
* @template S
|
|
7
|
+
* @param {string} tag - タグ名
|
|
8
|
+
* @returns {(props:{ [key: string] any }, ...children:any[]) => VNode<S>}
|
|
9
|
+
*/
|
|
10
|
+
export declare const el: (tag: string) => <S>(props?: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}, ...children: any[]) => VNode<S>;
|
|
13
|
+
/**
|
|
14
|
+
* アクションを結合して結果を返す
|
|
15
|
+
*
|
|
16
|
+
* @template S
|
|
17
|
+
* @template E
|
|
18
|
+
* @param {undefined | (state: S, e: E) => S | [S, Effect<S>]} action - 結合するアクション
|
|
19
|
+
* @param {S} newState - 結合するステート
|
|
20
|
+
* @param {E} e - イベント (任意のイベント型)
|
|
21
|
+
* @returns {S | [S, Effect<S>]}
|
|
22
|
+
*/
|
|
23
|
+
export declare const concatAction: <S, E>(action: undefined | ((state: S, e: E) => S | [S, Effect<S>]), newState: S, e: E) => S | [S, Effect<S>];
|
|
24
|
+
/**
|
|
25
|
+
* props から classList を取得
|
|
26
|
+
*
|
|
27
|
+
* @param {Record<string, any>} props - props
|
|
28
|
+
* @returns {string[]}
|
|
29
|
+
*/
|
|
30
|
+
export declare const getClassList: (props: {
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
}) => string[];
|
|
33
|
+
/**
|
|
34
|
+
* props から不要なキーを削除する
|
|
35
|
+
*
|
|
36
|
+
* @template T
|
|
37
|
+
* @param {T} props - props
|
|
38
|
+
* @param {(keyof T)[])} keys - 削除するキー
|
|
39
|
+
* @returns {Omit<T, (typeof keys)[number]>}
|
|
40
|
+
*/
|
|
41
|
+
export declare const deleteKeys: <T extends Record<string, any>>(props: T, ...keys: (keyof T)[]) => Omit<T, (typeof keys)[number]>;
|
|
42
|
+
/**
|
|
43
|
+
* ステート内の文字とmatchした時、VNodeを返す
|
|
44
|
+
*
|
|
45
|
+
* @template S
|
|
46
|
+
* @param {Record<string, any>} props - props
|
|
47
|
+
* @param {S} props.state - ステート
|
|
48
|
+
* @param {string[]} props.keyNames - ステート内の文字までのパス
|
|
49
|
+
* @param {string} props.match - 一致判定する文字
|
|
50
|
+
* @param {any} children - 出力する内容 (VNode / 配列 / 文字など)
|
|
51
|
+
* @returns {VNode<S> | null}
|
|
52
|
+
*/
|
|
53
|
+
export declare const Route: <S>(props: {
|
|
54
|
+
state: S;
|
|
55
|
+
keyNames: string[];
|
|
56
|
+
match: string;
|
|
57
|
+
}, children: any) => VNode<S> | null;
|
|
58
|
+
/**
|
|
59
|
+
* クリックで、クラス名のselectをトグルするボタン
|
|
60
|
+
*
|
|
61
|
+
* @template S
|
|
62
|
+
* @param {Record<string, any>} props - props
|
|
63
|
+
* @param {S} props.state - ステート
|
|
64
|
+
* @param {string[]} props.keyNames - ステート内の文字配列までのパス
|
|
65
|
+
* @param {string} props.id - ユニークID
|
|
66
|
+
* @param {boolean} [props.reverse] - 反転選択するか
|
|
67
|
+
* @param {any} children - 子要素 (VNode / string / 配列など)
|
|
68
|
+
* @returns {VNode<S>}
|
|
69
|
+
*/
|
|
70
|
+
export declare const SelectButton: <S>(props: {
|
|
71
|
+
state: S;
|
|
72
|
+
keyNames: string[];
|
|
73
|
+
id: string;
|
|
74
|
+
reverse?: boolean;
|
|
75
|
+
[key: string]: any;
|
|
76
|
+
}, children: any) => VNode<S>;
|
|
77
|
+
/**
|
|
78
|
+
* クリックで、クラス名のselectを排他的に選択するボタン
|
|
79
|
+
*
|
|
80
|
+
* @template S
|
|
81
|
+
* @param {Record<string, any>} props - props
|
|
82
|
+
* @param {S} props.state - ステート
|
|
83
|
+
* @param {string[]} props.keyNames - ステート内の文字までのパス
|
|
84
|
+
* @param {string} props.id - ユニークID
|
|
85
|
+
* @param {boolean} [props.reverse] - 反転選択するか
|
|
86
|
+
* @param {any} children - 子要素 (VNode / string / 配列など)
|
|
87
|
+
* @returns {VNode<S>}
|
|
88
|
+
*/
|
|
89
|
+
export declare const OptionButton: <S>(props: {
|
|
90
|
+
state: S;
|
|
91
|
+
keyNames: string[];
|
|
92
|
+
id: string;
|
|
93
|
+
reverse?: boolean;
|
|
94
|
+
[key: string]: any;
|
|
95
|
+
}, children: any) => VNode<S>;
|