hyperapp-is 0.1.50 → 0.2.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.
Files changed (36) hide show
  1. package/README.md +220 -1557
  2. package/dist/{hyperapp-is/animation → animation}/easing.d.ts +4 -0
  3. package/dist/{hyperapp-is/animation → animation}/easing.js +4 -4
  4. package/dist/{hyperapp-is/animation → animation}/properties.d.ts +9 -16
  5. package/dist/{hyperapp-is/animation → animation}/properties.js +13 -12
  6. package/dist/{hyperapp-is/animation → animation}/raf.d.ts +11 -12
  7. package/dist/animation/raf.js +192 -0
  8. package/dist/core/component.d.ts +23 -0
  9. package/dist/core/component.js +52 -0
  10. package/dist/core/effects.d.ts +10 -0
  11. package/dist/core/effects.js +34 -0
  12. package/dist/core/state.d.ts +21 -0
  13. package/dist/{hyperapp-is/core → core}/state.js +15 -20
  14. package/dist/dom/dialog.d.ts +6 -0
  15. package/dist/dom/dialog.js +85 -0
  16. package/dist/dom/utils.d.ts +15 -0
  17. package/dist/dom/utils.js +19 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1 -0
  20. package/dist/services/google.d.ts +69 -0
  21. package/dist/services/google.js +170 -0
  22. package/package.json +14 -40
  23. package/dist/hyperapp-is/animation/raf.js +0 -209
  24. package/dist/hyperapp-is/animationView/carousel.d.ts +0 -48
  25. package/dist/hyperapp-is/animationView/carousel.js +0 -461
  26. package/dist/hyperapp-is/core/component.d.ts +0 -65
  27. package/dist/hyperapp-is/core/component.js +0 -242
  28. package/dist/hyperapp-is/core/navigator.d.ts +0 -115
  29. package/dist/hyperapp-is/core/navigator.js +0 -615
  30. package/dist/hyperapp-is/core/state.d.ts +0 -27
  31. package/dist/hyperapp-is/dom/utils.d.ts +0 -37
  32. package/dist/hyperapp-is/dom/utils.js +0 -69
  33. package/dist/hyperapp-is/index.d.ts +0 -16
  34. package/dist/hyperapp-is/index.js +0 -10
  35. package/dist/hyperapp-is/services/google.d.ts +0 -89
  36. package/dist/hyperapp-is/services/google.js +0 -178
