peryl 1.5.2 → 1.5.4

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 (187) hide show
  1. package/README.md +31 -17
  2. package/demo/hsml-app-form-validation_demo.html +1 -0
  3. package/demo/hsml-app-form-validation_demo.ts +22 -23
  4. package/demo/hsml-app-form_demo.html +1 -0
  5. package/demo/hsml-app-form_demo.ts +24 -20
  6. package/demo/hsml-app-test_demo.ts +36 -41
  7. package/demo/hsml-app-tictactoe_demo.ts +17 -16
  8. package/demo/hsml-app_demo.html +1 -0
  9. package/demo/hsml-app_demo.ts +16 -16
  10. package/demo/hsml-appel_demo.html +7 -0
  11. package/demo/hsml-appel_demo.ts +47 -27
  12. package/demo/hsml-appi_demo.ts +15 -22
  13. package/demo/hsml_demo.ts +27 -22
  14. package/demo/js/hsml-app-js-happi_demo.html +28 -21
  15. package/demo/js/hsml-app-js_demo.html +15 -17
  16. package/dist/browser-esmodule/encode.js.map +1 -1
  17. package/dist/browser-esmodule/hsml-app.js +114 -123
  18. package/dist/browser-esmodule/hsml-app.js.map +1 -1
  19. package/dist/browser-esmodule/hsml-convert.js.map +1 -1
  20. package/dist/browser-esmodule/hsml-dom.js +3 -3
  21. package/dist/browser-esmodule/hsml-dom.js.map +1 -1
  22. package/dist/browser-esmodule/hsml-h.js.map +1 -1
  23. package/dist/browser-esmodule/hsml-html.js +2 -2
  24. package/dist/browser-esmodule/hsml-html.js.map +1 -1
  25. package/dist/browser-esmodule/hsml-idom.js +5 -5
  26. package/dist/browser-esmodule/hsml-idom.js.map +1 -1
  27. package/dist/browser-esmodule/hsml.js.map +1 -1
  28. package/dist/browser-esmodule/http.js.map +1 -1
  29. package/dist/browser-esmodule/index.js +118 -127
  30. package/dist/browser-esmodule/index.js.map +1 -1
  31. package/dist/browser-esmodule/router.js.map +1 -1
  32. package/dist/browser-umd/encode.js +1 -1
  33. package/dist/browser-umd/encode.js.map +1 -1
  34. package/dist/browser-umd/hsml-app.js +1 -1
  35. package/dist/browser-umd/hsml-app.js.map +1 -1
  36. package/dist/browser-umd/hsml-convert.js.map +1 -1
  37. package/dist/browser-umd/hsml-dom.js +1 -1
  38. package/dist/browser-umd/hsml-dom.js.map +1 -1
  39. package/dist/browser-umd/hsml-h.js.map +1 -1
  40. package/dist/browser-umd/hsml-html.js +1 -1
  41. package/dist/browser-umd/hsml-html.js.map +1 -1
  42. package/dist/browser-umd/hsml-idom.js +1 -1
  43. package/dist/browser-umd/hsml-idom.js.map +1 -1
  44. package/dist/browser-umd/hsml.js.map +1 -1
  45. package/dist/browser-umd/http.js +1 -1
  46. package/dist/browser-umd/http.js.map +1 -1
  47. package/dist/browser-umd/index.js +1 -1
  48. package/dist/browser-umd/index.js.map +1 -1
  49. package/dist/browser-umd/router.js +1 -1
  50. package/dist/browser-umd/router.js.map +1 -1
  51. package/dist/browser-umd/validators-moment.js +1 -1
  52. package/dist/browser-umd/validators-moment.js.map +1 -1
  53. package/dist/browser-umd/validators-numeral.js.map +1 -1
  54. package/dist/demo/encode_demo.ce182166.js.map +1 -1
  55. package/dist/demo/encode_demo.f40a44eb.js.map +1 -1
  56. package/dist/demo/hsml-app-form-validation_demo.8e406f15.js +2 -0
  57. package/dist/demo/hsml-app-form-validation_demo.8e406f15.js.map +1 -0
  58. package/dist/demo/hsml-app-form-validation_demo.9a95cff3.js +2 -0
  59. package/dist/demo/hsml-app-form-validation_demo.9a95cff3.js.map +1 -0
  60. package/dist/demo/hsml-app-form-validation_demo.c6856b02.js +2 -0
  61. package/dist/demo/hsml-app-form-validation_demo.c6856b02.js.map +1 -0
  62. package/dist/demo/hsml-app-form-validation_demo.fdcc0b2d.js +2 -0
  63. package/dist/demo/hsml-app-form-validation_demo.fdcc0b2d.js.map +1 -0
  64. package/dist/demo/hsml-app-form-validation_demo.html +1 -1
  65. package/dist/demo/hsml-app-form_demo.950b2a09.js +2 -0
  66. package/dist/demo/hsml-app-form_demo.950b2a09.js.map +1 -0
  67. package/dist/demo/hsml-app-form_demo.ea3af725.js +2 -0
  68. package/dist/demo/hsml-app-form_demo.ea3af725.js.map +1 -0
  69. package/dist/demo/hsml-app-form_demo.html +1 -1
  70. package/dist/demo/hsml-app-test_demo.36a210b8.js +2 -0
  71. package/dist/demo/hsml-app-test_demo.36a210b8.js.map +1 -0
  72. package/dist/demo/hsml-app-test_demo.6ab4ea94.js +2 -0
  73. package/dist/demo/hsml-app-test_demo.6ab4ea94.js.map +1 -0
  74. package/dist/demo/hsml-app-test_demo.html +1 -1
  75. package/dist/demo/hsml-app-tictactoe_demo.7a91c368.js +2 -0
  76. package/dist/demo/hsml-app-tictactoe_demo.7a91c368.js.map +1 -0
  77. package/dist/demo/hsml-app-tictactoe_demo.97905c2f.js +2 -0
  78. package/dist/demo/hsml-app-tictactoe_demo.97905c2f.js.map +1 -0
  79. package/dist/demo/hsml-app-tictactoe_demo.html +1 -1
  80. package/dist/demo/hsml-app_demo.b5c1d27d.js +2 -0
  81. package/dist/demo/hsml-app_demo.b5c1d27d.js.map +1 -0
  82. package/dist/demo/hsml-app_demo.bbebbbcf.js +2 -0
  83. package/dist/demo/hsml-app_demo.bbebbbcf.js.map +1 -0
  84. package/dist/demo/hsml-app_demo.html +1 -1
  85. package/dist/demo/hsml-appel_demo.4d9e135c.js +2 -0
  86. package/dist/demo/hsml-appel_demo.4d9e135c.js.map +1 -0
  87. package/dist/demo/hsml-appel_demo.7ddb6fb3.js +2 -0
  88. package/dist/demo/hsml-appel_demo.7ddb6fb3.js.map +1 -0
  89. package/dist/demo/hsml-appel_demo.html +1 -1
  90. package/dist/demo/hsml-appi_demo.e5e28a65.js +2 -0
  91. package/dist/demo/hsml-appi_demo.e5e28a65.js.map +1 -0
  92. package/dist/demo/hsml-appi_demo.fef950c1.js +2 -0
  93. package/dist/demo/hsml-appi_demo.fef950c1.js.map +1 -0
  94. package/dist/demo/hsml-appi_demo.html +1 -1
  95. package/dist/demo/hsml-convert_demo.0ea1fa3b.js.map +1 -1
  96. package/dist/demo/hsml-convert_demo.63e3e7b5.js.map +1 -1
  97. package/dist/demo/{hsml_demo.ff950ba1.js → hsml_demo.a248689a.js} +2 -2
  98. package/dist/demo/hsml_demo.a248689a.js.map +1 -0
  99. package/dist/demo/hsml_demo.eb3b08be.js +2 -0
  100. package/dist/demo/hsml_demo.eb3b08be.js.map +1 -0
  101. package/dist/demo/hsml_demo.html +1 -1
  102. package/dist/demo/http_demo.3e7da3d8.js.map +1 -1
  103. package/dist/demo/http_demo.8e435f23.js.map +1 -1
  104. package/dist/demo/i18n_demo.html +1 -1
  105. package/dist/demo/router_demo.3cfa03aa.js.map +1 -1
  106. package/dist/demo/router_demo.89ab1681.js.map +1 -1
  107. package/dist/demo/{validators_demo.252e13a6.js → validators_demo.90ff6001.js} +2 -2
  108. package/dist/demo/validators_demo.90ff6001.js.map +1 -0
  109. package/dist/demo/{validators_demo.66893723.js → validators_demo.ef5b2dea.js} +2 -2
  110. package/dist/demo/validators_demo.ef5b2dea.js.map +1 -0
  111. package/dist/demo/validators_demo.html +1 -1
  112. package/dist/encode.js +1 -1
  113. package/dist/encode.js.map +1 -1
  114. package/dist/hsml-app.d.ts +63 -42
  115. package/dist/hsml-app.js +110 -117
  116. package/dist/hsml-app.js.map +1 -1
  117. package/dist/hsml-convert.d.ts +3 -3
  118. package/dist/hsml-convert.js.map +1 -1
  119. package/dist/hsml-dom.d.ts +2 -2
  120. package/dist/hsml-dom.js +3 -3
  121. package/dist/hsml-dom.js.map +1 -1
  122. package/dist/hsml-h.d.ts +8 -8
  123. package/dist/hsml-h.js.map +1 -1
  124. package/dist/hsml-html.d.ts +4 -4
  125. package/dist/hsml-html.js +2 -2
  126. package/dist/hsml-html.js.map +1 -1
  127. package/dist/hsml-idom.d.ts +2 -2
  128. package/dist/hsml-idom.js +5 -5
  129. package/dist/hsml-idom.js.map +1 -1
  130. package/dist/hsml.d.ts +26 -27
  131. package/dist/hsml.js.map +1 -1
  132. package/dist/http.js +1 -1
  133. package/dist/http.js.map +1 -1
  134. package/dist/router.js +1 -1
  135. package/dist/router.js.map +1 -1
  136. package/package.json +8 -8
  137. package/src/hsml-app.ts +305 -197
  138. package/src/hsml-convert.ts +8 -8
  139. package/src/hsml-dom.ts +18 -18
  140. package/src/hsml-h.ts +10 -10
  141. package/src/hsml-html.ts +19 -19
  142. package/src/hsml-idom.ts +25 -25
  143. package/src/hsml.ts +46 -143
  144. package/demo/hsml-appc_demo.html +0 -16
  145. package/demo/hsml-appc_demo.ts +0 -49
  146. package/dist/demo/hsml-app-form-validation_demo.0b03b743.js +0 -2
  147. package/dist/demo/hsml-app-form-validation_demo.0b03b743.js.map +0 -1
  148. package/dist/demo/hsml-app-form-validation_demo.b3a5c810.js +0 -2
  149. package/dist/demo/hsml-app-form-validation_demo.b3a5c810.js.map +0 -1
  150. package/dist/demo/hsml-app-form-validation_demo.d3925067.js +0 -2
  151. package/dist/demo/hsml-app-form-validation_demo.d3925067.js.map +0 -1
  152. package/dist/demo/hsml-app-form-validation_demo.f757d763.js +0 -2
  153. package/dist/demo/hsml-app-form-validation_demo.f757d763.js.map +0 -1
  154. package/dist/demo/hsml-app-form_demo.007ffcaa.js +0 -2
  155. package/dist/demo/hsml-app-form_demo.007ffcaa.js.map +0 -1
  156. package/dist/demo/hsml-app-form_demo.a034239d.js +0 -2
  157. package/dist/demo/hsml-app-form_demo.a034239d.js.map +0 -1
  158. package/dist/demo/hsml-app-test_demo.35c14dc9.js +0 -2
  159. package/dist/demo/hsml-app-test_demo.35c14dc9.js.map +0 -1
  160. package/dist/demo/hsml-app-test_demo.3c7e16ae.js +0 -2
  161. package/dist/demo/hsml-app-test_demo.3c7e16ae.js.map +0 -1
  162. package/dist/demo/hsml-app-tictactoe_demo.5f4861c1.js +0 -2
  163. package/dist/demo/hsml-app-tictactoe_demo.5f4861c1.js.map +0 -1
  164. package/dist/demo/hsml-app-tictactoe_demo.7deeabad.js +0 -2
  165. package/dist/demo/hsml-app-tictactoe_demo.7deeabad.js.map +0 -1
  166. package/dist/demo/hsml-app_demo.87d83c29.js +0 -2
  167. package/dist/demo/hsml-app_demo.87d83c29.js.map +0 -1
  168. package/dist/demo/hsml-app_demo.941a13a6.js +0 -2
  169. package/dist/demo/hsml-app_demo.941a13a6.js.map +0 -1
  170. package/dist/demo/hsml-appc_demo.0234ff15.js +0 -2
  171. package/dist/demo/hsml-appc_demo.0234ff15.js.map +0 -1
  172. package/dist/demo/hsml-appc_demo.f5783031.js +0 -2
  173. package/dist/demo/hsml-appc_demo.f5783031.js.map +0 -1
  174. package/dist/demo/hsml-appc_demo.html +0 -1
  175. package/dist/demo/hsml-appel_demo.0e8a4d4c.js +0 -2
  176. package/dist/demo/hsml-appel_demo.0e8a4d4c.js.map +0 -1
  177. package/dist/demo/hsml-appel_demo.1a5c2c26.js +0 -2
  178. package/dist/demo/hsml-appel_demo.1a5c2c26.js.map +0 -1
  179. package/dist/demo/hsml-appi_demo.2c3fb511.js +0 -2
  180. package/dist/demo/hsml-appi_demo.2c3fb511.js.map +0 -1
  181. package/dist/demo/hsml-appi_demo.427fdebd.js +0 -2
  182. package/dist/demo/hsml-appi_demo.427fdebd.js.map +0 -1
  183. package/dist/demo/hsml_demo.33f28c29.js +0 -2
  184. package/dist/demo/hsml_demo.33f28c29.js.map +0 -1
  185. package/dist/demo/hsml_demo.ff950ba1.js.map +0 -1
  186. package/dist/demo/validators_demo.252e13a6.js.map +0 -1
  187. package/dist/demo/validators_demo.66893723.js.map +0 -1
