@twobirds/microcomponents 0.0.82 → 0.0.84

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 (268) hide show
  1. package/assets/documentation/MC.md +0 -1
  2. package/assets/test/test.html +1 -1
  3. package/dist/MC.d.ts +11 -10
  4. package/dist/MC.d.ts.map +1 -1
  5. package/dist/MC.js +137 -200
  6. package/dist/MC.min.js +157 -296
  7. package/dist/MC.ts +202 -337
  8. package/dist/elements.d.ts +1 -1
  9. package/dist/elements.d.ts.map +1 -1
  10. package/dist/elements.js +26 -6
  11. package/dist/elements.min.js +1 -1
  12. package/dist/elements.ts +50 -7
  13. package/dist/formValues.js +2 -2
  14. package/dist/formValues.min.js +1 -1
  15. package/dist/formValues.ts +3 -3
  16. package/dist/microcomponents.d.ts +0 -1
  17. package/dist/microcomponents.d.ts.map +1 -1
  18. package/dist/microcomponents.js +0 -1
  19. package/dist/microcomponents.min.js +1 -1
  20. package/dist/microcomponents.ts +1 -1
  21. package/dist/observables.d.ts.map +1 -1
  22. package/dist/observables.js +52 -57
  23. package/dist/observables.min.js +1 -1
  24. package/dist/observables.ts +68 -73
  25. package/package.json +6 -5
  26. package/public/MC.d.ts +11 -10
  27. package/public/MC.d.ts.map +1 -1
  28. package/public/MC.js +137 -200
  29. package/public/MC.js.map +1 -1
  30. package/public/MC.min.js +157 -296
  31. package/public/MC.ts +202 -337
  32. package/public/documentation/MC.md +0 -1
  33. package/public/elements.d.ts +1 -1
  34. package/public/elements.d.ts.map +1 -1
  35. package/public/elements.js +26 -6
  36. package/public/elements.js.map +1 -1
  37. package/public/elements.min.js +1 -1
  38. package/public/elements.ts +50 -7
  39. package/public/formValues.js +2 -2
  40. package/public/formValues.js.map +1 -1
  41. package/public/formValues.min.js +1 -1
  42. package/public/formValues.ts +3 -3
  43. package/public/microcomponents.d.ts +0 -1
  44. package/public/microcomponents.d.ts.map +1 -1
  45. package/public/microcomponents.js +0 -1
  46. package/public/microcomponents.js.map +1 -1
  47. package/public/microcomponents.min.js +1 -1
  48. package/public/microcomponents.ts +1 -1
  49. package/public/observables.d.ts.map +1 -1
  50. package/public/observables.js +52 -57
  51. package/public/observables.js.map +1 -1
  52. package/public/observables.min.js +1 -1
  53. package/public/observables.ts +68 -73
  54. package/public/{test/selectors.ts → selectors._ts} +2 -367
  55. package/public/src/MC.d.ts +37 -0
  56. package/public/src/MC.d.ts.map +1 -0
  57. package/public/src/MC.js +316 -0
  58. package/public/src/MC.js.map +1 -0
  59. package/public/src/MC.ts +202 -337
  60. package/public/src/elements.d.ts +5 -0
  61. package/public/src/elements.d.ts.map +1 -0
  62. package/public/src/elements.js +68 -0
  63. package/public/src/elements.js.map +1 -0
  64. package/public/src/elements.ts +50 -7
  65. package/public/src/formValues.d.ts +3 -0
  66. package/public/src/formValues.d.ts.map +1 -0
  67. package/public/src/formValues.js +162 -0
  68. package/public/src/formValues.js.map +1 -0
  69. package/public/src/formValues.ts +3 -3
  70. package/public/src/helpers.d.ts +14 -0
  71. package/public/src/helpers.d.ts.map +1 -0
  72. package/public/src/helpers.js +113 -0
  73. package/public/src/microcomponents.d.ts +6 -0
  74. package/public/src/microcomponents.d.ts.map +1 -0
  75. package/public/src/microcomponents.js +7 -0
  76. package/public/src/microcomponents.js.map +1 -0
  77. package/public/src/microcomponents.ts +1 -1
  78. package/public/src/observables.d.ts +11 -0
  79. package/public/src/observables.d.ts.map +1 -0
  80. package/public/src/observables.js +244 -0
  81. package/public/src/observables.js.map +1 -0
  82. package/public/src/observables.ts +68 -73
  83. package/public/{selectors.ts → src/selectors._ts} +2 -367
  84. package/public/src/test/grandparent.css +11 -0
  85. package/public/src/test/test/child.d.ts +2 -0
  86. package/public/src/test/test/child.d.ts.map +1 -0
  87. package/public/src/test/test/child.js +15 -0
  88. package/public/src/test/test/child.js.map +1 -0
  89. package/public/src/test/test/child.ts +21 -0
  90. package/public/src/test/test/grandchild.d.ts +2 -0
  91. package/public/src/test/test/grandchild.d.ts.map +1 -0
  92. package/public/src/test/test/grandchild.js +15 -0
  93. package/public/src/test/test/grandchild.js.map +1 -0
  94. package/public/src/test/test/grandchild.ts +21 -0
  95. package/public/src/test/test/grandparent.d.ts +2 -0
  96. package/public/src/test/test/grandparent.d.ts.map +1 -0
  97. package/public/src/test/test/grandparent.js +1 -0
  98. package/public/src/test/test/grandparent.js.map +1 -0
  99. package/public/src/test/test/grandparent.ts +29 -0
  100. package/public/src/test/test/greatgrandchild.d.ts +2 -0
  101. package/public/src/test/test/greatgrandchild.d.ts.map +1 -0
  102. package/public/src/test/test/greatgrandchild.js +29 -0
  103. package/public/src/test/test/greatgrandchild.js.map +1 -0
  104. package/public/src/test/test/greatgrandchild.ts +42 -0
  105. package/public/src/test/test/parent.d.ts +2 -0
  106. package/public/src/test/test/parent.d.ts.map +1 -0
  107. package/public/src/test/test/parent.js +15 -0
  108. package/public/src/test/test/parent.js.map +1 -0
  109. package/public/src/test/test/parent.ts +21 -0
  110. package/public/src/test/test/testform.d.ts +2 -0
  111. package/public/src/test/test/testform.d.ts.map +1 -0
  112. package/public/src/test/test/testform.js +1 -0
  113. package/public/src/test/test/testform.js.map +1 -0
  114. package/public/src/test/test/testform.ts +153 -0
  115. package/public/src/test/test/testfunction.d.ts +3 -0
  116. package/public/src/test/test/testfunction.d.ts.map +1 -0
  117. package/public/src/test/test/testfunction.js +7 -0
  118. package/public/src/test/test/testfunction.js.map +1 -0
  119. package/public/src/test/test/testfunction.ts +12 -0
  120. package/public/src/test/test/testmc.d.ts +3 -0
  121. package/public/src/test/test/testmc.d.ts.map +1 -0
  122. package/public/src/test/test/testmc.js +10 -0
  123. package/public/src/test/test/testmc.js.map +1 -0
  124. package/public/src/test/test/testmc.ts +16 -0
  125. package/public/src/test/test/testsimpleclass.d.ts +3 -0
  126. package/public/src/test/test/testsimpleclass.d.ts.map +1 -0
  127. package/public/src/test/test/testsimpleclass.js +9 -0
  128. package/public/src/test/test/testsimpleclass.js.map +1 -0
  129. package/public/src/test/test/testsimpleclass.ts +15 -0
  130. package/public/src/test/test.d.ts +2 -0
  131. package/public/src/test/test.d.ts.map +1 -0
  132. package/public/src/test/test.js +80 -0
  133. package/public/src/test/test.js.map +1 -0
  134. package/public/src/test/test.ts +188 -0
  135. package/public/src/test/testform.css +47 -0
  136. package/public/src/test/testform.html +56 -0
  137. package/public/src/test/testform.json +27 -0
  138. package/public/test/MC.d.ts +11 -10
  139. package/public/test/MC.d.ts.map +1 -1
  140. package/public/test/MC.js +137 -200
  141. package/public/test/MC.min.js +377 -0
  142. package/public/test/MC.ts +202 -337
  143. package/public/test/elements.d.ts +1 -1
  144. package/public/test/elements.d.ts.map +1 -1
  145. package/public/test/elements.js +26 -6
  146. package/public/test/elements.min.js +1 -0
  147. package/public/test/elements.ts +50 -7
  148. package/public/test/formValues.js +2 -2
  149. package/public/test/formValues.min.js +1 -0
  150. package/public/test/formValues.ts +3 -3
  151. package/public/test/grandparent.css +1 -3
  152. package/public/test/microcomponents.d.ts +0 -1
  153. package/public/test/microcomponents.d.ts.map +1 -1
  154. package/public/test/microcomponents.js +0 -1
  155. package/public/test/microcomponents.min.js +1 -1
  156. package/public/test/microcomponents.ts +1 -1
  157. package/public/test/observables.d.ts.map +1 -1
  158. package/public/test/observables.js +52 -57
  159. package/public/test/observables.min.js +1 -0
  160. package/public/test/observables.ts +68 -73
  161. package/public/test/test/child.ts +21 -0
  162. package/public/test/test/grandchild.ts +21 -0
  163. package/public/test/test/grandparent.d.ts.map +1 -1
  164. package/public/test/test/grandparent.js +1 -1
  165. package/public/test/test/grandparent.js.map +1 -1
  166. package/public/test/test/grandparent.ts +29 -0
  167. package/public/test/test/greatgrandchild.ts +42 -0
  168. package/public/test/test/parent.ts +21 -0
  169. package/public/test/test/testform.js +1 -1
  170. package/public/test/test/testform.js.map +1 -1
  171. package/public/test/test/testform.ts +153 -0
  172. package/public/test/test/testfunction.d.ts +3 -0
  173. package/public/test/test/testfunction.d.ts.map +1 -0
  174. package/public/test/test/testfunction.js +7 -0
  175. package/public/test/test/testfunction.js.map +1 -0
  176. package/public/test/test/testfunction.ts +12 -0
  177. package/public/test/test/testmc.d.ts +2 -5
  178. package/public/test/test/testmc.d.ts.map +1 -1
  179. package/public/test/test/testmc.js +4 -4
  180. package/public/test/test/testmc.js.map +1 -1
  181. package/public/test/test/testmc.ts +16 -0
  182. package/public/test/test/testsimpleclass.d.ts +3 -0
  183. package/public/test/test/testsimpleclass.d.ts.map +1 -0
  184. package/public/test/test/testsimpleclass.js +9 -0
  185. package/public/test/test/testsimpleclass.js.map +1 -0
  186. package/public/test/test/testsimpleclass.ts +15 -0
  187. package/public/test/test.html +1 -1
  188. package/public/test/test.js +5 -6
  189. package/public/test/test.js.map +1 -1
  190. package/public/test/test.ts +188 -0
  191. package/public/test/testform.css +47 -0
  192. package/public/test/testform.html +56 -0
  193. package/public/test/testform.json +3 -3
  194. package/public/typedoc/assets/navigation.js +1 -1
  195. package/public/typedoc/assets/search.js +1 -1
  196. package/public/typedoc/classes/MC.DC.html +6 -4
  197. package/public/typedoc/classes/MC.MC.html +3 -4
  198. package/public/typedoc/classes/MC.McBase.html +2 -2
  199. package/public/typedoc/functions/MC.autoload.html +1 -1
  200. package/public/typedoc/functions/MC.off.html +1 -0
  201. package/public/typedoc/functions/MC.on.html +1 -0
  202. package/public/typedoc/functions/MC.one.html +1 -0
  203. package/public/typedoc/functions/elements.defineCE.html +1 -1
  204. package/public/typedoc/functions/elements.getCE.html +1 -1
  205. package/public/typedoc/functions/formValues.formValues.html +1 -1
  206. package/public/typedoc/functions/observables.observe.html +1 -1
  207. package/public/typedoc/interfaces/MC.HTMLMcElement.html +2 -2
  208. package/public/typedoc/modules/MC.html +7 -6
  209. package/public/typedoc/modules/elements.html +1 -1
  210. package/public/typedoc/modules/formValues.html +1 -1
  211. package/public/typedoc/modules/observables.html +1 -1
  212. package/public/typedoc/types/observables.Observable.html +1 -1
  213. package/src/MC.ts +202 -337
  214. package/src/elements.ts +50 -7
  215. package/src/formValues.ts +3 -3
  216. package/src/microcomponents.ts +1 -1
  217. package/src/observables.ts +68 -73
  218. package/{dist/selectors.ts → src/selectors._ts} +2 -367
  219. package/src/test/test/grandparent.ts +12 -4
  220. package/src/test/test/testform.ts +13 -11
  221. package/src/test/test/testfunction.ts +12 -0
  222. package/src/test/test/testmc.ts +13 -9
  223. package/src/test/test/testsimpleclass.ts +15 -0
  224. package/src/test/test.ts +8 -20
  225. package/tasks.md +36 -0
  226. package/tsconfig.json +2 -2
  227. package/typedoc.json +1 -1
  228. package/webpack.config.js +2 -2
  229. package/dist/McEvent.d.ts +0 -15
  230. package/dist/McEvent.d.ts.map +0 -1
  231. package/dist/McEvent.js +0 -71
  232. package/dist/selectors.d.ts +0 -108
  233. package/dist/selectors.d.ts.map +0 -1
  234. package/dist/selectors.js +0 -971
  235. package/dist/selectors.min.js +0 -1
  236. package/public/McEvent.d.ts +0 -15
  237. package/public/McEvent.d.ts.map +0 -1
  238. package/public/McEvent.js +0 -71
  239. package/public/McEvent.js.map +0 -1
  240. package/public/selectors.d.ts +0 -108
  241. package/public/selectors.d.ts.map +0 -1
  242. package/public/selectors.js +0 -971
  243. package/public/selectors.js.map +0 -1
  244. package/public/selectors.min.js +0 -1
  245. package/public/src/selectors.ts +0 -1634
  246. package/public/test/MC.js.map +0 -1
  247. package/public/test/McEvent.d.ts +0 -15
  248. package/public/test/McEvent.d.ts.map +0 -1
  249. package/public/test/McEvent.js +0 -71
  250. package/public/test/McEvent.js.map +0 -1
  251. package/public/test/McEvent.ts +0 -96
  252. package/public/test/elements.js.map +0 -1
  253. package/public/test/formValues.js.map +0 -1
  254. package/public/test/microcomponents.js.map +0 -1
  255. package/public/test/observables.js.map +0 -1
  256. package/public/test/selectors.d.ts +0 -108
  257. package/public/test/selectors.d.ts.map +0 -1
  258. package/public/test/selectors.js +0 -971
  259. package/public/test/selectors.js.map +0 -1
  260. package/public/typedoc/classes/MC.McEvent.html +0 -9
  261. package/public/typedoc/functions/MC.addListener.html +0 -1
  262. package/public/typedoc/functions/MC.removeListener.html +0 -1
  263. package/src/McEvent.ts +0 -96
  264. package/src/selectors.ts +0 -1634
  265. /package/{dist/McEvent.ts → public/McEvent._ts} +0 -0
  266. /package/public/{McEvent.ts → src/McEvent._ts} +0 -0
  267. /package/public/{test → src}/helpers.js.map +0 -0
  268. /package/{public/src/McEvent.ts → src/McEvent._ts} +0 -0