@@ -1,3 +1,7 @@
1
+ /**
2
+ * RAFTask.progress に適用する
3
+ * イージング関数集
4
+ */
1
5
  export declare const progress_easing: {
2
6
  linear: (t: number) => number;
3
7
  easeInQuad: (t: number) => number;
@@ -1,7 +1,7 @@
1
- // hyperapp-is / animation / easing.ts
2
- // ---------- ---------- ---------- ---------- ----------
3
- // progress_easing
4
- // ---------- ---------- ---------- ---------- ----------
1
+ /**
2
+ * RAFTask.progress に適用する
3
+ * イージング関数集
4
+ */
5
5
  export const progress_easing = {
6
6
  // basic
7
7
  linear: (t) => t,
@@ -1,32 +1,25 @@
1
- import { Dispatch } from "hyperapp";
2
- import { InternalEffect, RAFTask } from "./raf";
1
+ import type { Dispatch, Effect } from "hyperapp";
2
+ import { RAFTask } from "./raf";
3
+ export type { CSSProperty };
4
+ export { createRAFProperties, effect_RAFProperties };
3
5
  /**
4
6
  * アニメーション進捗 (0〜1) を受け取り CSS 値を返す関数
5
7
  */
6
- export interface CSSProperty {
8
+ interface CSSProperty {
7
9
  [selector: string]: {
8
10
  [name: string]: (progress: number) => string;
9
11
  };
10
12
  }
11
- /**
12
- * CSSProperty[] から、doms と styles のセットに変換
13
- */
14
- export declare const createUnits: (properties: CSSProperty[]) => {
15
- doms: HTMLElement[];
16
- styles: {
17
- [name: string]: (progress: number) => string;
18
- };
19
- }[];
20
13
  /**
21
14
  * subscription_RAFManager をベースにした CSS アニメーション RAFTask を作成する
22
15
  * props は基本的に RAFTask の値
23
16
  */
24
- export declare const createRAFProperties: <S>(props: {
17
+ declare const createRAFProperties: <S>(props: {
25
18
  id: string;
26
19
  groupID?: string;
27
20
  duration: number;
28
21
  delay?: number;
29
- finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
22
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, Effect<S>];
30
23
  priority?: number;
31
24
  extension?: Record<string, any>;
32
25
  properties: CSSProperty[];
@@ -35,12 +28,12 @@ export declare const createRAFProperties: <S>(props: {
35
28
  * subscription_RAFManager をベースにした CSS アニメーションエフェクト
36
29
  * props は基本的に RAFTask の値
37
30
  */
38
- export declare const effect_RAFProperties: <S>(props: {
31
+ declare const effect_RAFProperties: <S>(props: {
39
32
  id: string;
40
33
  groupID?: string;
41
34
  duration: number;
42
35
  delay?: number;
43
- finish?: (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
36
+ finish?: (state: S, rafTask: RAFTask<S>) => S | [S, Effect<S>];
44
37
  priority?: number;
45
38
  extension?: Record<string, any>;
46
39
  properties: CSSProperty[];
@@ -1,13 +1,20 @@
1
- // hyperapp-is / animation / properties.ts
1
+ // ---------- ---------- ---------- ---------- ----------
2
+ // import
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ // hyprerapp-is
2
5
  import { getValue, setValue } from "../core/state";
3
6
  import { RAFTask } from "./raf";
7
+ export { createRAFProperties, effect_RAFProperties };
4
8
  // ---------- ---------- ---------- ---------- ----------
5
- // createUnits
9
+ // implementation
10
+ // ---------- ---------- ---------- ---------- ----------
11
+ // GPU_LAYER を適用させる CSS プロパティ
12
+ const GPU_LAYER = new Set(["transform", "opacity"]);
6
13
  // ---------- ---------- ---------- ---------- ----------
7
14
  /**
8
15
  * CSSProperty[] から、doms と styles のセットに変換
9
16
  */
10
- export const createUnits = function (properties) {
17
+ const createUnits = function (properties) {
11
18
  return properties.map(p => {
12
19
  const selector = Object.keys(p)[0];
13
20
  return {
@@ -17,20 +24,17 @@ export const createUnits = function (properties) {
17
24
  });
18
25
  };
19
26
  // ---------- ---------- ---------- ---------- ----------
20
- // createRAFProperties
21
- // ---------- ---------- ---------- ---------- ----------
22
27
  /**
23
28
  * subscription_RAFManager をベースにした CSS アニメーション RAFTask を作成する
24
29
  * props は基本的に RAFTask の値
25
30
  */
26
- export const createRAFProperties = function (props) {
31
+ const createRAFProperties = function (props) {
27
32
  const { id, groupID, duration, delay, priority, extension, properties } = props;
28
33
  // ---------- ---------- ----------
29
34
  // action
30
35
  // ---------- ---------- ----------
31
36
  const action = (state, rafTask) => {
32
- var _a;
33
- const progress = (_a = rafTask.progress) !== null && _a !== void 0 ? _a : 0;
37
+ const progress = rafTask.progress ?? 0;
34
38
  const units = createUnits(properties);
35
39
  // set styles
36
40
  units.forEach(unit => {
@@ -70,14 +74,11 @@ export const createRAFProperties = function (props) {
70
74
  });
71
75
  };
72
76
  // ---------- ---------- ---------- ---------- ----------
73
- // effect_RAFProperties
74
- // ---------- ---------- ---------- ---------- ----------
75
- const GPU_LAYER = new Set(["transform", "opacity"]);
76
77
  /**
77
78
  * subscription_RAFManager をベースにした CSS アニメーションエフェクト
78
79
  * props は基本的に RAFTask の値
79
80
  */
80
- export const effect_RAFProperties = function (props) {
81
+ const effect_RAFProperties = function (props) {
81
82
  const { id, groupID, duration, delay, finish, priority, extension, properties, keyNames } = props;
82
83
  // get doms
83
84
  const units = createUnits(properties);
@@ -1,17 +1,16 @@
1
- import { Effect, Subscription } from "hyperapp";
2
- import { Keys_ArrayRAFTask } from "../core/state";
3
- /**
4
- * 戻値としては返されないことを示したエフェクト
5
- * Effect の型エイリアス
6
- */
7
- export type InternalEffect<S> = Effect<S>;
1
+ import type { Effect, Subscription } from "hyperapp";
2
+ export type { RAFEvent };
3
+ export { RAFTask, subscription_RAFManager };
4
+ declare const _isStart: unique symbol;
8
5
  /**
9
6
  * RAFTask の action, finish
10
7
  * 型エイリアス
11
8
  */
12
- export type RAFEvent<S> = (state: S, rafTask: RAFTask<S>) => S | [S, InternalEffect<S>];
13
- declare const _isStart: unique symbol;
14
- export declare class RAFTask<S> {
9
+ type RAFEvent<S> = (state: S, rafTask: RAFTask<S>) => S | [S, Effect<S>];
10
+ /**
11
+ * requestAnimationFrame を利用して実行する、タスクを管理するクラス
12
+ */
13
+ declare class RAFTask<S> {
15
14
  #private;
16
15
  constructor(props: {
17
16
  id: string;
@@ -53,6 +52,6 @@ export declare class RAFTask<S> {
53
52
  }
54
53
  /**
55
54
  * RAFTask 配列の実行を管理するサブスクリプション
55
+ * keyNames には、RAFTask[] までのパスを指定する
56
56
  */
57
- export declare const subscription_RAFManager: <S>(state: S, keyNames: Keys_ArrayRAFTask) => Subscription<S>;
58
- export {};
57
+ declare const subscription_RAFManager: <S>(state: S, keyNames: string[]) => Subscription<S>;
@@ -0,0 +1,192 @@
1
+ // ---------- ---------- ---------- ---------- ----------
2
+ // import
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ // hyperapp-is
5
+ import { getValue, setValue } from "../core/state";
6
+ export { RAFTask, subscription_RAFManager };
7
+ // ---------- ---------- ---------- ---------- ----------
8
+ // implementation
9
+ // ---------- ---------- ---------- ---------- ----------
10
+ // Symbol
11
+ // subscription_RAFManager のみで使用される専用メソッド
12
+ // Symbol を知らない限り、モジュールの外からは呼べない
13
+ const _isStart = Symbol("RAFTask.isStart");
14
+ // ---------- ---------- ---------- ---------- ----------
15
+ /**
16
+ * requestAnimationFrame を利用して実行する、タスクを管理するクラス
17
+ */
18
+ class RAFTask {
19
+ // field
20
+ #id;
21
+ #groupID;
22
+ #duration;
23
+ #delay;
24
+ #action;
25
+ #finish;
26
+ #priority;
27
+ #extension;
28
+ #startTime;
29
+ #currentTime;
30
+ #pausedTime;
31
+ #paused;
32
+ #deltaTime;
33
+ #isDone;
34
+ // constructor
35
+ constructor(props) {
36
+ this.#id = props.id;
37
+ this.#groupID = props.groupID;
38
+ this.#duration = props.duration;
39
+ this.#delay = props.delay ?? 0;
40
+ this.#action = props.action;
41
+ this.#finish = props.finish;
42
+ this.#priority = props.priority ?? 0;
43
+ this.#extension = props.extension ?? {};
44
+ this.#isDone = false;
45
+ this.#paused = false;
46
+ }
47
+ // getter
48
+ get id() { return this.#id; }
49
+ get groupID() { return this.#groupID; }
50
+ get duration() { return this.#duration; }
51
+ get delay() { return this.#delay; }
52
+ get action() { return this.#action; }
53
+ get finish() { return this.#finish; }
54
+ get priority() { return this.#priority; }
55
+ get extension() { return this.#extension; }
56
+ get progress() {
57
+ if (this.#startTime === undefined || this.#currentTime === undefined)
58
+ return 0;
59
+ return Math.min(1, Math.max(0, (this.#currentTime - this.#startTime) /
60
+ Math.max(1, this.#duration)));
61
+ }
62
+ get deltaTime() { return this.#deltaTime ?? 0; }
63
+ get isDone() {
64
+ if (this.#isDone)
65
+ return true;
66
+ if (this.#pausedTime !== undefined)
67
+ return false;
68
+ return this.progress === 1;
69
+ }
70
+ get paused() { return this.#paused; }
71
+ // setter
72
+ set groupID(val) { this.#groupID = val; }
73
+ set priority(val) { this.#priority = val; }
74
+ set extension(val) { this.#extension = val; }
75
+ set isDone(val) { this.#isDone = val; }
76
+ set paused(val) { this.#paused = val; }
77
+ // ---------- ---------- ----------
78
+ // private method: _isStart
79
+ // ---------- ---------- ----------
80
+ /**
81
+ * アクションを開始して良いか判定する
82
+ * 現在時間等のアップデートも同時に行われる
83
+ * subscription_RAFManager でのみ使用される
84
+ */
85
+ [_isStart](now) {
86
+ // done
87
+ if (this.isDone)
88
+ return false;
89
+ // startTime
90
+ if (this.#startTime === undefined)
91
+ this.#startTime = now + this.#delay;
92
+ // pause
93
+ if (this.paused) {
94
+ if (this.#pausedTime === undefined)
95
+ this.#pausedTime = now;
96
+ this.#deltaTime = 0;
97
+ this.#currentTime = now;
98
+ return false;
99
+ }
100
+ // resume
101
+ if (!this.paused && this.#pausedTime !== undefined) {
102
+ this.#startTime = this.#startTime + now - this.#pausedTime;
103
+ this.#pausedTime = undefined;
104
+ }
105
+ // deltaTime
106
+ this.#deltaTime = now < this.#startTime
107
+ ? 0
108
+ : now - (this.#currentTime ?? now);
109
+ // currentTime
110
+ this.#currentTime = now;
111
+ // result
112
+ this.#isDone = this.progress === 1;
113
+ return !this.#isDone;
114
+ }
115
+ // ---------- ---------- ----------
116
+ // method: clone
117
+ // ---------- ---------- ----------
118
+ /**
119
+ * 時間を初期化したクローンを作成して返す
120
+ */
121
+ clone() {
122
+ return new RAFTask({
123
+ id: this.id,
124
+ groupID: this.groupID,
125
+ duration: this.duration,
126
+ delay: this.delay,
127
+ action: this.action,
128
+ finish: this.finish,
129
+ priority: this.priority,
130
+ extension: this.extension
131
+ });
132
+ }
133
+ }
134
+ // ---------- ---------- ---------- ---------- ----------
135
+ /**
136
+ * RAFTask 配列の実行を管理するサブスクリプション
137
+ * keyNames には、RAFTask[] までのパスを指定する
138
+ */
139
+ const subscription_RAFManager = function (state, keyNames) {
140
+ let rID = 0; // rAF timerID
141
+ // result
142
+ return [
143
+ (dispatch, payload) => {
144
+ if (payload.length === 0)
145
+ return () => {
146
+ if (rID !== 0)
147
+ cancelAnimationFrame(rID);
148
+ };
149
+ // rAF callback
150
+ const loop = (now) => {
151
+ dispatch((state) => {
152
+ const tasks = getValue(state, keyNames, []);
153
+ // newTasks
154
+ const newTasks = tasks.map(task => {
155
+ if (task.isDone)
156
+ return null;
157
+ // action
158
+ if (task[_isStart](now)) {
159
+ requestAnimationFrame(() => dispatch((state) => task.action(state, task)));
160
+ }
161
+ // finish
162
+ if (task.isDone) {
163
+ const fn = task.finish;
164
+ if (fn) {
165
+ requestAnimationFrame(() => dispatch((state) => fn(state, task)));
166
+ }
167
+ return null;
168
+ }
169
+ // next
170
+ return task;
171
+ }).filter(task => task !== null);
172
+ // next loop
173
+ if (newTasks.length !== 0)
174
+ rID = requestAnimationFrame(loop);
175
+ // set state
176
+ return setValue(state, keyNames, newTasks);
177
+ });
178
+ };
179
+ // set animation
180
+ rID = requestAnimationFrame(loop);
181
+ // finalize
182
+ return () => {
183
+ if (rID !== 0)
184
+ cancelAnimationFrame(rID);
185
+ };
186
+ },
187
+ // payload
188
+ getValue(state, keyNames, [])
189
+ .filter(task => !task.isDone)
190
+ .sort((a, b) => b.priority - a.priority)
191
+ ];
192
+ };
@@ -0,0 +1,23 @@
1
+ import type { VNode, Effect } from "hyperapp";
2
+ export { el, concatAction, getClassList, deleteKeys };
3
+ /**
4
+ * h 関数のラッパー
5
+ */
6
+ declare const el: <S = any>(tag: string) => (props?: {
7
+ [key: string]: any;
8
+ }, ...children: any[]) => VNode<S>;
9
+ /**
10
+ * アクションを結合する
11
+ * 結合したアクションは、1フレーム後に実行される
12
+ */
13
+ declare const concatAction: <S, E>(action: undefined | ((state: S, e: E) => S | [S, Effect<S>]), newState: S, e: E) => S | [S, Effect<S>];
14
+ /**
15
+ * props から クラスリストを取得する
16
+ */
17
+ declare const getClassList: (props: {
18
+ [key: string]: any;
19
+ }) => string[];
20
+ /**
21
+ * props から 指定されたキーを削除する
22
+ */
23
+ declare const deleteKeys: <T extends Record<string, any>>(props: T, ...keys: (keyof T)[]) => Omit<T, (typeof keys)[number]>;
@@ -0,0 +1,52 @@
1
+ // ---------- ---------- ---------- ---------- ----------
2
+ // import
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ import { h, text } from "hyperapp";
5
+ // ---------- ---------- ---------- ---------- ----------
6
+ // exports
7
+ // ---------- ---------- ---------- ---------- ----------
8
+ export { el, concatAction, getClassList, deleteKeys };
9
+ // ---------- ---------- ---------- ---------- ----------
10
+ // implementation
11
+ // ---------- ---------- ---------- ---------- ----------
12
+ /**
13
+ * h 関数のラッパー
14
+ */
15
+ const el = (tag) => (props, ...children) => h(tag, props ?? {}, children
16
+ .flat()
17
+ .filter(child => child !== null &&
18
+ child !== undefined)
19
+ .map((child) => typeof child === "object" ? child : text(`${child}`)));
20
+ // ---------- ---------- ---------- ---------- ----------
21
+ /**
22
+ * アクションを結合する
23
+ * 結合したアクションは、1フレーム後に実行される
24
+ */
25
+ const concatAction = function (action, newState, e) {
26
+ if (!action)
27
+ return newState;
28
+ const effect = (dispatch) => {
29
+ requestAnimationFrame(() => {
30
+ dispatch((state) => action(state, e));
31
+ });
32
+ };
33
+ return [newState, effect];
34
+ };
35
+ // ---------- ---------- ---------- ---------- ----------
36
+ /**
37
+ * props から クラスリストを取得する
38
+ */
39
+ const getClassList = (props) => {
40
+ return props.class
41
+ ? props.class.trim().split(" ").filter(Boolean)
42
+ : [];
43
+ };
44
+ // ---------- ---------- ---------- ---------- ----------
45
+ /**
46
+ * props から 指定されたキーを削除する
47
+ */
48
+ const deleteKeys = (props, ...keys) => {
49
+ const result = { ...props };
50
+ keys.forEach(key => delete result[key]);
51
+ return result;
52
+ };
@@ -0,0 +1,10 @@
1
+ import { Effect } from "hyperapp";
2
+ export { effect_toast };
3
+ /**
4
+ * 一定時間値を設定した後、元の値に戻す
5
+ */
6
+ declare const effect_toast: <S>(props: {
7
+ keyNames: string[];
8
+ value: any;
9
+ duration?: number;
10
+ }) => Effect<S>;
@@ -0,0 +1,34 @@
1
+ // ---------- ---------- ---------- ---------- ----------
2
+ // import
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ // hyperapp-is
5
+ import { getValue, setValue } from "./state";
6
+ // ---------- ---------- ---------- ---------- ----------
7
+ // exports
8
+ // ---------- ---------- ---------- ---------- ----------
9
+ export { effect_toast };
10
+ // ---------- ---------- ---------- ---------- ----------
11
+ // implementation
12
+ // ---------- ---------- ---------- ---------- ----------
13
+ /**
14
+ * 一定時間値を設定した後、元の値に戻す
15
+ */
16
+ const effect_toast = function (props) {
17
+ const { keyNames, value, duration = 2000 } = props;
18
+ const fn = (dispatch, thisValue) => {
19
+ setTimeout(() => {
20
+ dispatch((state) => {
21
+ if (getValue(state, keyNames, undefined) !== value)
22
+ return state;
23
+ return setValue(state, keyNames, thisValue);
24
+ });
25
+ }, duration);
26
+ }; // end fn
27
+ return (dispatch) => {
28
+ dispatch((state) => {
29
+ const thisValue = getValue(state, keyNames, undefined);
30
+ fn(dispatch, thisValue);
31
+ return setValue(state, keyNames, value);
32
+ });
33
+ };
34
+ };
@@ -0,0 +1,21 @@
1
+ export { getValue, setValue, getLocalState, setLocalState, createLocalKey };
2
+ /**
3
+ * state の keyNames をたどって値を取得する
4
+ */
5
+ declare const getValue: <S, D>(state: S, keyNames: string[], def: D) => D;
6
+ /**
7
+ * state の keyNames をたどって値を設定する
8
+ */
9
+ declare const setValue: <S>(state: S, keyNames: string[], value: any) => S;
10
+ /**
11
+ * ユニーク文字を作成する
12
+ */
13
+ declare const createLocalKey: (id: string) => string;
14
+ /**
15
+ * state にぶら下げられたローカルステートを取得する
16
+ */
17
+ declare const getLocalState: <S, T>(state: S, id: string, def: T) => T;
18
+ /**
19
+ * state にローカルステートをぶら下げる
20
+ */
21
+ declare const setLocalState: <S, T>(state: S, id: string, value: T) => S;
@@ -1,11 +1,14 @@
1
- // hyperapp-is / core / state.ts
2
1
  // ---------- ---------- ---------- ---------- ----------
3
- // getValue
2
+ // exports
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ export { getValue, setValue, getLocalState, setLocalState, createLocalKey };
5
+ // ---------- ---------- ---------- ---------- ----------
6
+ // implementation
4
7
  // ---------- ---------- ---------- ---------- ----------
5
8
  /**
6
- * パスを辿って、ステートから値を取得する
9
+ * state の keyNames をたどって値を取得する
7
10
  */
8
- export const getValue = function (state, keyNames, def) {
11
+ const getValue = function (state, keyNames, def) {
9
12
  let result = state;
10
13
  for (const key of keyNames) {
11
14
  if (result == null ||
@@ -21,12 +24,10 @@ export const getValue = function (state, keyNames, def) {
21
24
  return result;
22
25
  };
23
26
  // ---------- ---------- ---------- ---------- ----------
24
- // setValue
25
- // ---------- ---------- ---------- ---------- ----------
26
27
  /**
27
- * パスを辿って、ステートに値を設定して返す
28
+ * state の keyNames をたどって値を設定する
28
29
  */
29
- export const setValue = function (state, keyNames, value) {
30
+ const setValue = function (state, keyNames, value) {
30
31
  let result = { ...state };
31
32
  let current = result;
32
33
  for (let i = 0; i < keyNames.length; i++) {
@@ -47,19 +48,15 @@ export const setValue = function (state, keyNames, value) {
47
48
  return result;
48
49
  };
49
50
  // ---------- ---------- ---------- ---------- ----------
50
- // createLocalKey
51
- // ---------- ---------- ---------- ---------- ----------
52
51
  /**
53
- * IDからユニーク文字列を作成する
52
+ * ユニーク文字を作成する
54
53
  */
55
- export const createLocalKey = (id) => `local_key_${id}`;
56
- // ---------- ---------- ---------- ---------- ----------
57
- // getLocalState
54
+ const createLocalKey = (id) => `local_key_${id}`;
58
55
  // ---------- ---------- ---------- ---------- ----------
59
56
  /**
60
- * ステートから、ローカルステートを取得する
57
+ * state にぶら下げられたローカルステートを取得する
61
58
  */
62
- export const getLocalState = function (state, id, def) {
59
+ const getLocalState = function (state, id, def) {
63
60
  const localKey = createLocalKey(id);
64
61
  const obj = Object.prototype.hasOwnProperty.call(state, localKey)
65
62
  ? state[localKey]
@@ -70,12 +67,10 @@ export const getLocalState = function (state, id, def) {
70
67
  };
71
68
  };
72
69
  // ---------- ---------- ---------- ---------- ----------
73
- // setLocalState
74
- // ---------- ---------- ---------- ---------- ----------
75
70
  /**
76
- * ローカルステートを更新してステートを返す
71
+ * state にローカルステートをぶら下げる
77
72
  */
78
- export const setLocalState = function (state, id, value) {
73
+ const setLocalState = function (state, id, value) {
79
74
  const localKey = createLocalKey(id);
80
75
  const obj = Object.prototype.hasOwnProperty.call(state, localKey)
81
76
  ? state[localKey]
@@ -0,0 +1,6 @@
1
+ export { withLoadingDialog };
2
+ /**
3
+ * タスク実行中にローディングダイアログを表示する
4
+ * onCancel を指定した場合は、Esc キーで onCancel が呼び出される
5
+ */
6
+ declare const withLoadingDialog: <T>(task: () => Promise<T>, onCancel?: () => void) => Promise<T>;
@@ -0,0 +1,85 @@
1
+ // ---------- ---------- ---------- ---------- ----------
2
+ // exports
3
+ // ---------- ---------- ---------- ---------- ----------
4
+ export { withLoadingDialog };
5
+ // ---------- ---------- ---------- ---------- ----------
6
+ // implementation
7
+ // ---------- ---------- ---------- ---------- ----------
8
+ /**
9
+ * タスク実行中にローディングダイアログを表示する
10
+ * onCancel を指定した場合は、Esc キーで onCancel が呼び出される
11
+ */
12
+ const withLoadingDialog = async function (task, onCancel) {
13
+ // dialog
14
+ const dialog = document.createElement("dialog");
15
+ dialog.className = "withLoadingDialog";
16
+ // Esc
17
+ let canceled = false;
18
+ dialog.addEventListener("cancel", e => {
19
+ if (!onCancel) {
20
+ e.preventDefault();
21
+ return;
22
+ }
23
+ if (canceled)
24
+ return;
25
+ canceled = true;
26
+ onCancel();
27
+ });
28
+ dialog.style.margin = "auto auto";
29
+ dialog.style.padding = "0";
30
+ dialog.style.border = "0";
31
+ dialog.style.outline = "none";
32
+ dialog.style.backgroundColor = "transparent";
33
+ // svg
34
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
35
+ svg.setAttribute("viewBox", "0 -960 960 960");
36
+ svg.setAttribute("width", "24px");
37
+ svg.setAttribute("height", "24px");
38
+ svg.setAttribute("fill", "#1F1F1F");
39
+ svg.animate([
40
+ { transform: "rotate(0deg)" },
41
+ { transform: "rotate(360deg)" }
42
+ ], {
43
+ duration: 1000,
44
+ iterations: Infinity,
45
+ easing: "linear"
46
+ });
47
+ // path
48
+ const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
49
+ path.setAttribute("d", "M325-111.5q-73-31.5-127.5-86t-86-127.5Q80-398 80-480.5t31.5-155q31.5-72.5 86-127t127.5-86Q398-880 480-880q17 0 28.5 11.5T520-840q0 17-11.5 28.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160q133 0 226.5-93.5T800-480q0-17 11.5-28.5T840-520q17 0 28.5 11.5T880-480q0 82-31.5 155t-86 127.5q-54.5 54.5-127 86T480.5-80Q398-80 325-111.5Z");
50
+ // span
51
+ const span = document.createElement("span");
52
+ span.textContent = "Loading...";
53
+ span.style.marginLeft = "0.5rem";
54
+ // append
55
+ svg.appendChild(path);
56
+ dialog.appendChild(svg);
57
+ dialog.appendChild(span);
58
+ // result
59
+ let timerID = undefined;
60
+ try {
61
+ timerID = setTimeout(() => {
62
+ if (timerID === undefined)
63
+ return;
64
+ document.body.appendChild(dialog);
65
+ try {
66
+ dialog.showModal();
67
+ }
68
+ catch {
69
+ dialog.remove();
70
+ }
71
+ }, 250);
72
+ return await task();
73
+ }
74
+ finally {
75
+ // clear timer
76
+ if (timerID !== 0) {
77
+ clearTimeout(timerID);
78
+ timerID = undefined;
79
+ }
80
+ // remove dialog
81
+ if (dialog.open)
82
+ dialog.close();
83
+ dialog.remove();
84
+ }
85
+ };