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/README.md ADDED
@@ -0,0 +1,1254 @@
1
+ # hyperapp-is
2
+
3
+ Hyperapp で再利用可能なコンポーネントを作成するためのライブラリです
4
+ hyperapp-is の is は、is4416 の略です
5
+
6
+ [example](https://is4416.github.io/hyperapp-is/)
7
+ ※ 本ライブラリの実装サンプル
8
+
9
+ 本ライブラリは **イミュータブルなステート更新** と **シンプルな副作用管理** を前提として設計されています。
10
+ JSX を使用する場合は `hyperapp-jsx-pragma` を前提としています。
11
+
12
+ ## Functions / 関数リスト
13
+
14
+ **core / state.ts**
15
+ - [getValue](#getvalue)
16
+ - [setValue](#setvalue)
17
+ - [getLocalState](#getlocalstate)
18
+ - [setLocalState](#setlocalstate)
19
+ - [createLocalKey](#createlocalkey)
20
+
21
+ **core / component.ts**
22
+ - [el](#el)
23
+ - [concatAction](#concataction)
24
+ - [getClassList](#getclasslist)
25
+ - [deleteKeys](#deletekeys)
26
+ - [Route](#route)
27
+ - [SelectButton](#selectbutton)
28
+ - [OptionButton](#optionbutton)
29
+
30
+ **animation / step.ts**
31
+ - [effect_throwMessageStart](#effect_throwmessagestart)
32
+ - [effect_throwMessagePause](#effect_throwmessagepause--effect_throwmessageresume)
33
+ - [effect_throwMessageResume](#effect_throwmessagepause--effect_throwmessageresume)
34
+
35
+ **animation / raf.ts**
36
+ - [InternalEffect](#internaleffect)
37
+ - [RAFEvent](#rafevent)
38
+ - [RAFTask](#raftask)
39
+ - [subscription_RAFManager](#subscription_rafmanager)
40
+
41
+ **animation / properties.ts**
42
+ - [CSSProperty](#cssproperty)
43
+ - [createUnits](#createunits)
44
+ - [createRAFProperties](#createrafproperties)
45
+ - [effect_RAFProperties](#effect_rafproperties)
46
+
47
+ **animation / easing.ts**
48
+ - [progress_easing](#progress_easing)
49
+
50
+ **animation / translate.ts**
51
+ - [TranslateState](#translatestate)
52
+ - [createRAFTranslate](#createraftranslate)
53
+ - [effect_translateStart](#effect_translatestart)
54
+ - [effect_translateRollback](#effect_translaterollback)
55
+ - [effect_translateRollforward](#effect_translaterollforward)
56
+ - [effect_translateSlide](#effect_translateslide)
57
+
58
+ **animationView / carouselts**
59
+ - [CarouselState](#carouselstate)
60
+ - [CarouselController](#carouselcontroller)
61
+ - [Carousel](#carousel)
62
+ - [effect_InitCarousel](#effect_initcarousel)
63
+
64
+ **dom / utils.ts**
65
+ - [ScrollMargin](#scrollmargin)
66
+ - [getScrollMargin](#getscrollmargin)
67
+ - [MatrixState](#matrixstate)
68
+ - [getMatrixState](#getmatrixstate)
69
+ - [marquee](#marquee)
70
+
71
+ **dom / lifecycle.ts**
72
+ - [effect_setTimedValue](#effect_settimedvalue)
73
+ - [effect_nodesInitialize](#effect_nodesinitialize)
74
+ - [subscription_nodesCleanup](#subscription_nodescleanup)
75
+ - [subscription_nodesLifecycleByIds](#subscription_nodeslifecyclebyids)
76
+
77
+ ## Design / 設計方針
78
+
79
+ ### ライブラリの目的
80
+
81
+ Hyperapp はステートの形に制約がないため、コンポーネントを作る際にはどのステートを参照・更新するかを事前に決めておく必要があります。
82
+ 本ライブラリでは、コンポーネントに「目的の値がどこにあるか」を通知する設計を採用することにより、hyperapp の自由度を保ちつつ、再利用可能な構造を提供します。
83
+
84
+ ---
85
+
86
+ ### core / state.ts
87
+
88
+ 基本的なステート操作関数
89
+
90
+ - `getValue` / `setValue` : パスを指定して値を取得・設定
91
+ - `getLocalState` / `setLocalState` : コンポーネント内部の一時状態を ID キーで管理
92
+ - `createLocalKey` : ID からユニーク文字列を作成する
93
+
94
+ ---
95
+
96
+ ### core / component.ts
97
+
98
+ 基本コンポーネント設計関数
99
+
100
+ - `el` : hyperapp h 関数のラッパー
101
+ - `concatAction` : アクションを統合して結果を返す
102
+ - `getClassList` : props から classList を取得
103
+ - `deleteKeys` : props から不要なキーを削除
104
+ - `Route` : ステート内の文字と match した時、VNode を返す
105
+ - `SelectButton` / `OptionButton` : クリックで、クラス名 `select` をトグルするボタン
106
+
107
+ ---
108
+
109
+ ### animation / step.ts
110
+
111
+ タイマーを利用したアニメーションのステップ処理
112
+
113
+ - `effect_throwMessageStart` / `effect_throwMessagePause` / `effect_throwMessageResume` :
114
+ ステートに文字を1文字ずつ流し込むエフェクト
115
+
116
+ ---
117
+
118
+ ### animation / raf.ts
119
+
120
+ requestAnimationFrame を利用した処理
121
+
122
+ - `InternalEffect` : Dispatch の内部処理から呼び出されるエフェクトで、戻り値とならない
123
+ 設計意図を明示するための型エイリアス (型としては `Effect` と同一)
124
+ - `RAFEvent` : RAFTask のアクションイベント (型エイリアス)
125
+ - `RAFTask` : rAF タスクを管理するクラス
126
+ - `subscription_RAFManager` : RAFTask をフレームごとに実行させるサブスクリプション
127
+ タスクの並び替え・進捗管理・終了判定を一括で行う
128
+
129
+ ---
130
+
131
+ ### animation / properties.ts
132
+
133
+ rAF を利用した CSS設定
134
+
135
+ - `CSSProperty` : CSS 設定用オブジェクト
136
+ - `createUnits` : CSSProperty[] から doms と styles のセットに変換
137
+ - `createRAFProperties` : CSS アニメーション RAFTask を作成する
138
+ - `effect_RAFProperties` : rAF をベースにした、CSSアニメーションエフェクト
139
+
140
+ ---
141
+
142
+ ### animation / easing.ts
143
+
144
+ - `progress_easing` : easing プリセット
145
+
146
+ ---
147
+
148
+ ### animation / translate.ts
149
+
150
+ `RAFTask` をベースとした、カルーセル用のエフェクト
151
+
152
+ - `TranslateState` : Translate 管理用オブジェクト
153
+ - `createRAFTranslate` : Translate アニメーション RAFTask を作成する
154
+ - `effect_translateStart` : subscription_RAFManager をベースにした Translate アニメーションエフェクト
155
+ - `effect_translateRollback` : Translate中のアニメーションを元に戻すエフェクト
156
+ - `effect_translateRollforward` : Translate中のアニメーションを早送りするエフェクト
157
+ - `effect_translateSlide` : Translateを任意のインデックスまで移動する
158
+
159
+ ---
160
+
161
+ ### animationView / carousel.ts
162
+
163
+ `RAFTask` をベースとした、カルーセルコンポーネントセット (現在作成中)
164
+ *将来的には `animation/translate.ts` は廃止予定*
165
+
166
+ - `CarouselState` : Carousel 管理用オブジェクト
167
+ - `CarouselController` : Carousel を外部から操作するためのオブジェクト
168
+ - `Carousel` : Carousel コンポーネント (VNode)
169
+ - `effect_InitCarousel` : Carousel アニメーションを開始するためのエフェクト
170
+
171
+ ---
172
+
173
+ ### dom / utils
174
+
175
+ DOM を直接扱うユーティリティ
176
+
177
+ - `ScrollMargin` : スクロールの余白を管理するオブジェクト
178
+ - `getScrollMargin` : スクロールの余白を取得
179
+ - `MatrixState` : transform 情報
180
+ - `getMatrixState` : DOM から transfrom 情報を取得する
181
+ - `marquee` : Translate 風に DOM が流れるアニメーションを実行する
182
+
183
+ ---
184
+
185
+ ### dom / lifecycle.ts
186
+
187
+ DOM のライフサイクルを管理するための関数
188
+
189
+ - `effect_setTimedValue` : 存在時間制限付きの値をステートにセットするエフェクト
190
+ - `effect_nodesInitialize` : DOM 生成後にノードを初期化するためのエフェクト
191
+ - `subscription_nodesCleanup` : DOM が存在しない場合にクリーンアップ処理を行うためのサブスクリプション
192
+ - `subscription_nodesLifecycleByIds` : 登録された id を元に DOM を監視し、初期化・終了処理を行うためのサブスクリプション
193
+
194
+ ## source file / ソースファイル
195
+
196
+ ```
197
+ src
198
+ └ hyperapp-is
199
+ ├ index.ts
200
+
201
+ ├ core
202
+ │ ├ state.ts
203
+ │ │ getValue, setValue, getLocalState, setLocalState, createLocalKey
204
+ │ │
205
+ │ └ component.ts
206
+ │ el, concatAction, getClassList, deleteKeys
207
+ │ Route, SelectButton, OptionButton
208
+
209
+ ├ animation
210
+ │ ├ step.ts
211
+ │ │ effect_throwMessageStart, effect_throwMessagePause, effect_throwMessageResume
212
+ │ │
213
+ │ ├ raf.ts
214
+ │ │ InternalEffect
215
+ │ │ RAFEvent
216
+ │ │ RAFTask
217
+ │ │ subscription_RAFManager
218
+ │ │
219
+ │ ├ properties.ts
220
+ │ │ CSSProperty
221
+ │ │ createRAFProperties
222
+ │ │ effect_RAFProperties
223
+ │ │
224
+ │ ├ easing.ts
225
+ │ │ progress_easing
226
+ │ │
227
+ │ └ translate.ts
228
+ │ TranslateState
229
+ │ createRAFTranslate
230
+ │ effect_translateStart
231
+ │ effect_translateRollback
232
+ │ effect_translateRollforward
233
+ │ effect_translateSlide
234
+
235
+ ├ animationView
236
+ │ └ carousel.ts
237
+
238
+ └ dom
239
+ ├ utils.ts
240
+ │ ScrollMargin
241
+ │ getScrollMargin
242
+ │ MatrixState
243
+ │ getMatrixState
244
+ │ marquee
245
+
246
+ └ lifecycle.ts
247
+ effect_setTimedValue
248
+ effect_nodesInitialize
249
+ subscription_nodesCleanup
250
+ subscription_nodesLifecycleByIds
251
+ ```
252
+
253
+ ## hyperapp-is/core
254
+
255
+ ### getValue
256
+ パスを辿ってステートから値を取得
257
+ 安全にアクセス可能
258
+
259
+ ```ts
260
+ export const getValue = function <S, D> (
261
+ state : S,
262
+ keyNames: string[],
263
+ def : D
264
+ ): D
265
+ ```
266
+ *型保証は呼び出し側の責任*
267
+
268
+ - state : ステート
269
+ - keyNames: 値までのパス
270
+ - def : デフォルト値
271
+
272
+ ---
273
+
274
+ ### setValue
275
+ パスを辿ってステートに値を設定し、immutable な新しいステートを返す
276
+
277
+ ```ts
278
+ export const setValue = function <S> (
279
+ state : S,
280
+ keyNames: string[],
281
+ value : any
282
+ ): S
283
+ ```
284
+ - state : ステート
285
+ - keyNames: 値までのパス
286
+ - value : 設定する値
287
+
288
+ ---
289
+
290
+ ### getLocalState
291
+ ID に紐づいたローカルステートを取得
292
+
293
+ ```ts
294
+ export const getLocalState = function <S> (
295
+ state: S,
296
+ id : string,
297
+ def : { [key: string]: any }
298
+ ): { [key: string]: any }
299
+ ```
300
+
301
+ - state: ステート
302
+ - id : ユニークID
303
+ - def : 初期値
304
+
305
+ ---
306
+
307
+ ### setLocalState
308
+ ローカルステートを更新して新しいステートを返す
309
+
310
+ ```ts
311
+ export const setLocalState = function <S> (
312
+ state: S,
313
+ id : string,
314
+ value: { [key: string]: any }
315
+ ): S
316
+ ```
317
+
318
+ - state: ステート
319
+ - id : ユニークID
320
+ - value: 設定するローカルステート
321
+
322
+ ---
323
+
324
+ ### createLocalKey
325
+ ID からユニーク文字列を作成する
326
+
327
+ ```ts
328
+ export const createLocalKey = (id: string): string => `local_key_${ id }`
329
+ ```
330
+
331
+ ---
332
+
333
+ ### el
334
+ Hyperapp の h 関数ラッパー。JSX と競合する場合に使用
335
+ children の処理も同時に行っているため、本ライブラリでは VNode を作成する際に使用しています
336
+
337
+ ```ts
338
+ export const el = (tag: string) => <S> (
339
+ props ?: { [key: string]: any },
340
+ children?: Array
341
+ ): VNode<S>
342
+ ```
343
+
344
+ - tag: タグ名
345
+
346
+ ---
347
+
348
+ ### concatAction
349
+ アクションを結合して結果を返す
350
+ `effect_nodesInitialize` と組み合わせ可能
351
+
352
+ ```ts
353
+ export const concatAction = function <S, E> (
354
+ action : undefined | ((state: S, e: E) => S | [S, Effect<S>]),
355
+ newState: S,
356
+ e : E
357
+ ): S | [S, Effect<S>]
358
+ ```
359
+ *newStateを設定後、DOM描画を待ち、次の action に結合します*
360
+
361
+ - action : 結合するアクション
362
+ - newState: 結合するステート
363
+ - e : イベント (任意のイベント型)
364
+
365
+ ---
366
+
367
+ ### getClassList
368
+ props オブジェクトから classList を取得
369
+
370
+ ```ts
371
+ export const getClassList = (
372
+ props: { [key: string]: any }
373
+ ): string[]
374
+ ```
375
+
376
+ - props: props
377
+
378
+ ---
379
+
380
+ ### deleteKeys
381
+ props から不要なキーを除去
382
+
383
+ ```ts
384
+ export const deleteKeys = <T extends Record<string, any>> (
385
+ props : T,
386
+ ...keys: (keyof T)[]
387
+ ): Omit<T, (typeof keys)[number]>
388
+ ```
389
+
390
+ - props : props
391
+ - ...keys: 削除するキー
392
+
393
+ ---
394
+
395
+ ### Route
396
+ ステート値と一致した場合に VNode を返す
397
+ 条件付きレンダリングに利用
398
+
399
+ ```ts
400
+ export const Route = function <S> (
401
+ props: {
402
+ state : S
403
+ keyNames: string[]
404
+ match : string
405
+ },
406
+ children: any
407
+ ): VNode<S> | null
408
+ ```
409
+ *返値に `null` が設定された場合 `VNode` は生成されません*
410
+
411
+ - props : props
412
+ - props.state : ステート
413
+ - props.keyNames: ステート内の文字までのパス
414
+ - props.match : 一致判定する文字
415
+ - children : 出力する内容 (VNode / 配列 / 文字など)
416
+
417
+ ---
418
+
419
+ ### SelectButton
420
+ クラス名 `select` をトグルするボタン
421
+ 複数選択可能
422
+
423
+ ```ts
424
+ export const SelectButton = function <S> (
425
+ props: {
426
+ state : S
427
+ keyNames : string[]
428
+ id : string
429
+ reverse? : boolean
430
+ [key: string]: any
431
+ },
432
+ children: any
433
+ ): VNode<S>
434
+ ```
435
+ *クリックにより、クラス名 `select` がトグルされます*
436
+
437
+ - props : props
438
+ - props.state : ステート
439
+ - props.keyNames: ステート内の文字配列までのパス
440
+ - props.id : ユニークID
441
+ - props.reverse?: 反転選択するか
442
+ - children : 子要素 (VNode / string / 配列など)
443
+
444
+ ---
445
+
446
+ ### OptionButton
447
+ クラス名 `select` を単一選択で切り替えるボタン
448
+ 単一選択用
449
+
450
+ ```ts
451
+ export const OptionButton = function <S> (
452
+ props: {
453
+ state : S
454
+ keyNames : string[]
455
+ id : string
456
+ reverse? : boolean
457
+ [key: string]: any
458
+ },
459
+ children: any
460
+ ): VNode<S>
461
+ ```
462
+ *クリックにより、クラス名 `select` が排他的に選択されます*
463
+
464
+ - props : props
465
+ - props.state : ステート
466
+ - props.keyNames: ステート内の文字までのパス
467
+ - props.id : ユニークID
468
+ - props.reverse?: 反転選択するか
469
+ - children : 子要素 (VNode / string / 配列など)
470
+
471
+ ## hyperapp-is/animation
472
+
473
+ ### effect_throwMessageStart
474
+ 文字を一文字ずつ流し込むエフェクト
475
+
476
+ ```ts
477
+ export const effect_throwMessageStart = function <S> (
478
+ keyNames: string[],
479
+ id : string,
480
+ text : string,
481
+ interval: number,
482
+ ): (dispatch: Dispatch<S>) => void
483
+ ```
484
+
485
+ - keyNames: 値までのパス
486
+ - id : ユニークID
487
+ - text : 流し込む文字
488
+ - interval: 次の文字を流し込むまでの間隔 (ms)
489
+
490
+ ---
491
+
492
+ ### effect_throwMessagePause / effect_throwMessageResume
493
+ throwMessage を一時停止・再開
494
+
495
+ ```ts
496
+ export const effect_throwMessagePause = function <S> (
497
+ id: string
498
+ ): (dispatch: Dispatch<S>) => void
499
+ ```
500
+ ```ts
501
+ export const effect_throwMessageResume = function <S> (
502
+ id: string
503
+ ): (dispatch: Dispatch<S>) => void
504
+ ```
505
+
506
+ - id: ユニークID
507
+
508
+ ---
509
+
510
+ ### InternalEffect
511
+ Dispatch の内部処理(finish / action)から呼び出されることを前提としたエフェクト
512
+ Action の戻り値としては返されず、Dispatch の実行フロー内で直接実行される
513
+ 型としては `Effect<S>` と同一で「Dispatch 内部専用」という役割と設計意図を明示するための型エイリアス
514
+
515
+ ```ts
516
+ type InternalEffect<S> = Effect<S>
517
+ ```
518
+
519
+ **説明**
520
+
521
+ Dispatch で呼ばれるアクションでは、エフェクトを直接返すことはできません
522
+ しかし、非同期処理でエフェクトを使用したいこともあります
523
+
524
+ このときアクションを `(state: S) => S | [S, Effect<S>]` とせず `(state: S) => S | [S, InternalEffect<S>]`とすることで、エフェクトが戻り値とならないことを明示します ( Dispatch 内でエフェクトが戻せない罠対策です )
525
+ 具体的には `requestAnimationFrame` などを使用して時間差で Dispatch してください
526
+
527
+ **ポイント**
528
+
529
+ - 戻り値として使用されず、Dispatch 内でのみ実行される
530
+ - `Effect<S>` と同一
531
+ - 内部専用であることを、型で明示
532
+
533
+ **Dispatch例**
534
+
535
+ ```ts
536
+ return [state, (dispatch: Dispatch) => {
537
+ requestAnimationFrame(() =>
538
+ dispatch(state: S) => [state, effect]
539
+ )
540
+ }]
541
+ ```
542
+ *requestAnimationFrame などで、Dispatch 外部に移動した後、Dispatch します (どうしても1フレーム遅延します)*
543
+
544
+ ---
545
+
546
+ ### RAFEvent
547
+ RAFTask で使用されるイベント
548
+ hyperapp で使用される通常のアクション と同一なものですが
549
+ `payload` と `Effect` の型名が再定義されています
550
+
551
+ ```ts
552
+ type RAFEvent = <S> (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>]
553
+ ```
554
+
555
+ ---
556
+
557
+ ### RAFTask
558
+ requestAnimationFrame (rAF) を管理するためのクラス
559
+
560
+ ```ts
561
+ export class RAFTask <S> {
562
+ // constructor
563
+ constructor (props: {
564
+ id : string
565
+ groupID ?: string
566
+ duration : number
567
+ delay ?: number
568
+ action : RAFEvent<S>
569
+ finish ?: RAFEvent<S>
570
+ priority ?: number
571
+ extension?: { [key: string]: any }
572
+ })
573
+
574
+ // getter
575
+ id : string
576
+ duration : number
577
+ delay : number
578
+ action : RAFEvent<S>
579
+ finish : RAFEvent<S>
580
+ progress : number
581
+ deltaTime: number
582
+
583
+ // getter / setter
584
+ groupID : string | undefined
585
+ priority : number
586
+ extension: { [key: string]: any }
587
+ isDone : boolean
588
+ paused : boolean
589
+
590
+ // method
591
+ clone: RAFTask<S>
592
+ }
593
+ ```
594
+
595
+ **constructor**
596
+
597
+ 基本
598
+ - id : rAF のユニークID
599
+ - duration: 1回の実行時間 (ms)
600
+ - action : 毎フレームごとのアクション
601
+
602
+ 拡張
603
+ - groupID : 任意のグループID
604
+ - delay : 初回実行までの待機時間 (ms)
605
+ - finish : 最終フレームで実行されるアクション
606
+ - priority : 処理の優先順位
607
+ - extension: 任意の拡張データ
608
+
609
+ **property**
610
+
611
+ getter
612
+ - id : rAF のユニークID
613
+ - duration : 1回の実行時間 (ms)
614
+ - delay : 初回実行までの待機時間 (ms)
615
+ - action : 毎フレームごとのアクション
616
+ - finish : 最終フレームで実行されるアクション
617
+ - progress : 進捗状況 (0 - 1)
618
+ - deltaTime: 前回アクションからの経過時間 (ms)
619
+
620
+ getter / setter
621
+ - groupID : 任意のグループID
622
+ - priority : 処理の優先順位
623
+ - extension: 任意の拡張データ
624
+ - isDone : 終了状況の取得 / 設定
625
+ - paused : 一時停止状況の取得 / 設定
626
+
627
+ **method**
628
+
629
+ - clone: 時間を初期化したクローンを作成して返す
630
+
631
+ ---
632
+
633
+ ### subscription_RAFManager
634
+ RAFTask 配列をフレームごとに実行するサブスクリプション
635
+
636
+ ```ts
637
+ export const subscription_RAFManager = function <S> (
638
+ state : S,
639
+ keyNames: string[]
640
+ ): Subscription<S>
641
+ ```
642
+
643
+ - state : ステート
644
+ - keyNames: RAFTask 配列までのパス
645
+
646
+ [詳細説明](animation-system.md)
647
+
648
+ ---
649
+
650
+ ### CSSProperty
651
+ CSS設定用オブジェクト
652
+
653
+ ```ts
654
+ export interface CSSProperty {
655
+ [selector: string]: {
656
+ [name: string]: (progress: number) => string
657
+ }
658
+ }
659
+ ```
660
+
661
+ - selector: セレクター
662
+ - selector.[name] => fn
663
+ - name: CSS プロパティ名
664
+ - fn(progress): CSS 値を計算する関数
665
+
666
+ ---
667
+
668
+ ### createUnits
669
+ CSSProperty を変換する補助関数
670
+ selector から、doms を取得してセットにします
671
+
672
+ ```ts
673
+ export const createUnits = function (
674
+ properties: CSSProperty[]
675
+ ): {
676
+ doms : HTMLElement[],
677
+ styles: {
678
+ [name: string]: (progress: number) => string
679
+ }
680
+ }[]
681
+ ```
682
+
683
+ - properties: プロパティ配列
684
+
685
+ ---
686
+
687
+ ### createRAFProperties
688
+ subscription_RAFManager をベースにした CSS アニメーション RAFTask を作成する
689
+
690
+ ```ts
691
+ export const createRAFProperties = function <S> (
692
+ props: {
693
+ id : string
694
+ groupID?: string
695
+ duration: number
696
+ delay ?: number
697
+
698
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>]
699
+
700
+ priority ?: number
701
+ extension?: { [key: string]: any }
702
+
703
+ properties: CSSProperty[]
704
+ }
705
+ ): RAFTask<S>
706
+ ```
707
+
708
+ props は、基本的に RAFTask の値
709
+
710
+ - properties: セレクタとスタイル設定のセット配列
711
+
712
+ ---
713
+
714
+ ### effect_RAFProperties
715
+ CSS プロパティをフレーム単位で段階的に変更
716
+
717
+ ```ts
718
+ export const effect_RAFProperties = function <S>(
719
+ props: {
720
+ id : string
721
+ groupID?: string
722
+ duration: number
723
+ delay ?: number
724
+
725
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>]
726
+
727
+ priority ?: number
728
+ extension?: { [key: string]: any }
729
+
730
+ properties: CSSProperty[]
731
+ keyNames : string[]
732
+ }
733
+ ): (dispatch : Dispatch<S>) => void
734
+ ```
735
+
736
+ props は、基本的に RAFTask の値
737
+
738
+ - properties: セレクタとスタイル設定のセット配列
739
+ - keyNames : RAFTask 配列までのパス
740
+
741
+ ---
742
+
743
+ ### TranslateState
744
+ Translate 管理用オブジェクト
745
+
746
+ ```ts
747
+ export interface TranslateState {
748
+ width : number
749
+ index : number
750
+ total : number
751
+ easing: (t: number) => number
752
+ }
753
+ ```
754
+
755
+ - width : 移動量
756
+ - index : 先頭のインデックス
757
+ - total : 子の数
758
+ - easing: easing 関数
759
+
760
+ ---
761
+
762
+ ### createRAFTranslate
763
+ subscription_RAFManager をベースにした Translate アニメーション RAFTask を作成する
764
+
765
+ ```ts
766
+ export const createRAFTranslate = function <S> (
767
+ props: {
768
+ id : string
769
+ groupID?: string
770
+ duration: number
771
+ delay : number
772
+
773
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>]
774
+
775
+ priority ?: number
776
+ extension?: { [key: string]: any }
777
+
778
+ translateState: TranslateState
779
+ }
780
+ ): RAFTask<S>
781
+ ```
782
+
783
+ - props は、基本的に RAFTask の値
784
+ - translateState: Translate情報
785
+
786
+ ---
787
+
788
+ ### effect_translateStart
789
+ `subscription_RAFManager` をベースにした Translate アニメーションエフェクトです
790
+
791
+ ```ts
792
+ export const effect_translateStart = function <S> (
793
+ props: {
794
+ id : string
795
+ groupID?: string
796
+ duration: number
797
+ delay : number
798
+
799
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>]
800
+
801
+ priority ?: number
802
+ extension?: { [key: string]: any }
803
+
804
+ easing ?: (t: number) => number
805
+
806
+ keyNames: string[]
807
+ }
808
+ ): (dispatch: Dispatch<S>) => void
809
+ ```
810
+
811
+ - props は、基本的に RAFTask の値
812
+ - easing : easing 関数
813
+ - keyNames: RAFTask 配列までのパス
814
+
815
+ **説明**
816
+
817
+ marquee は単純な DOM に対しての副作用で、Translate としての動作は
818
+ ステート経由で rAF を制御しているこちらに集約されることになります
819
+
820
+ marquee はステートを通さず直接 DOM に対して副作用を発生させるため
821
+ 用途によっては marquee に優位性があります
822
+
823
+ - marquee : DOM 直接操作。軽量で即時反映
824
+ - effect_translateStart : Hyperapp のステート経由で管理。RAFManager と連携可能
825
+
826
+ ### effect_translateRollback
827
+ アニメーション中のTranslateを、元の位置に戻す
828
+
829
+ ```ts
830
+ export const effect_translateRollback = function <S> (
831
+ props: {
832
+ id : string
833
+ keyNames: string[]
834
+ paused ?: boolean
835
+ finish ?: RAFEvent<S>
836
+ }
837
+ ): (dispatch: Dispatch<S>)
838
+ ```
839
+
840
+ - id : ユニークID
841
+ - keyNames: RAFTask 配列までのパス
842
+ - paused : 実行後、一時停止するか
843
+ - finish : 実行後に呼び出されるイベント
844
+
845
+ **注意**
846
+ `effect_translateStart` に依存しています
847
+ 上記エフェクトでループしている id に対して使用します
848
+
849
+ ---
850
+
851
+ ### effect_translateRollforward
852
+ アニメーション中のTranslateを、早送りする
853
+
854
+ ```ts
855
+ export const effect_translateRollforward = function <S> (
856
+ props: {
857
+ id : string
858
+ keyNames: string[]
859
+ paused ?: boolean
860
+ finish ?: RAFEvent<S>
861
+ }
862
+ ): (dispatch: Dispatch<S>)
863
+ ```
864
+
865
+ - id : ユニークID
866
+ - keyNames: RAFTask 配列までのパス
867
+ - paused : 実行後、一時停止するか
868
+ - finish : 実行後に呼び出されるイベント
869
+
870
+ **注意**
871
+ `effect_translateStart` に依存しています
872
+ 上記エフェクトでループしている id に対して使用します
873
+
874
+ ---
875
+
876
+ ### effect_translateSlide
877
+ Translateを任意のインデックスまで移動する
878
+
879
+ ```ts
880
+ export const effect_translateSlide = function <S> (
881
+ props: {
882
+ id : string
883
+ keyNames: string[]
884
+ index : number
885
+ paused ?: boolean
886
+ finish ?: RAFEvent<S>
887
+ }
888
+ ): (dispatch: Dispatch<S>) => void
889
+ ```
890
+
891
+ - id : ユニークID
892
+ - keyNames: RAFTask 配列までのパス
893
+ - index : 移動先のインデックス
894
+ - paused : 実行後、一時停止するか
895
+ - finish : 実行後に呼び出されるイベント
896
+
897
+ **注意**
898
+ `effect_translateStart` に依存しています
899
+ 上記エフェクトでループしている id に対して使用します
900
+
901
+ ---
902
+
903
+ ### progress_easing
904
+ easing プリセット
905
+
906
+ ```ts
907
+ export const progress_easing = {
908
+
909
+ // basic
910
+ linear : (t: number) => t,
911
+ easeInQuad : (t: number) => t * t,
912
+ easeOutQuad : (t: number) => 1 - (1 - t) * (1 - t),
913
+ easeInOutQuad: (t: number) => t < 0.5
914
+ ? 2 * t * t
915
+ : 1 - Math.pow(-2 * t + 2, 2) / 2,
916
+
917
+ // cubic
918
+ easeInCubic : (t: number) => t * t * t,
919
+ easeOutCubic : (t: number) => 1 - Math.pow(1 - t, 3),
920
+ easeInOutCubic: (t: number) => t < 0.5
921
+ ? 4 * t * t * t
922
+ : 1 - Math.pow(-2 * t + 2, 3) / 2,
923
+
924
+ // quart
925
+ easeInQuart : (t: number) => t * t * t * t,
926
+ easeOutQuart : (t: number) => 1 - Math.pow(1 - t, 4),
927
+ easeInOutQuart: (t: number) => t < 0.5
928
+ ? 8 * t * t * t * t
929
+ : 1 - Math.pow(-2 * t + 2, 4) / 2,
930
+
931
+ // back (跳ねる)
932
+ easeOutBack: (t: number) => {
933
+ const c1 = 1.70158
934
+ const c3 = c1 + 1
935
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2)
936
+ },
937
+
938
+ // bounce
939
+ easeOutBounce: (t: number) => {
940
+ const n1 = 7.5625
941
+ const d1 = 2.75
942
+
943
+ if (t < 1 / d1) {
944
+ return n1 * t * t
945
+ } else if (t < 2 / d1) {
946
+ return n1 * (t -= 1.5 / d1) * t + 0.75
947
+ } else if (t < 2.5 / d1) {
948
+ return n1 * (t -= 2.25 / d1) * t + 0.9375
949
+ } else {
950
+ return n1 * (t -= 2.625 / d1) * t + 0.984375
951
+ }
952
+ },
953
+
954
+ // elastic
955
+ easeOutElastic: (t: number) => {
956
+ const c4 = (2 * Math.PI) / 3
957
+
958
+ return t === 0
959
+ ? 0
960
+ : t === 1
961
+ ? 1
962
+ : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1
963
+ }
964
+ }
965
+ ```
966
+
967
+ ## hyperapp-is/animationView
968
+
969
+ ### CarouselState
970
+ Carousel コンポーネント情報
971
+ RAFTask.extension に保存されます
972
+
973
+ ```ts
974
+ export interface CarouselState <S> {
975
+ id : string
976
+ step: number
977
+
978
+ // option
979
+ groupID ?: string
980
+ duration ?: number
981
+ delay ?: number
982
+ priority ?: number
983
+ extension?: { [key: string]: any }
984
+
985
+ // event
986
+ action?: RAFEvent<S>
987
+ finish?: RAFEvent<S>
988
+
989
+ // animation
990
+ easing?: (t: number) => number
991
+
992
+ // report
993
+ reportPageIndex?: string[]
994
+ }
995
+ ```
996
+ 基本的には `RAFTask` に準拠します
997
+ カルーセルを動作せるため `effect_InitCarousel` に渡すための値です
998
+
999
+ 必須項目
1000
+ - id: `Carousel` コンポーネントの id を指定してください
1001
+ - step: 移動するアイテムの数で、負の数は逆回転。0 は停止となります
1002
+
1003
+ 拡張項目
1004
+ - easing: アニメーションの動作を指定する関数
1005
+ 指定しない場合は `(t: number) => t` (linear) となります
1006
+
1007
+ - reportPagreIndex: 現在一番左端に表示されているアイテムのインデックスを受けるパス
1008
+ コントロールバーを自作したい時などに利用できます
1009
+
1010
+ ---
1011
+
1012
+ ### CarouselController
1013
+ 外部から Carousel コンポーネントを操作するためのクラス
1014
+ RAFTask.extension に保存されます
1015
+
1016
+ ```ts
1017
+ export interface CarouselController <S> {
1018
+ step : (rafTask: RAFTask<S>, delta: number, skipSpeedRate?: number) => Promise <RAFTask<S>>
1019
+ moveTo: (rafTask: RAFTask<S>, index: number, skipSpeedRage?: number) => Promise <RAFTask<S>>
1020
+ }
1021
+ ```
1022
+
1023
+ - step: `delta` で指定した方向にページを移動します (相対値)
1024
+ スキップ時のスピードは、変更前の `duration` に `skipSpeedRate` を乗じたものになります
1025
+ 終了時に処理を割り込ませたい場合は、`Promsie` により処理します
1026
+
1027
+ - moveTo: `index` で指定したページに移動します (絶対値)
1028
+ スキップ時のスピードは、変更前の `duration` に `skipSpeedRate` を乗じたものになります
1029
+ 終了時に処理を割り込ませたい場合は、`Promsie` により処理します
1030
+
1031
+ ### Carousel
1032
+ カルーセルコンポーネントです
1033
+ `CarouselState` を引数に `effect_InitCarousel` を実行することで動作開始します
1034
+ `subscription_RAFManager` を使用するので、予め `subscriptions` に追加してください
1035
+
1036
+ ```ts
1037
+ export const Carousel = function <S> (
1038
+ props: {
1039
+ state : S
1040
+ id : string
1041
+ keyNames : string[]
1042
+ controlButton?: boolean
1043
+ controlBar ?: boolean
1044
+ skipSpeedRate?: number
1045
+ [key: string] : any
1046
+ },
1047
+ children: any
1048
+ ): VNode<S>
1049
+ ```
1050
+
1051
+ - state : ステート
1052
+ - id : ユニークID (DOM の id)
1053
+ - keyNames : RAFTask 配列までのパス
1054
+ - controlButton: 操作ボタンを表示するか (未実装)
1055
+ - controlBar : 操作バーを表示するか
1056
+ - skipSpeedRate: スキップ時の動作速度
1057
+
1058
+ ### effect_InitCarousel
1059
+ カルーセルを初期化し起動するエフェクト
1060
+
1061
+ ```ts
1062
+ export const effect_InitCarousel = function <S> (
1063
+ keyNames : string[],
1064
+ carouselState: CarouselState<S>
1065
+ ): (dispatch: Dispatch<S>) => void
1066
+ ```
1067
+
1068
+ - keyNames : RAFTask 配列までのパス
1069
+ - carouselState: カルーセルの動作設定
1070
+
1071
+ ## hyperapp-is/dom
1072
+
1073
+ ### ScrollMargin
1074
+ スクロールの余白を管理するオブジェクト
1075
+
1076
+ ```ts
1077
+ export interface ScrollMargin {
1078
+ top : number
1079
+ left : number
1080
+ right : number
1081
+ bottom: number
1082
+ }
1083
+ ```
1084
+
1085
+ - top : 上までの余白
1086
+ - left : 左までの余白
1087
+ - right : 右までの余白
1088
+ - bottom: 下までの余白
1089
+
1090
+ ---
1091
+
1092
+ ### getScrollMargin
1093
+ スクロールの余白を取得
1094
+
1095
+ ```ts
1096
+ export const getScrollMargin = function (e: Event): ScrollMargin
1097
+ ```
1098
+
1099
+ - e: イベント
1100
+
1101
+ ---
1102
+
1103
+ ### MatrixState
1104
+ transform 情報
1105
+
1106
+ ```ts
1107
+ export interface MatrixState {
1108
+ translate: {
1109
+ x: number
1110
+ y: number
1111
+ z: number
1112
+ }
1113
+
1114
+ scale: {
1115
+ x: number
1116
+ y: number
1117
+ z: number
1118
+ }
1119
+
1120
+ // radian
1121
+ rotate: {
1122
+ x: number
1123
+ y: number
1124
+ z: number
1125
+ }
1126
+ }
1127
+ ```
1128
+
1129
+ ---
1130
+
1131
+ ### getMatrixState
1132
+ DOM から transfrom 情報を取得する
1133
+
1134
+ ```ts
1135
+ export const getMatrixState = (
1136
+ dom: HTMLElement
1137
+ ): MatrixState | null
1138
+ ```
1139
+
1140
+ - dom : 情報を取得する DOM
1141
+
1142
+ ---
1143
+
1144
+ ### marquee
1145
+ Translate 風に DOM が流れるアニメーションを実行します
1146
+
1147
+ ```ts
1148
+ export const marquee = function <S> (
1149
+ props: {
1150
+ ul : HTMLUListElement
1151
+ duration: number
1152
+ interval: number
1153
+ easing ?: (t: number) => number
1154
+ }
1155
+ ): { start: () => void, stop : () => void }
1156
+ ```
1157
+ *ステートから独立して `requestAnimationFrame` により直接 DOM を変更します*
1158
+
1159
+ **パラメータ**
1160
+ - props.ul : アニメーション対象の <ul> エレメント
1161
+ - props.duration: 実行時間 (ms)
1162
+ - props.interval: 待機時間 (ms)
1163
+ - props.easing : easing 関数
1164
+
1165
+ **戻値**
1166
+ - start(): アニメーションを開始
1167
+ - stop() : アニメーションを停止
1168
+
1169
+ ---
1170
+
1171
+ ### effect_setTimedValue
1172
+ ステートに存在時間制限付きの値を設定
1173
+
1174
+ ```ts
1175
+ export const effect_setTimedValue = function <S, T> (
1176
+ keyNames: string[],
1177
+ id : string,
1178
+ timeout : number,
1179
+ value : T,
1180
+ reset : T | null = null
1181
+ ): (dispatch: Dispatch<S>) => void
1182
+ ```
1183
+
1184
+ - keyNames: 値までのパス
1185
+ - id : ユニークID
1186
+ - timeout : 存在可能時間 (ms)
1187
+ - value : 一時的に設定する値
1188
+ - reset : タイムアウト後に設定する値
1189
+
1190
+ ---
1191
+
1192
+ ### effect_nodesInitialize
1193
+ VNode マウント後の初期化処理を実行
1194
+
1195
+ ```ts
1196
+ export const effect_nodesInitialize = function <S> (
1197
+ nodes: {
1198
+ id : string
1199
+ event: (state: S, element: Element) => S | [S, Effect<S>]
1200
+ }[]
1201
+ ): (dispatch: Dispatch<S>) => void
1202
+ ```
1203
+
1204
+ - nodes : 初期化対象ノード定義配列
1205
+ - nodes.id : ユニークID
1206
+ - nodes.event: 初期化イベント
1207
+
1208
+ ---
1209
+
1210
+ ### subscription_nodesCleanup
1211
+ DOM 消失時にクリーンアップ処理を実行
1212
+
1213
+ ```ts
1214
+ export const subscription_nodesCleanup = function <S>(
1215
+ nodes: {
1216
+ id : string
1217
+ finalize: (state: S) => S | [S, Effect<S>]
1218
+ }[]
1219
+ ): Subscription<S>[]
1220
+ ```
1221
+
1222
+ - nodes : クリーンアップ対象ノード定義配列
1223
+ - nodes.id : ユニークID
1224
+ - nodes.finalize: 終了時イベント
1225
+
1226
+ ---
1227
+
1228
+ ### subscription_nodesLifecycleByIds
1229
+ ステート上の ID 配列変化に応じて initialize / finalize を自動管理
1230
+
1231
+ ```ts
1232
+ export const subscription_nodesLifecycleByIds = function <S> (
1233
+ keyNames: string[],
1234
+ nodes: {
1235
+ id : string
1236
+ initialize: (state: S, element: Element | null) => S | [S, Effect<S>]
1237
+ finalize : (state: S, element: Element | null) => S | [S, Effect<S>]
1238
+ }[]
1239
+ ): Subscription<S>[]
1240
+ ```
1241
+
1242
+ - keyNames : 文字配列までのパス
1243
+ - nodes : 監視対象ノード定義配列
1244
+ - nodes.id : ユニークID
1245
+ - nodes.initialize: 初期化イベント
1246
+ - nodes.finalize : 終了時イベント
1247
+
1248
+ ## Notes
1249
+ - This library assumes immutable state updates.
1250
+ - Designed for Hyperapp with effect-based side effects.
1251
+ - JSX usage assumes `hyperapp-jsx-pragma`.
1252
+
1253
+ ## License
1254
+ MIT