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.
@@ -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,2 @@
1
+ export type { CarouselState, CarouselController } from "./carousel";
2
+ export { Carousel, effect_InitCarousel } from "./carousel";
@@ -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>;