package/src/hsml-app.ts CHANGED
@@ -5,31 +5,60 @@ const log = console.log;
5
5
  const error = console.error;
6
6
  const warn = console.warn;
7
7
 
8
- export type HState<STATE> = () => STATE;
9
- export type HView<STATE> = (state: STATE) => HElements;
10
- export type HView1<STATE> = (state: STATE) => HElement;
8
+ export type HState<State> = () => State;
9
+
10
+ export type HView<State, HActionType extends string> = (
11
+ state: State
12
+ ) => HElements<HActionType>;
13
+
14
+ export type HView1<State, HActionType extends string> = (
15
+ state: State
16
+ ) => HElement<HActionType>;
17
+
18
+ export type HAppActionType =
19
+ | "happ-init"
20
+ | "happ-mount"
21
+ | "happ-umount"
22
+ | "happ-update"
23
+ | "happ-action"
24
+ | "happ-attribute";
25
+
26
+ export enum HAppActions {
27
+ init = "happ-init",
28
+ mount = "happ-mount",
29
+ umount = "happ-umount",
30
+ update = "happ-update",
31
+ action = "happ-action",
32
+ attribute = "happ-attribute"
33
+ }
11
34
 
12
- export interface HAction {
13
- type: string;
35
+ export interface HAction<HActionType extends string> {
36
+ type: HActionType | HAppActionType | HAppActions;
14
37
  data?: any;
15
38
  event?: Event;
16
39
  }
17
40
 
18
- export type HDispatch = (type: HAction["type"],
19
- data?: HAction["data"],
20
- event?: HAction["event"]) => Promise<void>;
41
+ export type HDispatchScope =
42
+ | "element"
43
+ | "window";
21
44
 
22
- export type HUpdate = () => void;
45
+ export enum HDispatchScopes {
46
+ element = "element",
47
+ window = "window"
48
+ }
23
49
 
24
- export type HDispatcher<STATE> = (action: HAction, state: STATE, dispatch: HDispatch) => Promise<void>;
25
- // export type HDispatcher<STATE> = (this: HApp<STATE>, action: HAction, state: STATE, dispatch: HDispatch) => Promise<void>;
50
+ export type HDispatch<HActionType extends string> = (
51
+ type: HAction<HActionType>["type"],
52
+ data?: HAction<HActionType>["data"],
53
+ scope?: HDispatchScope | HDispatchScopes
54
+ ) => Promise<void>;
26
55
 
27
- export enum HAppAction {
28
- _init = "_init",
29
- _mount = "_mount",
30
- _umount = "_umount",
31
- _element = "_element"
32
- }
56
+ export type HDispatcher<State, HActionType extends string> = (
57
+ // this: HApp<State, HActionType>,
58
+ action: HAction<HActionType>,
59
+ state: State,
60
+ dispatch: HDispatch<HActionType>
61
+ ) => Promise<void>;
33
62
 
34
63
  const schedule = window.requestAnimationFrame ||
35
64
  // window.webkitRequestAnimationFrame ||
@@ -45,164 +74,254 @@ const unschedule = window.cancelAnimationFrame ||
45
74
  // (window as any).msCancelAnimationFrame ||
46
75
  function (handle: number) { window.clearTimeout(handle); };
47
76
 
48
- const msgAction = "HApp action:";
49
- const msgDispatch = "HApp dispatch:";
50
- const msgRender = "HApp render:";
51
- const msgUpdate = "HApp update:";
52
-
53
- export function happ<STATE>(state: HState<STATE>,
54
- view: HView<STATE>,
55
- dispatcher: HDispatcher<STATE>,
56
- element: Element | string | null = document.body) {
57
- return new HApp<STATE>(state, view, dispatcher, element);
58
- }
59
-
60
- // HAppI
77
+ const msgAction = "action:";
78
+ const msgDispatch = "dispatch:";
79
+ const msgRender = "render:";
80
+ const msgUpdate = "update:";
61
81
 
62
- export type Class<T = object> = new (...args: any[]) => T;
82
+ const HAPP = "happ";
63
83
 
64
- export interface HAppI<STATE> {
65
- state(): STATE;
66
- view(state: STATE): HElements;
67
- dispatcher(action: HAction, state: STATE, dispatch: HDispatch): Promise<void>;
68
- // dispatcher(this: HApp<STATE>, action: HAction, state: STATE, dispatch: HDispatch): Promise<void>;
84
+ export interface HAppI<State, HActionType extends string> {
85
+ state: HState<State>;
86
+ view: HView<State, HActionType>;
87
+ dispatcher: HDispatcher<State, HActionType>;
88
+ element?: Element | string | null;
89
+ debug?: boolean;
90
+ name?: string;
91
+ attributes?: string[];
69
92
  }
70
93
 
71
- export function happi<STATE>(hAppI: Class<HAppI<STATE>>, e: Element | string | null = document.body) {
72
- const hapi = new hAppI();
73
- return new HApp<STATE>(hapi.state, hapi.view, hapi.dispatcher, e);
94
+ /**
95
+ * HApp definition
96
+ *
97
+ * @param hAppI HApp definition
98
+ * @returns HApp instance
99
+ */
100
+ export function happ<State, HActionType extends string>(hAppI: {
101
+ state: HState<State>;
102
+ view: HView<State, HActionType>;
103
+ dispatcher: HDispatcher<State, HActionType>;
104
+ element: Element | string | null;
105
+ debug?: boolean;
106
+ name?: string;
107
+ // attributes?: string[];
108
+ }) {
109
+ return new HApp<State, HActionType>(
110
+ hAppI.state,
111
+ hAppI.view,
112
+ hAppI.dispatcher,
113
+ hAppI.element,
114
+ hAppI.debug,
115
+ hAppI.name
116
+ // hAppI!.attributes
117
+ );
74
118
  }
75
119
 
76
- // HAppEl
77
-
78
- export function happel<STATE>(elementName: string,
79
- elementAttrs: string[],
80
- state: HState<STATE>,
81
- view: HView<STATE>,
82
- dispatcher: HDispatcher<STATE>): void {
83
- customElements.define(elementName, class HAppElement extends HTMLElement {
120
+ // export type Class<T = object> = new (...args: any[]) => T;
121
+
122
+ // export function happi<State, HActionType extends string>(
123
+ // hAppI: Class<HAppI<State, HActionType>>,
124
+ // element?: Element | string | null,
125
+ // debug? boolean,
126
+ // name?: string,
127
+ // attributes: string[]
128
+ // ) {
129
+ // const hapi = new hAppI();
130
+ // return new HApp<State, HActionType>(
131
+ // hapi.state,
132
+ // hapi.view,
133
+ // hapi.dispatcher,
134
+ // element,
135
+ // debug
136
+ // );
137
+ // }
84
138
 
85
- static get observedAttributes() {
86
- return elementAttrs;
87
- }
139
+ // HAppEl
88
140
 
89
- private _happel: HApp<STATE>;
141
+ /**
142
+ * HApp custom HTML element definition.
143
+ *
144
+ * @param hAppI HApp definition
145
+ */
146
+ export function happel<State, HActionType extends string>(hAppI: {
147
+ state: HState<State>;
148
+ view: HView<State, HActionType>;
149
+ dispatcher: HDispatcher<State, HActionType>;
150
+ /** Element suffix name, element name patern is `happ-${name}` */
151
+ name: string;
152
+ /** Element attribute list */
153
+ attributes: string[];
154
+ debug?: boolean;
155
+ }): void {
156
+ customElements.define(
157
+ `${HAPP}-${hAppI.name}`,
158
+ class HAppElement extends HTMLElement {
159
+ static get observedAttributes() {
160
+ return hAppI.attributes;
161
+ }
90
162
 
91
- constructor() {
92
- super();
93
- this._happel = new HApp<STATE>(state, view, dispatcher);
94
- (this._happel as any).customElement = this;
95
- }
163
+ private _happel: HApp<State, HActionType>;
164
+
165
+ constructor() {
166
+ super();
167
+ this._happel = new HApp<State, HActionType>(
168
+ hAppI.state,
169
+ hAppI.view,
170
+ hAppI.dispatcher,
171
+ undefined,
172
+ hAppI.debug,
173
+ hAppI.name,
174
+ hAppI.attributes
175
+ );
176
+ (this._happel as any).customElement = this;
177
+ }
96
178
 
97
- connectedCallback() {
98
- // this._happel.mount(this);
99
- this.attachShadow({ mode: "open" });
100
- this._happel.mount(this.shadowRoot as any);
101
- }
179
+ connectedCallback() {
180
+ // this._happel.mount(this);
181
+ this.attachShadow({ mode: "open" });
182
+ this._happel.mount(this.shadowRoot as any);
183
+ }
102
184
 
103
- disconnectedCallback() {
104
- this._happel.umount();
105
- }
185
+ disconnectedCallback() {
186
+ this._happel.umount();
187
+ }
106
188
 
107
- adoptedCallback() {
108
- this._happel.update();
109
- }
189
+ adoptedCallback() {
190
+ this._happel.update();
191
+ }
110
192
 
111
- attributeChangedCallback(attrName: string, oldVal: string | null, newVal: string | null) {
112
- this._happel.dispatch(HAppAction._element, { attrName, oldVal, newVal });
193
+ attributeChangedCallback(
194
+ attrName: string,
195
+ oldVal: string | null,
196
+ newVal: string | null
197
+ ) {
198
+ this._happel.dispatch(HAppActions.attribute, {
199
+ attrName,
200
+ oldVal,
201
+ newVal,
202
+ });
203
+ }
113
204
  }
114
-
115
- });
205
+ );
116
206
  }
117
207
 
118
- // HAppC
208
+ /**
209
+ * HSML App
210
+ */
211
+ export class HApp<State, HActionType extends string> implements HHandlerCtx<HActionType> {
119
212
 
120
- export type HController<State> = (this: HApp<State>,
121
- data?: HAction["data"],
122
- event?: HAction["event"]) => void;
123
-
124
- export type HControllers<State, TypeofActionEnum> = { [actionType in keyof TypeofActionEnum]?: HController<State>; };
125
-
126
- export function controllersDdispatcher<State, TyopeofActionEnum>(controllers: HControllers<State, TyopeofActionEnum>): HDispatcher<State> {
127
- return async function (this: HApp<State>, action) {
128
- const controller = controllers[action.type as keyof TyopeofActionEnum];
129
- if (controller) {
130
- controller.apply<HApp<State>, [any?, Event?], void>(this, [action.data, action.event]);
131
- } else {
132
- warn("no controller for action", action);
133
- }
134
- };
135
- }
136
-
137
- const HAPP = "happ";
213
+ readonly state: State;
214
+ readonly view: HView<State, HActionType>;
215
+ readonly dispatcher: HDispatcher<State, HActionType>;
138
216
 
139
- export class HApp<STATE> implements HHandlerCtx {
217
+ debug: boolean;
140
218
 
141
- static debug = false;
219
+ readonly name: string;
220
+ readonly attributes: string[];
142
221
 
143
- readonly state: STATE;
144
- readonly view: HView<STATE>;
145
- readonly dispatcher: HDispatcher<STATE>;
222
+ readonly element?: HTMLElement;
223
+ readonly refs: { [key: string]: HTMLElement } = {};
146
224
 
147
225
  readonly customElement?: HTMLElement; // happ custom html element
148
226
 
149
- readonly dom?: HTMLElement;
150
- readonly refs: { [key: string]: HTMLElement } = {};
151
-
152
227
  private _updateSched?: number;
153
228
 
154
- private _onDispatch?: HDispatcher<STATE>;
229
+ // private _onDispatch?: HDispatcher<State>;
155
230
 
156
231
  private _windowEventListener?: (event: Event) => void;
157
232
 
158
- constructor(state: HState<STATE>, view: HView<STATE>, dispatcher?: HDispatcher<STATE>, e: Element | string | null = document.body) {
233
+ constructor(
234
+ state: HState<State>,
235
+ view: HView<State, HActionType>,
236
+ dispatcher?: HDispatcher<State, HActionType>,
237
+ element?: Element | string | null,
238
+ debug?: boolean ,
239
+ name?: string,
240
+ attributes?: string[]
241
+ ) {
242
+ this.debug = debug ?? false;
243
+ this.name = name ?? HAPP;
244
+ this.attributes = attributes ?? [];
159
245
  this.state = state();
160
246
  this.view = view;
161
- this.dispatcher = dispatcher ?? (async (a) => log(msgAction, a.type, a.data));
162
- this.dispatch(HAppAction._init, this).then(() => this.mount(e));
247
+ this.dispatcher = dispatcher ?? (async (a) => log(this.name, msgAction, a.type, a.data));
248
+ this._dispatchAction(HAppActions.init, this).then(() => element && this.mount(element));
163
249
  }
164
250
 
165
- private async _dispatch(type: string, data: any, event: Event | undefined) {
166
- try {
167
- await this.dispatcher({ type, data, event }, this.state, this.dispatch);
168
- this._onDispatch?.({ type, data, event }, this.state, this.dispatch);
169
- this.dom && elementDispatchCustomEvent(this.dom, HAPP, { type, data, event });
170
- this.customElement && elementDispatchCustomEvent(this.customElement, type, data);
171
- !this.customElement && this.dom && elementDispatchCustomEvent(this.dom, type, data);
172
- this.update();
173
- } catch (e) {
174
- error(msgDispatch, e);
175
- }
251
+ dispatch: HDispatch<HActionType> = async (
252
+ type: HActionType | HAppActionType,
253
+ data?: any,
254
+ scope?: HDispatchScope
255
+ ): Promise<void> => {
256
+ return this._dispatchAction(type, data, undefined, scope);
176
257
  }
177
258
 
178
- onDispatch = (dispatcher: HDispatcher<STATE>): this => {
179
- this._onDispatch = dispatcher;
180
- return this;
181
- }
182
-
183
- dispatch: HDispatch = async (type: string, data?: any, event?: Event): Promise<void> => {
184
- if (HApp.debug) {
185
- log(msgAction, { type, data, event });
259
+ // onDispatch = (dispatcher: HDispatcher<State>): this => {
260
+ // this._onDispatch = dispatcher;
261
+ // return this;
262
+ // }
263
+
264
+ private async _dispatchAction(
265
+ type: HActionType | HAppActionType,
266
+ data?: any,
267
+ event?: Event,
268
+ scope?: HDispatchScope
269
+ ): Promise<void> {
270
+ if (this.debug) {
271
+ log(this.name, msgAction, { type, data, event });
186
272
  const t0 = performance.now();
187
- await this._dispatch(type, data, event);
273
+ await this._dispatch(type, data, event, scope);
188
274
  const t1 = performance.now();
189
- log(msgDispatch, `${t1 - t0} ms`, this.state);
275
+ log(this.name, msgDispatch, `${t1 - t0} ms`, this.state);
190
276
  } else {
191
- await this._dispatch(type, data, event);
277
+ await this._dispatch(type, data, event, scope);
192
278
  }
193
279
  }
194
280
 
195
- windowDispatch: HDispatch = async (type: string, data?: any, event?: Event): Promise<void> => {
196
- window.dispatchEvent(new CustomEvent(HAPP, { detail: { type, data } }));
281
+ private async _dispatch(
282
+ type: HActionType | HAppActionType,
283
+ data: any,
284
+ event?: Event,
285
+ scope?: HDispatchScope
286
+ ) {
287
+ try {
288
+ await this.dispatcher(
289
+ { type: type as HActionType, data, event },
290
+ this.state,
291
+ this.dispatch
292
+ );
293
+ this.update();
294
+ scope === "element" && this._dispatchElement(type, data);
295
+ scope === "window" && this._dispatchWindow(type, data);
296
+ } catch (e) {
297
+ error(this.name, msgDispatch, e);
298
+ }
299
+ }
300
+
301
+ private _dispatchElement: HDispatch<HActionType> = async (
302
+ type: HActionType | HAppActionType,
303
+ data?: any
304
+ ): Promise<void> => {
305
+ this.customElement && elementDispatchCustomEvent(this.customElement, HAppActions.action, { type, data });
306
+ !this.customElement && this.element && elementDispatchCustomEvent(this.element, HAppActions.action, { type, data });
307
+ // this.customElement && elementDispatchCustomEvent(this.customElement, type, data);
308
+ // !this.customElement && this.element && elementDispatchCustomEvent(this.element, type, data);
309
+ // this._onDispatch?.({ type, data, event }, this.state, this.dispatch);
310
+ }
311
+
312
+ private _dispatchWindow: HDispatch<HActionType> = async (
313
+ type: HActionType | HAppActionType,
314
+ data?: any): Promise<void> => {
315
+ window.dispatchEvent(new CustomEvent(HAppActions.action, { detail: { type, data } }));
197
316
  }
198
317
 
199
318
  windowDispatchOn() {
200
319
  if (!this._windowEventListener) {
201
320
  this._windowEventListener = (event: Event) => {
202
- const action = (event as CustomEvent).detail as HAction;
203
- this.dispatch(action.type, action.data, event);
321
+ const action = (event as CustomEvent).detail as HAction<HActionType>;
322
+ this._dispatchAction(action.type, action.data);
204
323
  };
205
- window.addEventListener(HAPP, this._windowEventListener);
324
+ window.addEventListener(HAppActions.action, this._windowEventListener);
206
325
  } else {
207
326
  warn("windowEventListener olready setted");
208
327
  }
@@ -210,34 +329,34 @@ export class HApp<STATE> implements HHandlerCtx {
210
329
 
211
330
  windowDispatchOff() {
212
331
  if (this._windowEventListener) {
213
- window.removeEventListener(HAPP, this._windowEventListener);
332
+ window.removeEventListener(HAppActions.action, this._windowEventListener);
214
333
  }
215
334
  }
216
335
 
217
- render = (): HElements => {
218
- if (HApp.debug) {
336
+ render = (): HElements<HActionType> => {
337
+ if (this.debug) {
219
338
  const t0 = performance.now();
220
339
  let hsmls;
221
340
  try {
222
341
  hsmls = this.view(this.state);
223
342
  } catch (e) {
224
- error(msgRender, e);
343
+ error(this.name, msgRender, e);
225
344
  }
226
345
  const t1 = performance.now();
227
- log(msgRender, `${t1 - t0} ms`, hsmls);
346
+ log(this.name, msgRender, `${t1 - t0} ms`, hsmls);
228
347
  return hsmls ?? [];
229
348
  } else {
230
349
  let hsmls;
231
350
  try {
232
351
  hsmls = this.view(this.state);
233
352
  } catch (e) {
234
- error(msgRender, e);
353
+ error(this.name, msgRender, e);
235
354
  }
236
355
  return hsmls ?? [];
237
356
  }
238
357
  }
239
358
 
240
- actionCb = (action: string, data: HAttrOnData, event: Event): void => {
359
+ actionCb = (actionType: HActionType, data: HAttrOnData, event: Event): void => {
241
360
  data = (data?.constructor === Function)
242
361
  ? (data as HAttrOnDataFnc)(event)
243
362
  : data;
@@ -248,53 +367,66 @@ export class HApp<STATE> implements HHandlerCtx {
248
367
  data = formData(event);
249
368
  }
250
369
  }
251
- this.dispatch(action, data, event);
370
+ this._dispatchAction(actionType, data, event);
371
+ }
372
+
373
+ private _updateDom<HActionType extends string>(
374
+ el: Element,
375
+ hsml: HElements<HActionType>,
376
+ ctx: HHandlerCtx<HActionType>
377
+ ): void {
378
+ if (this.debug) {
379
+ const t0 = performance.now();
380
+ hsmls2idomPatch(el, hsml, ctx);
381
+ const t1 = performance.now();
382
+ log(this.name, msgUpdate, `${t1 - t0} ms`, el);
383
+ } else {
384
+ hsmls2idomPatch(el, hsml, ctx);
385
+ }
252
386
  }
253
387
 
254
- mount = (e: Element | string | null = document.body): this => {
255
- const el = (typeof e === "string")
256
- ? document.getElementById(e) ?? document.body
257
- : e ?? document.body;
258
- if ((el as any)[HAPP]) {
259
- const a = (el as any)[HAPP] as HApp<STATE>;
388
+ mount = (e: Element | string | null): this => {
389
+ const el = (typeof e === "string") ? document.getElementById(e) : e;
390
+ if (el && (el as any)[HAPP]) {
391
+ const a = (el as any)[HAPP] as HApp<State, HActionType>;
260
392
  a.umount();
261
393
  }
262
- if (!this.dom) {
263
- (this as any).dom = el;
394
+ if (el && !this.element) {
395
+ (this as any).element = el;
264
396
  (el as any)[HAPP] = this;
265
397
  const hsmls = (this as any).render();
266
- updateDom(el, hsmls, this);
267
- this.dispatch(HAppAction._mount, this.dom);
398
+ this._updateDom<HActionType>(el, hsmls, this);
399
+ this._dispatchAction(HAppActions.mount, this.element);
268
400
  }
269
401
  return this;
270
402
  }
271
403
 
272
404
  umount = (): this => {
273
- if (this.dom) {
274
- this.dispatch(HAppAction._umount, this.dom);
275
- if (this.dom.hasAttribute(HAPP)) {
276
- this.dom.removeAttribute(HAPP);
405
+ if (this.element) {
406
+ this._dispatchAction(HAppActions.umount, this.element);
407
+ if (this.element.hasAttribute(HAPP)) {
408
+ this.element.removeAttribute(HAPP);
277
409
  }
278
- const aNodes = this.dom.querySelectorAll(`[${HAPP}]`);
410
+ const aNodes = this.element.querySelectorAll(`[${HAPP}]`);
279
411
  for (let i = 0; i < aNodes.length; i++) {
280
- const a = (aNodes[i] as any).happ as HApp<STATE>;
412
+ const a = (aNodes[i] as any).happ as HApp<State, HActionType>;
281
413
  a?.umount();
282
414
  }
283
- while (this.dom.firstChild /*.hasChildNodes()*/) {
284
- this.dom.removeChild(this.dom.firstChild);
415
+ while (this.element.firstChild /*.hasChildNodes()*/) {
416
+ this.element.removeChild(this.element.firstChild);
285
417
  }
286
- delete (this.dom as any).happ;
287
- (this as any).dom = undefined;
418
+ delete (this.element as any).happ;
419
+ (this as any).element = undefined;
288
420
  }
289
421
  return this;
290
422
  }
291
423
 
292
424
  update = (): this => {
293
- if (this.dom && !this._updateSched) {
425
+ if (this.element && !this._updateSched) {
294
426
  this._updateSched = schedule(() => {
295
- if (this.dom) {
427
+ if (this.element) {
296
428
  const hsmls = this.render();
297
- updateDom(this.dom, hsmls, this);
429
+ this._updateDom<HActionType>(this.element, hsmls, this);
298
430
  }
299
431
  this._updateSched = undefined;
300
432
  });
@@ -302,47 +434,40 @@ export class HApp<STATE> implements HHandlerCtx {
302
434
  return this;
303
435
  }
304
436
 
305
- toHsml = (): HElement => {
306
- if (this.dom) {
437
+ toHsml = (): HElement<HActionType> => {
438
+ if (this.element) {
307
439
  if (this._updateSched) {
308
440
  unschedule(this._updateSched);
309
441
  this._updateSched = undefined;
310
442
  } else {
311
- return ["div", { _skip: true }];
443
+ return ["div", { skip: true }];
312
444
  }
313
445
  }
314
446
  const hsmls = this.render();
315
447
  hsmls.push(
316
448
  (e: Element) => {
317
- if (!this.dom) {
318
- (this as any).dom = e;
449
+ if (!this.element) {
450
+ (this as any).element = e;
319
451
  (e as any).happ = this;
320
- this.dispatch(HAppAction._mount, this.dom);
452
+ this._dispatchAction(HAppActions.mount, this.element);
321
453
  }
322
454
  });
323
455
  return ["div", hsmls];
324
456
  }
325
457
 
326
458
  toHtml = (): string => {
327
- return this.dom ? this.dom.outerHTML : "";
459
+ return this.element ? this.element.outerHTML : "";
328
460
  }
329
461
 
330
462
  }
331
463
 
332
- function updateDom(el: Element, hsml: HElements, ctx: HHandlerCtx): void {
333
- if (HApp.debug) {
334
- const t0 = performance.now();
335
- hsmls2idomPatch(el, hsml, ctx);
336
- const t1 = performance.now();
337
- log(msgUpdate, `${t1 - t0} ms`, el);
338
- } else {
339
- hsmls2idomPatch(el, hsml, ctx);
340
- }
341
- }
342
-
343
- function elementDispatchCustomEvent(el: HTMLElement, type: string, data: any) {
464
+ function elementDispatchCustomEvent<HActionType extends string>(
465
+ el: HTMLElement,
466
+ type: HActionType,
467
+ data: any
468
+ ) {
344
469
  el?.dispatchEvent(new CustomEvent(type, { detail: data }));
345
- (el as any)[`on${type.toLowerCase()}`]?.(new CustomEvent(type, { detail: data }));
470
+ (el as any)[`on${type}`]?.(new CustomEvent(type, { detail: data }));
346
471
  }
347
472
 
348
473
  function formData(e: Event): { [k: string]: string | number | boolean | null | Array<string | null> } | string | number | boolean | null | Array<string | null> {
@@ -491,20 +616,3 @@ function formInputData(el: Element): { [k: string]: string | number | boolean |
491
616
  }
492
617
  return data;
493
618
  }
494
-
495
- // export const formInputData = <STATE>(dispatcher: Actions<STATE>): Actions<STATE> =>
496
- // (app: App<STATE>, action: string | number, data?: any, event?: Event): void => {
497
- // if (data === undefined && event) {
498
- // data = inputEventData(event);
499
- // }
500
- // dispatcher(app, action, data, event);
501
- // };
502
-
503
- // // Decorator
504
- // export function FormInputData() {
505
- // return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
506
- // const method = descriptor.value;
507
- // descriptor.value = formInputData(method);
508
- // return descriptor;
509
- // };
510
- // }