package/public/test/MC.ts CHANGED
@@ -1,19 +1,20 @@
1
1
  'use strict';
2
2
 
3
3
  import { LooseObject } from './helpers.js';
4
- import { McEvent } from './McEvent.js';
5
4
 
6
5
  var isBrowser = new Function(
7
6
  'try {return this===window;}catch(e){ return false;}'
8
7
  );
9
8
 
10
- let nativeEventNames: Set<string> = new Set();
11
-
12
- // HTMLElement native event names
13
- if (isBrowser()) {
14
- Object.keys(HTMLElement.prototype)
15
- .filter((key) => /^on/.test(key))
16
- .forEach((eventName) => nativeEventNames.add(eventName));
9
+ // get HTMLElement native event names
10
+ function getNativeEventNames( domNode: HTMLElement ): string[] {
11
+ let nativeEventNames: Array<string> = [];
12
+ if (isBrowser()) {
13
+ Object.keys(HTMLElement.prototype)
14
+ .filter((key) => /^on/.test(key))
15
+ .forEach((eventName) => nativeEventNames.push(eventName));
16
+ }
17
+ return nativeEventNames;
17
18
  }
18
19
 
19
20
  export interface HTMLMcElement extends HTMLElement {
@@ -64,34 +65,6 @@ function isDOM(element: { [key: string]: any }) {
64
65
  return element && element instanceof HTMLElement;
65
66
  }
66
67
 
67
- function addListener(
68
- domNode: Node,
69
- eventName: string,
70
- handler: EventListenerOrEventListenerObject | null,
71
- capture: boolean = false,
72
- once: boolean = false
73
- ) {
74
- let options: EventListenerOptions & { once: boolean } = { once: false };
75
- if (capture) {
76
- options.capture = capture;
77
- }
78
-
79
- if (once) {
80
- options.once = once;
81
- }
82
-
83
- //console.log( 'addEventListener', eventName, ( handler as Function ).name, options );
84
- domNode.addEventListener(eventName, handler, options);
85
- }
86
-
87
- function removeListener(
88
- domNode: Node,
89
- eventName: string,
90
- handler: EventListenerOrEventListenerObject | null
91
- ) {
92
- domNode.removeEventListener(eventName, handler);
93
- }
94
-
95
68
  // add a microcomponent to a target DOM node
96
69
  function add(target: HTMLElement, key: string, element = {}): any {
97
70
  let node = target as HTMLMcElement;
@@ -111,8 +84,8 @@ function add(target: HTMLElement, key: string, element = {}): any {
111
84
  if (key.length && !_mc[key]) {
112
85
  _mc[key] = element;
113
86
  // add attribute if HTMLElement
114
- if (target instanceof HTMLElement && ! target.getAttribute('_mc') ) {
115
- target.setAttribute('_mc', '');
87
+ if (target instanceof HTMLElement && ! target.getAttribute('data-mc') ) {
88
+ target.setAttribute('data-mc', '');
116
89
  }
117
90
  }
118
91
  return element;
@@ -133,41 +106,10 @@ function remove(target: HTMLMcElement, key: string) {
133
106
  if (
134
107
  !Object.keys(_mc).length &&
135
108
  target instanceof HTMLElement &&
136
- target.hasAttribute('_mc')
109
+ target.hasAttribute('data-mc')
137
110
  ) {
138
- target.removeAttribute('_mc');
139
- }
140
- return;
141
- }
142
-
143
- // trigger an event
144
- function trigger(
145
- target: HTMLElement,
146
- ev: McEvent | string,
147
- data: any = {},
148
- bubble: string = 'l'
149
- ) {
150
- let _mc = (target as any)?._mc;
151
- if (!_mc) return;
152
-
153
- let event =
154
- ev instanceof McEvent
155
- ? new McEvent(ev.type, ev.data, 'l')
156
- : new McEvent(ev, data, 'l'),
157
- mcEvent: McEvent =
158
- typeof ev !== 'string' ? (ev as McEvent) : new McEvent(ev, data, bubble);
159
-
160
- [...Object.values(_mc)].forEach((mc: any) => {
161
- //console.log( 'mc [', mc.constructor.name, ']', mc.constructor.prototype?.oneInit );
162
- if ((mc as any)?.trigger && typeof (mc as any)?.trigger === 'function') {
163
- (mc as any)?.trigger(event);
164
- }
165
- });
166
-
167
- if (/[ud]/.test(mcEvent.bubble)) {
168
- bubbleEvent(target, mcEvent);
111
+ target.removeAttribute('data-mc');
169
112
  }
170
-
171
113
  return;
172
114
  }
173
115
 
@@ -193,6 +135,77 @@ function init(element: MC | DC) {
193
135
  }, 0);
194
136
  }
195
137
 
138
+ function getMcEventName( eventName: string ): string {
139
+ return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
140
+ }
141
+
142
+ /*
143
+ CustomEvent Section...
144
+ */
145
+ function off( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject ){
146
+ domNode.removeEventListener( getMcEventName(eventName), handler );
147
+ }
148
+
149
+ function on( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject, once: boolean = false ) {
150
+ domNode.addEventListener( getMcEventName(eventName), handler, { capture: false, once });
151
+ }
152
+
153
+ function one( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject ) {
154
+ on(domNode, eventName, handler, true );
155
+ }
156
+
157
+ // create and dispatch custom event
158
+ function trigger(
159
+ domNode: HTMLElement,
160
+ event: CustomEvent | string,
161
+ data: any = {},
162
+ bubble: string = 'l'
163
+ ){
164
+ const ev = typeof event === 'string'
165
+ ? new CustomEvent( getMcEventName( event ), { detail: {data, bubble} } )
166
+ : event;
167
+
168
+ // execute locally if 'l' or nothing is given as bubble
169
+ if( bubble.length && bubble.indexOf('l') > -1 ){
170
+ domNode.dispatchEvent( ev );
171
+ }
172
+
173
+ // bubble if up or down is indicated
174
+ if( /[u|d]/.test( bubble ) ){
175
+ bubbleEvent( domNode, ev );
176
+ }
177
+ }
178
+
179
+ function bubbleEvent( domNode: HTMLElement, ev: CustomEvent) {
180
+ // at this point, either 'u' or 'd' bubbling should be indicated
181
+ // event bubbling is asynchronous!
182
+ setTimeout(() => {
183
+
184
+ // add missing 'l', or else no handlers are executed
185
+ if (ev.detail.bubble.indexOf('l') === -1) {
186
+ ev.detail.bubble += 'l';
187
+ }
188
+
189
+ // bubble up towards root
190
+ if (ev.detail.bubble.indexOf('u') > -1 ) {
191
+ domNode.closest('[data-mc]')?.dispatchEvent( ev );
192
+ }
193
+
194
+ // bubble down
195
+ if (ev.detail.bubble.indexOf('d') > -1) {
196
+ let targets = new Set<HTMLMcElement>(
197
+ (domNode as HTMLMcElement)._mc
198
+ .children()
199
+ .map((c: unknown) => (c as any)?.target)
200
+ );
201
+ targets.forEach((target: HTMLMcElement) => {
202
+ if (target) DC.trigger(target, ev);
203
+ });
204
+ }
205
+
206
+ }, 0);
207
+ }
208
+
196
209
  function autoAttachListeners(element: MC | DC) {
197
210
  if (!isBrowser() || element.constructor === DC) return;
198
211
 
@@ -209,71 +222,41 @@ function autoAttachListeners(element: MC | DC) {
209
222
  .forEach((key) => {
210
223
  let once = /^one/.test(key),
211
224
  withoutOnOne = key.replace(/^on[e]{0,1}/, ''), // preserves upper/lowercase for non-native events
212
- nativeEventName = withoutOnOne.toLowerCase(),
213
- listener = (ev: McEvent | Event | CustomEvent) => {
214
- that.trigger(withoutOnOne, ev);
215
- };
216
- if (once) {
217
- // console.log( '...is only called once', that.constructor.prototype[key] );
218
- Object.defineProperty(element, 'on' + withoutOnOne, {
219
- configurable: true,
220
- enumerable: false,
221
- writable: true,
222
- value: (ev: any) => {
223
- // console.log( 'onceHandler execute:', that.constructor.prototype[key] );
224
- that.constructor.prototype[key].bind(that)(ev);
225
- },
226
- });
227
- }
225
+ nativeEventName = withoutOnOne.toLowerCase(); // lowercase for native event names
228
226
 
229
- if (nativeEventNames.has('on' + nativeEventName)) {
230
- // native event defined in HTMLElement
231
- // console.log('added as native listener', target, nativeEventName );
232
- addListener(target, nativeEventName, listener, false, once);
227
+ let listener = (ev: Event | CustomEvent) => {
228
+ that[key]( ev );
229
+ }
230
+
231
+ if ( !!( target as any )['on' + nativeEventName] ) {
232
+ // it is a native HTML event
233
+ //console.log( 'AAL: attach native event listener', nativeEventName, 'to', target );
234
+ target.addEventListener( nativeEventName, listener);
235
+ } else {
236
+ // it is a customEvent
237
+ //console.log( 'AAL: attach custom event listener', '_mc' + withoutOnOne , 'to key', key, 'in', element );
238
+ on( target, withoutOnOne, listener, once );
233
239
  }
234
240
  });
235
241
  }
236
242
  }
237
243
 
238
- function bubbleEvent(target: HTMLElement, ev: McEvent) {
239
- // at this point, either 'u' or 'd' bubbling should be indicated
240
- // mcEvent bubbling is asynchronous, and the order of target MC execution in case of multiple matches is not guaranteed!
241
- if (/[ud]/.test(ev.bubble)) {
242
- setTimeout(() => {
243
- // bubbling must include 'l' for local, or else no handlers are executed'
244
- if (ev.bubble.indexOf('l') === -1) {
245
- ev.bubble += 'l';
246
- }
247
-
248
- // bubble up towards root
249
- if (ev.bubble.indexOf('u') > -1) {
250
- let parent = traverseNodes(target, '', true)?.[0].target;
251
- if (parent) DC.trigger(parent, ev);
252
- }
253
-
254
- // bubble down
255
- if (ev.bubble.indexOf('d') > -1) {
256
- let targets = new Set<HTMLMcElement>(
257
- (target as HTMLMcElement)._mc
258
- .children()
259
- .map((c: unknown) => (c as any)?.target)
260
- );
261
- targets.forEach((target: HTMLMcElement) => {
262
- if (target) DC.trigger(target, ev);
263
- });
264
- }
265
- }, 0);
266
- }
244
+ function getMcChildNodes(domNode: HTMLElement): NodeListOf<Element> {
245
+ const id = Math.random().toString().replace('.', '');
246
+ const selector = '[data-mc]:not([temp_id="' + id + '"] [data-mc] [data-mc])';
247
+ domNode.setAttribute('temp_id', id);
248
+ const myDomElements = domNode.querySelectorAll(selector);
249
+ domNode.removeAttribute('temp_id');
250
+ return myDomElements;
267
251
  }
268
252
 
269
253
  class McBase {
270
- #target: WeakRef<any>; // avoid circular reference
254
+ private _target: WeakRef<any>; // avoid circular reference
271
255
 
272
256
  constructor(target?: { [key: string]: any }, debug: boolean = false) {
273
- let that: unknown = this,
274
- element = that as MC | DC;
257
+ let element = this as unknown as MC | DC;
275
258
 
276
- this.#target = new WeakRef(target || {});
259
+ this._target = new WeakRef(target || {});
277
260
 
278
261
  init(element); // async lifecycle event
279
262
 
@@ -281,91 +264,24 @@ class McBase {
281
264
  }
282
265
 
283
266
  get target(): any {
284
- return this.#target.deref();
267
+ return this._target.deref();
285
268
  }
269
+
286
270
  }
287
271
 
288
272
  class MC extends McBase {
289
- _mc?: LooseObject = {};
290
-
291
273
  constructor(target?: any) {
292
274
  super(target);
293
275
  }
294
276
 
295
277
  static trigger = trigger;
296
-
297
- trigger(ev: McEvent | string, data: any = {}, bubble: string = 'l') {
298
- let that = this;
299
-
300
- //console.log( that, '.trigger(', ev, data, bubble, ')' );
301
-
302
- // run all triggers
303
- if (that.constructor === MC || that.constructor === DC) {
304
- let event =
305
- ev instanceof McEvent
306
- ? new McEvent(ev.type, ev.data, 'l')
307
- : new McEvent(ev, data, 'l'),
308
- mcEvent: McEvent =
309
- typeof ev !== 'string'
310
- ? (ev as McEvent)
311
- : new McEvent(ev, data, bubble);
312
- [...Object.getOwnPropertyNames(that)].forEach((mc) => {
313
- if (
314
- (that as any)[mc]?.trigger &&
315
- typeof (that as any)[mc]?.trigger === 'function'
316
- ) {
317
- (that as any)[mc]?.trigger(event);
318
- }
319
- });
320
-
321
- if (/[ud]/.test(mcEvent.bubble)) {
322
- bubbleEvent(that.target, mcEvent);
323
- }
324
-
325
- return; // must return here!
326
- }
327
-
328
- // only this instance
329
- if ((that as any) instanceof MC || (that as any) instanceof DC) {
330
- const that = this,
331
- mcEvent: McEvent =
332
- typeof ev !== 'string'
333
- ? (ev as McEvent)
334
- : new McEvent(ev, data, bubble),
335
- handlerName =
336
- 'on' + mcEvent.type[0].toUpperCase() + mcEvent.type.slice(1);
337
- // console.log('trigger', handlerName, mcEvent, data, bubble );
338
-
339
- if (mcEvent.bubble.indexOf('l') > -1) {
340
- if (
341
- !mcEvent.immediateStopped &&
342
- typeof (that as any)[handlerName] === 'function'
343
- ) {
344
- // console.log( 'execute handler:', handlerName );
345
- (that as any)[handlerName](mcEvent);
346
- if ((that as any).hasOwnProperty(handlerName)) {
347
- // it is a once handler
348
- delete (that as any)[handlerName]; // remove after first execution
349
- }
350
- }
351
- }
352
-
353
- // if event stopped or local only, handling is cancelled
354
- if (mcEvent.stopped || mcEvent.bubble === 'l') {
355
- return that;
356
- }
357
-
358
- //console.log('bubble', mcEvent);
359
- if (/[ud]/.test(mcEvent.bubble)) {
360
- bubbleEvent(that.target, mcEvent);
361
- }
362
- }
278
+
279
+ trigger(ev: string, data: any = {}, bubble: string = 'l') {
280
+ // TBD
363
281
  }
364
282
  }
365
283
 
366
284
  class DC extends McBase {
367
- _mc?: LooseObject = {};
368
-
369
285
  constructor(target: HTMLElement, debug: boolean = false) {
370
286
  super(target);
371
287
  }
@@ -374,8 +290,23 @@ class DC extends McBase {
374
290
  static remove: Function = remove;
375
291
  static trigger: Function = trigger;
376
292
 
377
- trigger(ev: McEvent | string, data: any = {}, bubble?: string) {
378
- MC.prototype.trigger.call(this, ev, data, bubble);
293
+ off( eventName: string, handler: EventListenerOrEventListenerObject ) {
294
+ off( this.target, eventName, handler );
295
+ }
296
+
297
+ on( eventName: string, handler: EventListenerOrEventListenerObject ) {
298
+ on( this.target, eventName, handler );
299
+ }
300
+
301
+ one( eventName: string, handler: EventListenerOrEventListenerObject ) {
302
+ one( this.target, eventName, handler );
303
+ }
304
+
305
+ trigger(ev: CustomEvent | string, data: any = {}, bubble: string = 'l') {
306
+ if ( typeof ev === 'string' ){
307
+
308
+ }
309
+ //trigger( this.target, ev, data, bubble);
379
310
  }
380
311
 
381
312
  parent(search: string = ''): any[] {
@@ -393,62 +324,66 @@ class DC extends McBase {
393
324
  children(search: string = ''): any[] {
394
325
  let target: any = (this as any)?.target;
395
326
  if (!isDOM(target)) return [];
396
- const id = Math.random().toString().replace('.', '');
397
- const selector = '[_mc]:not([temp_id="' + id + '"] [_mc] [_mc])';
398
- target.setAttribute('temp_id', id);
399
- const myDomElements = target.querySelectorAll(selector);
327
+ const myDomElements = getMcChildNodes(target);
400
328
  const mcValues = getMicroComponents([...myDomElements], search);
401
- target.removeAttribute('temp_id');
402
329
  return mcValues;
403
330
  }
404
331
 
405
332
  descendants(search: string = ''): any[] {
406
333
  let target: any = (this as any)?.target;
407
334
  if (!isDOM(target)) return [];
408
- const myDomElements = target.querySelectorAll('*[_mc]');
335
+ const myDomElements = target.querySelectorAll('*[data-mc]');
409
336
  return getMicroComponents([...myDomElements], search);
410
337
  }
411
338
  }
412
339
 
413
- /*
414
- unresolvedCEs (code below this comment):
340
+ const loadingDCs = new Set<string>();
415
341
 
416
- a repository (a hashmap) of undefined custom elements:
417
- the name is the tagname of the micro component (like "my-custom-component")
418
- if they are loading, the value is a script element
419
- if they are loaded, the entry is deleted and the browser instanciates it automatically
420
- if they cannot be loaded, the browser will throw an error
342
+ // this only applies to DCs defined in the data-mc attribute,
343
+ // since they need to be attached manually
344
+ function attachDC(element: string): Function {
421
345
 
422
- If the custom element ( defined by its tagname, like "my-custom-component") is not defined, it will be on-demand loaded:
423
- The file name is assumed to be "/my/custom/component.js"
424
- The file must define a custom element via the defineCE() function included in the "elements" module.
425
- This function is a wrapper for customElementRegistry.define(), which you can also use directly in the imported code.
346
+ //@ts-ignore
347
+ return () => {
348
+ const elements: HTMLElement[] = Array
349
+ .from(document.querySelectorAll(`[data-mc*="${element}"]`))
350
+ .filter( element => element instanceof HTMLElement );
426
351
 
427
- In general this behaves like a custom runtime import for custom elements in the browser.
428
- The only difference is that the micro component is loaded only when needed, and not on page load.
429
- */
352
+ if ( elements.length === 0 ) return;
430
353
 
431
- const CEs = new Map();
354
+ //console.log( 'loadedPromise elements', elements );
432
355
 
433
- /*
434
- loadedMCs (code below this comment):
435
- a repository (a hashmap) of micro components:
436
- the name is the name of the micro component (like "my-mc")
437
- if they are loading, the value is a script element
438
- if they are loaded, the value is the micro component class itself
356
+ const klass = customElements.get( element );
357
+
358
+ elements.forEach((node: HTMLElement) => {
359
+ //console.log( 'add', klass!.name, 'to', node );
360
+ DC.add(node, klass!.name, new klass!(node));
361
+
362
+ //@ts-ignore
363
+ const new_mc = node
364
+ .getAttribute( 'data-mc' )
365
+ .split(' ')
366
+ .filter( (name) => name !== element && name !== '' )
367
+ .join(' ')
368
+ .trim();
439
369
 
440
- This is mostly used for old style progressive enhancement:
441
- If the micro component ( defined in the HTMLElements "_mc" attribute, like "my-mc") is not defined, it will be on-demand loaded:
442
- The file name is assumed to be "/my/mc.js"
443
- The file needs to have a default export, and it should be a class that extends the DC class ( since it is in a HTMLElements attribute )
370
+ //@ts-ignore
371
+ node.setAttribute(
372
+ 'data-mc',
373
+ //@ts-ignore
374
+ new_mc
375
+ )
376
+ });
377
+ };
378
+ };
444
379
 
445
- In general this behaves like a custom runtime import for classes in the browser.
446
- The only difference is that the micro component is loaded only when needed, and not on page load.
447
- */
448
- const MCs = new Map();
380
+ function makeLoadScript( element: string ) {
449
381
 
450
- function makeLoadScript( element: string ): HTMLScriptElement {
382
+ if ( loadingDCs.has( element ) ) return; // already loading
451
383
 
384
+ loadingDCs.add( element );
385
+
386
+ //console.log( 'makeLoadScript:', element);
452
387
  const fileName: string = './' + element.split('-').join('/')+'.js';
453
388
 
454
389
  const se: HTMLScriptElement = document.createElement('script');
@@ -457,123 +392,53 @@ function makeLoadScript( element: string ): HTMLScriptElement {
457
392
  se.setAttribute('blocking', 'render');
458
393
  se.async = true;
459
394
  se.setAttribute('type', 'module');
460
- se.setAttribute( 'name', element);
395
+ se.setAttribute( 'data-name', element);
461
396
  se.setAttribute( 'loading', '');
462
397
 
463
- addListener( se, 'load', (ev) => {
464
- // console.info('loaded MC', elementName);
465
- se.removeAttribute( 'loading' );
466
- se.setAttribute( 'loaded', '');
467
- });
398
+ const loadedPromise = customElements.whenDefined( element );
468
399
 
469
- addListener( se, 'error', (ev) => {
470
- console.error('could not load Custom Element code from', fileName);
471
- });
472
-
473
- return se;
474
- }
400
+ //@ts-ignore
401
+ loadedPromise.then( attachDC( element ) );
475
402
 
476
- function onLoadCallback( script: HTMLScriptElement ) {
477
- // create callback script tag
478
- // it is essential to do this in a timeout and via another script tag,
479
- // to force it to be a top level module allowing for the use of "import"
480
- setTimeout( function(){
481
- // create callback script tag
482
- const importFileName = script.getAttribute('src');
483
- const elementName = script.getAttribute('name');
484
-
485
- const se: HTMLScriptElement = document.createElement('script');
486
-
487
- se.async = true;
488
- se.setAttribute( 'type', 'module');
489
-
490
- // --- autoload script
491
- const code = /*javascript*/`
492
-
493
- import _ from "${importFileName}";
494
- import { DC } from "./microcomponents.js";
495
-
496
- const elements = Array.from(document.querySelectorAll('[_mc*="${elementName}"]')).filter( element => element instanceof HTMLElement );
497
-
498
- elements.forEach((element) => {
499
- // add class to MCs repository
500
- autoload.state.MCs.set( '${elementName}', _ );
501
- // add instance to HTMLElement
502
- DC.add(element, _.name, new _(element));
503
- // remove instance name from elements "_mc" attribute
504
- element.setAttribute('_mc', element.getAttribute('_mc').replace('${elementName}', '').replace( /\w\w/g, ' ').trim());
505
- });
403
+ se.addEventListener( 'load', (ev: Event) => {
404
+ loadingDCs.delete( element );
506
405
 
507
- setTimeout( () => {
508
- document.body.querySelector('script[name="${elementName}]"')?.remove();
509
- },0);
406
+ document.head.querySelector(`script[data-name="${element}"]`)?.remove();
407
+ });
510
408
 
511
- `;
512
- // --- end autoload script
409
+ se.addEventListener( 'error', (ev: Event) => {
410
+ console.error('could not load DC code from', fileName);
411
+ });
513
412
 
514
- se.innerHTML = code;
515
- document.body.append(se);
516
- }, 0);
413
+ document.head.append(se);
517
414
  }
518
415
 
519
- function loadUndefinedMicroComponents() {
416
+ function loadUndefinedMCs() {
520
417
 
521
- // load unresolved custom eleents
522
- [ ...document.querySelectorAll(':not(:defined)') ] // undefined custom elements
418
+ // load unresolved custom elements
419
+ [ ...document.querySelectorAll(':not(:defined)') ]
523
420
  .filter( (element) => !!element
524
421
  && !customElements.get(element.tagName.toLowerCase()) // not in CustomElementsRegistry
525
- && !CEs.has(element.tagName.toLowerCase()) // not in loading list
422
+ && !loadingDCs.has(element.tagName.toLowerCase()) // not in loading list
526
423
  )
527
424
  .forEach((el) => {
528
- const elementName = el.tagName.toLowerCase(),
529
- fileName: string = './'+elementName.split('-').join('/')+'.js';
530
-
531
- const se: HTMLScriptElement = makeLoadScript( elementName );
532
-
533
- addListener( se, 'load', () => {
534
- CEs.set( elementName, customElements.get(el.tagName.toLowerCase()) );
535
- });
536
-
537
- CEs.set( elementName, 'loading');
538
- document.head.append(se);
539
-
540
- // instanciation of the micro component will be handled by the browser automatically
541
- // module code must define the micro component class and add it to the customElementRegistry
425
+ //console.log( 'detected CE', el.tagName.toLowerCase() );
426
+ makeLoadScript( el.tagName.toLowerCase() ); // will automatically be instanciated
542
427
  });
543
428
 
544
- [ ...document.querySelectorAll('[_mc]:not([_mc=""]') ] // undefined DOM components
429
+ // if defined in _mc attribute: instanciate DCs, load if necessary
430
+ [ ...document.querySelectorAll('[data-mc]:not([data-mc=""]') ]
545
431
  .filter( (element) => !!element )
546
432
  .forEach((el) => {
547
- const elements = el.getAttribute('_mc')?.split(' ').filter( m => !!m ) || [];
548
- const elementsToBeLoaded = elements.filter( m => !MCs.has( m ) );
549
-
550
- // load MC components that do not exist yet
551
- elementsToBeLoaded?.forEach( elementName => {
552
- const se: HTMLScriptElement = makeLoadScript( elementName );
553
-
554
- addListener( se, 'load', () => onLoadCallback( document.head.querySelector(`script[name="${elementName}"]`) as HTMLScriptElement) );
555
-
556
- MCs.set( elementName, 'loading');
557
-
558
- document.head.append(se);
559
- });
560
-
561
- // loading MC components already have callbacks attached
562
- const elementsAlreadyLoaded = elements.filter( m => MCs.has( m ) && !MCs.get( m )!.length);
563
-
564
- // MCs that are already loaded will trigger the onLoadCallback manually
565
- elementsAlreadyLoaded?.forEach( elementName => {
566
- setTimeout( ()=>{
567
- //console.log('attaching', elementName, (autoload as any).state.MCs.get(elementName));
568
- DC.add(el, elementName, new ( (autoload as any).state.MCs.get(elementName) as any)(el)); // add instance to DOM
569
-
570
- const newAttribute = (el as any).getAttribute('_mc')
571
- .replace('${elementName}', '')
572
- .replace( /\w\w/g, ' ')
573
- .trim() || '_mc';
574
-
575
- (el as any).setAttribute('_mc', ); // set new "_mc" attribute
576
- }, 5);
433
+ const _mc = el.getAttribute('data-mc')?.split(' ').filter( name => name !== '' );
434
+ _mc?.forEach( element => {
435
+ //console.log( 'detected DC', dc );
436
+ const isDefined = customElements.get(element);
437
+ if ( !loadingDCs.has(element) && !isDefined ) {
438
+ makeLoadScript( element );
439
+ } else if ( isDefined ) {
440
+ attachDC(element)();
441
+ }
577
442
  });
578
443
  });
579
444
  }
@@ -590,11 +455,11 @@ function autoload(enable: boolean = true): boolean {
590
455
  }
591
456
 
592
457
  autoloadEnabled = enable;
593
- observer = new MutationObserver(loadUndefinedMicroComponents);
458
+ observer = new MutationObserver(loadUndefinedMCs);
594
459
 
595
460
  setTimeout(() => {
596
461
  observer!.observe(document.body, { childList: true, subtree: true });
597
- loadUndefinedMicroComponents();
462
+ loadUndefinedMCs();
598
463
  }, 5);
599
464
 
600
465
  (window as any).autoload = (window as any).autoload || autoload;
@@ -602,7 +467,7 @@ function autoload(enable: boolean = true): boolean {
602
467
  return autoloadEnabled;
603
468
  }
604
469
 
605
- (autoload as LooseObject).state = { CEs, MCs };
470
+ (autoload as LooseObject).state = loadingDCs;
606
471
 
607
- export { addListener, removeListener, McBase, MC, DC, McEvent, autoload };
472
+ export { McBase, MC, DC, autoload, on, one, off, trigger };
608
473