@twobirds/microcomponents 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/MC.ts CHANGED
@@ -1,10 +1,41 @@
1
1
  'use strict';
2
2
 
3
3
  import { LooseObject } from './helpers.js';
4
+ import { trigger, on, one, off, BubbleController } from './events.js';
4
5
 
6
+ /**
7
+ Determines whether the current runtime environment is a web browser.
8
+
9
+ This function works by attempting to access `this` within an anonymous function
10
+ and checking if it refers to the global `window` object. It returns `true`
11
+ when executed in a browser context, and `false` otherwise (e.g., Node.js).
12
+
13
+ Note: While modern environments typically provide more reliable detection mechanisms,
14
+ this fallback remains compatible across older runtimes where other detection techniques
15
+ may be unreliable.
16
+
17
+ @returns {boolean} `true` if the code is running in a browser environment, `false` otherwise.
18
+ */
5
19
  const isBrowser = new Function('try {return this===window;}catch(e){ return false;}');
6
20
 
21
+ /**
22
+ Represents a DOM element that has been enhanced with microcomponent functionality.
23
+
24
+ @template HTMLElement - The base HTML element type
25
+ */
7
26
  export interface HTMLMcElement extends HTMLElement {
27
+ /**
28
+ Hash object containing inner microcomponents, keyed by their unique identifiers (strings).
29
+ Each value is a reference to the corresponding `MicroComponent` instance or its configuration,
30
+ depending on the implementation.
31
+
32
+ This property allows direct access to nested microcomponents for programmatic interaction
33
+ (e.g., invoking methods or accessing state), and supports internal lifecycle management
34
+ such as mounting/unmounting or updating.
35
+
36
+ @type {LooseObject<MicroComponent>}
37
+ @readonly
38
+ */
8
39
  _mc: LooseObject;
9
40
  }
10
41
 
@@ -12,7 +43,18 @@ function isDOM(element: { [key: string]: any }) {
12
43
  return element && element instanceof HTMLElement;
13
44
  }
14
45
 
15
- // add a microcomponent to a target DOM node
46
+ /**
47
+ Adds a microcomponent instance to a target DOM node under the specified key.
48
+
49
+ This function initializes or updates the internal `_mc` collection on the target element,
50
+ which stores references to child microcomponents. It also adds the `data-mc` attribute
51
+ if missing, indicating that this DOM node hosts at least one microcomponent.
52
+
53
+ @param {HTMLElement} target - The DOM element to attach the microcomponent to.
54
+ @param {string} key - The property name/key under which the element will be stored in `_mc`.
55
+ @param {any} [element={}] - The microcomponent instance or configuration object to attach.
56
+ @returns {HTMLMcElement} The target DOM node, now enhanced with the attached microcomponent.
57
+ */
16
58
  function add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
17
59
  let node = target as HTMLMcElement;
18
60
 
@@ -37,7 +79,15 @@ function add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement
37
79
  return node;
38
80
  }
39
81
 
40
- // remove a micro component from the DOM
82
+ /**
83
+ Removes a named microcomponent from the internal `_mc` collection of a target DOM node.
84
+
85
+ This function deletes the specified key from the element's `_mc` hash object and, if the
86
+ collection becomes empty, removes the `data-mc` attribute from the DOM node.
87
+
88
+ @param {HTMLElement} target - The DOM element whose microcomponent should be removed.
89
+ @param {string} key - The property name/key corresponding to the microcomponent to remove.
90
+ */
41
91
  function remove(target: HTMLElement, key: string) {
42
92
  if (!key) return; // silent fail
43
93
 
@@ -55,7 +105,15 @@ function remove(target: HTMLElement, key: string) {
55
105
  return;
56
106
  }
57
107
 
58
- // run the "init" lifecycle event on the complete _mc structure
108
+ /**
109
+ Runs the "Init" lifecycle event on a microcomponent instance asynchronously.
110
+
111
+ This function schedules the `trigger('Init')` call within a zero-delay timeout,
112
+ ensuring that all synchronous initialization is complete before the lifecycle
113
+ hook executes. It skips execution for the base `DC` class itself.
114
+
115
+ @param {DC} element - The microcomponent instance on which to trigger the Init event.
116
+ */
59
117
  function init(element: DC) {
60
118
  //console.warn('init(): args', ...arguments);
61
119
  setTimeout(() => {
@@ -64,99 +122,15 @@ function init(element: DC) {
64
122
  }, 0);
65
123
  }
66
124
 
67
- // 'eventName' => '_mcEventName'
68
- function getMcEventName(eventName: string): string {
69
- return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
70
- }
71
-
72
- /*
73
- CustomEvent Section...
74
- */
75
- function off(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject) {
76
- domNode.removeEventListener(getMcEventName(eventName), handler);
77
- }
78
-
79
- function on(
80
- domNode: Node,
81
- eventName: string,
82
- handler: EventListenerOrEventListenerObject,
83
- once: boolean = false
84
- ): EventListenerOrEventListenerObject {
85
- domNode.addEventListener(getMcEventName(eventName), handler, { capture: false, once });
86
- return handler;
87
- }
88
-
89
- function one(
90
- domNode: Node,
91
- eventName: string,
92
- handler: EventListenerOrEventListenerObject
93
- ): EventListenerOrEventListenerObject {
94
- on(domNode, eventName, handler, true);
95
- return handler;
96
- }
97
-
98
- class BubbleController {
99
- stopped = false;
100
- constructor() {}
101
- stop() {
102
- this.stopped = true;
103
- }
104
- }
105
-
106
- // create and dispatch custom event
107
- function trigger(
108
- domNode: HTMLElement,
109
- event: string,
110
- data: any = {},
111
- bubble: string = 'l', // direction of bubbling
112
- controller?: BubbleController
113
- ) {
114
- //console.warn('trigger args', ...arguments);
115
-
116
- const eventName = /^_mc/.test(event) ? event : getMcEventName(event),
117
- bubbleController = controller ? controller : new BubbleController(),
118
- ev = new CustomEvent(eventName, {
119
- detail: { data, control: bubbleController },
120
- bubbles: false,
121
- });
122
-
123
- if (bubbleController.stopped) return;
124
-
125
- if (/l/.test(bubble)) {
126
- domNode.dispatchEvent(ev);
127
- ev.stopImmediatePropagation();
128
-
129
- if (bubbleController.stopped) return;
130
- }
131
-
132
- // bubble if up or down is indicated
133
- if (/[ud]/.test(bubble)) {
134
- // add missing 'l', or else no handlers are executed
135
- if (bubble.indexOf('l') === -1) {
136
- bubble += 'l';
137
- }
138
-
139
- setTimeout(() => {
140
- // bubble up towards document.body
141
- if (bubble.indexOf('u') > -1) {
142
- let parentMc: HTMLMcElement | null | undefined =
143
- domNode.parentElement?.closest('[data-mc]');
144
- if (parentMc) {
145
- parentMc?._mc.trigger(eventName, data, bubble, bubbleController);
146
- }
147
- }
125
+ /**
126
+ Attaches event listeners to DOM elements based on method naming conventions.
148
127
 
149
- // bubble down towards DOM children
150
- if (bubble.indexOf('d') > -1) {
151
- let childNodes: DC[] | null = (domNode as HTMLMcElement)._mc.children();
152
- if (childNodes) {
153
- childNodes.forEach((_mc: DC) => _mc.trigger(eventName, data, bubble)); // event multiplex - dont carry bubble controller
154
- }
155
- }
156
- }, 0);
157
- }
158
- }
128
+ Scans the prototype of the provided element and attaches listeners for methods
129
+ prefixed with `on` or `one`, corresponding to either native HTML events (e.g.,
130
+ 'onclick') or microcomponent-prefixed custom events (e.g., '_mcUpdate').
159
131
 
132
+ @param {MC|DC} element - The instance whose prototype should be scanned for event handlers.
133
+ */
160
134
  function autoAttachListeners(element: MC | DC) {
161
135
  if (!isBrowser() || element.constructor === DC) return;
162
136
 
@@ -193,6 +167,17 @@ function autoAttachListeners(element: MC | DC) {
193
167
  }
194
168
  }
195
169
 
170
+ /**
171
+ Retrieves immediate child microcomponents of a DOM node.
172
+
173
+ Queries the DOM for descendant elements marked with `data-mc` that are direct
174
+ children of the provided element and returns their associated `_mc` instances.
175
+ Temporarily sets an internal attribute on the node to prevent recursive matches
176
+ within nested subtrees.
177
+
178
+ @param {HTMLElement} domNode - The DOM element whose child microcomponents to find.
179
+ @returns {DC[]|null} An array of child microcomponent instances, or null if none found.
180
+ */
196
181
  function getMcChildNodes(domNode: HTMLElement): DC[] | null {
197
182
  const id = Math.random().toString().replace('.', '');
198
183
  const selector = '[data-mc]:not([temp_id="' + id + '"] [data-mc] [data-mc])';
@@ -204,9 +189,24 @@ function getMcChildNodes(domNode: HTMLElement): DC[] | null {
204
189
  return mcArray.length ? (mcArray as DC[]) : null;
205
190
  }
206
191
 
192
+ /**
193
+ The base class for all microcomponents.
194
+
195
+ Implements a `WeakRef` to the target DOM element or other data, avoiding
196
+ circular references. Automatically triggers the "Init" lifecycle event and
197
+ attaches listeners via `autoAttachListeners` upon construction.
198
+ */
207
199
  class McBase {
208
200
  private _target: WeakRef<any>; // avoid circular reference
209
201
 
202
+ /**
203
+ The constructor for the base `McBase` class.
204
+
205
+ Initializes a weak reference to the target and triggers auto-attachment
206
+ of listeners and initialization lifecycle events.
207
+
208
+ @param {any} [target={}] - The object or element this microcomponent represents.
209
+ */
210
210
  constructor(target?: { [key: string]: any }) {
211
211
  let element = this as unknown as MC | DC;
212
212
 
@@ -219,28 +219,73 @@ class McBase {
219
219
  init(element as DC); // async lifecycle event
220
220
  }
221
221
 
222
+ /**
223
+ Returns the current target object (DOM node or other data) referenced by this microcomponent.
224
+
225
+ Uses a `WeakRef` internally to avoid circular references, and safely dereferences it here.
226
+
227
+ @returns {any} The target object, or undefined if the reference has been garbage collected.
228
+ */
222
229
  get target(): any {
223
230
  return this._target.deref();
224
231
  }
225
232
  }
226
233
 
234
+ /**
235
+ A general-purpose base microcomponent that does not require a DOM target.
236
+
237
+ Inherits from `McBase`, but is primarily used as a lightweight container or
238
+ for logic not directly tied to DOM elements.
239
+ */
227
240
  class MC extends McBase {
241
+ /**
242
+ Constructs an instance of the general-purpose microcomponent.
243
+
244
+ @param {any} [target=undefined] - Optional target object or data.
245
+ */
228
246
  constructor(target?: any) {
229
247
  super(target);
230
248
  }
231
249
  }
232
250
 
251
+ /**
252
+ A DOM-centric microcomponent that operates on a specific HTML element.
253
+
254
+ Extends `McBase` and associates itself with an actual DOM node via the
255
+ `_target` reference. Provides methods for event handling, DOM traversal,
256
+ and interaction with sibling or ancestor microcomponents.
257
+ */
233
258
  class DC extends McBase {
234
259
  constructor(target: HTMLElement) {
235
260
  super(target);
236
261
  //console.warn('DC constructor:', arguments);
237
262
  }
238
263
 
264
+ /**
265
+ Static helper to attach a microcomponent instance to a DOM element.
266
+
267
+ Wrapper around the `add()` utility function, providing a class-level API
268
+ for adding child microcomponents to a target node.
269
+
270
+ @param {HTMLElement} target - The DOM element to which to attach the microcomponent.
271
+ @param {string} key - The property name/key under which to store the instance in `_mc`.
272
+ @param {any} [element={}] - The microcomponent instance or config object to attach.
273
+ @returns {HTMLMcElement} The target DOM element with the attached microcomponent.
274
+ */
239
275
  static add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
240
276
  //console.warn('static DC.add() args', arguments);
241
277
  return add(target, key, element);
242
278
  }
243
279
 
280
+ /**
281
+ Static helper to remove a named microcomponent from a DOM element.
282
+
283
+ Wrapper around the `remove()` utility function, providing a class-level API
284
+ for removing child microcomponents.
285
+
286
+ @param {HTMLElement} target - The DOM element from which to remove the microcomponent.
287
+ @param {string} key - The property name/key corresponding to the microcomponent to remove.
288
+ */
244
289
  static remove(target: HTMLElement, key: string) {
245
290
  remove(target, key);
246
291
  }
@@ -250,6 +295,15 @@ class DC extends McBase {
250
295
  off(this.target, eventName, handler);
251
296
  }
252
297
 
298
+ /**
299
+ Attaches a persistent event listener to the DOM node.
300
+
301
+ This is an instance method wrapper for `on()`, using the internal `_target` DOM reference.
302
+
303
+ @param {string} eventName - The name of the event (e.g., 'click', 'update').
304
+ @param {EventListenerOrEventListenerObject} handler - The callback function or object to invoke.
305
+ @returns {EventListenerOrEventListenerObject} The attached handler reference.
306
+ */
253
307
  on(
254
308
  eventName: string,
255
309
  handler: EventListenerOrEventListenerObject
@@ -257,6 +311,15 @@ class DC extends McBase {
257
311
  return on(this.target, eventName, handler);
258
312
  }
259
313
 
314
+ /**
315
+ Attaches a one-time event listener to the DOM node.
316
+
317
+ This is an instance method wrapper for `one()`, using the internal `_target` DOM reference.
318
+
319
+ @param {string} eventName - The name of the event (e.g., 'click', 'update').
320
+ @param {EventListenerOrEventListenerObject} handler - The callback function or object to invoke once.
321
+ @returns {EventListenerOrEventListenerObject} The attached one-time handler reference.
322
+ */
260
323
  one(
261
324
  eventName: string,
262
325
  handler: EventListenerOrEventListenerObject
@@ -264,13 +327,30 @@ class DC extends McBase {
264
327
  return one(this.target, eventName, handler);
265
328
  }
266
329
 
330
+ /**
331
+ Triggers a custom event on the DOM node and optionally bubbles it.
332
+
333
+ This is an instance method wrapper for `trigger()`, using the internal `_target` DOM reference.
334
+
335
+ @param {string} eventName - The name of the event (will be prefixed if needed).
336
+ @param {any} [data={}] - Additional data payload attached to `event.detail.data`.
337
+ @param {string} [bubble='l'] - Bubbling direction ('l', 'u', 'd' or combinations).
338
+ @param {BubbleController} [controller] - Optional controller for managing bubbling behavior.
339
+ */
267
340
  trigger(eventName: string, data: any = {}, bubble: string = 'l', controller?: BubbleController) {
268
341
  //console.warn('MC.trigger args', ...arguments, this);
269
342
 
270
343
  trigger(this.target, eventName, data, bubble, controller);
271
344
  }
272
345
 
273
- /* DOM traversal */
346
+ /**
347
+ Returns an array of all ancestor microcomponents up the DOM tree.
348
+
349
+ Traverses upward from this element's target, collecting all ancestor
350
+ elements marked with `data-mc` and returning their `_mc` instances.
351
+
352
+ @returns {DC[]|null} An array of ancestor microcomponent instances, or null if none found.
353
+ */
274
354
  ancestors(): DC[] | null {
275
355
  let currentNode: HTMLElement | null = (this as DC)?.target as HTMLMcElement,
276
356
  result: DC[] = [];
@@ -286,18 +366,41 @@ class DC extends McBase {
286
366
  return result.length ? result : null;
287
367
  }
288
368
 
369
+ /**
370
+ Returns the closest ancestor microcomponent or null if none found.
371
+
372
+ This method is equivalent to calling `ancestors()[0]`, but more concise.
373
+
374
+ @returns {DC|null} The nearest ancestor microcomponent, or null if not found.
375
+ */
289
376
  closest(): DC | null {
290
377
  let target: HTMLElement = (this as DC).target;
291
378
  if (!isDOM(target)) return null;
292
379
  return ((target.closest('[data-mc]') as HTMLMcElement)?._mc as DC) || null;
293
380
  }
294
381
 
382
+ /**
383
+ Returns an array of direct child microcomponents.
384
+
385
+ Calls `getMcChildNodes()` internally to find immediate descendants only,
386
+ excluding nested grandchildren and deeper levels.
387
+
388
+ @returns {DC[]|null} An array of child microcomponent instances, or null if none found.
389
+ */
295
390
  children(): DC[] | null {
296
391
  let target: any = (this as any)?.target;
297
392
  if (!isDOM(target)) return null;
298
393
  return getMcChildNodes(target);
299
394
  }
300
395
 
396
+ /**
397
+ Returns an array of all descendant microcomponents recursively.
398
+
399
+ Uses a `querySelectorAll` query to collect every nested element marked with
400
+ `data-mc`, returning their associated `_mc` instances.
401
+
402
+ @returns {DC[]|null} An array of descendant microcomponent instances, or null if none found.
403
+ */
301
404
  descendants(): DC[] | null {
302
405
  const target: any = (this as DC)?.target;
303
406
  if (!isDOM(target)) return [];
@@ -314,12 +417,25 @@ Autoload Section...
314
417
 
315
418
  const loadingDCs = new Set<string>();
316
419
 
420
+ /**
421
+ Creates a closure that attaches DOM elements with the specified tag name to
422
+ their corresponding microcomponent instances.
423
+
424
+ Used internally by `makeLoadScript()` when dynamically loading external
425
+ custom element definitions. The returned function is invoked after the
426
+ element definition becomes available, and performs:
427
+ - Querying of all matching elements in the DOM
428
+ - Instantiation of new `DC` instances
429
+ - Attachment to each DOM node via `DC.add()`
430
+
431
+ @param {string} element - The tag name (custom element name) of the microcomponent to instantiate.
432
+ @returns {Function} A closure that performs the attachment logic when invoked.
433
+ */
317
434
  function attachDC(element: string): Function {
318
- //@ts-ignore
319
435
  return () => {
320
436
  const elements: HTMLElement[] = Array.from(
321
437
  document.querySelectorAll(`[data-mc*="${element}"]`)
322
- ).filter((element) => element instanceof HTMLElement);
438
+ ).filter((element) => element instanceof HTMLElement) as HTMLElement[];
323
439
 
324
440
  if (elements.length === 0) return;
325
441
 
@@ -342,7 +458,7 @@ function attachDC(element: string): Function {
342
458
  }
343
459
  }
344
460
 
345
- //@ts-ignore
461
+ //@ts-ignore: override - node may be null
346
462
  const new_mc = node
347
463
  .getAttribute('data-mc')
348
464
  .split(' ')
@@ -350,16 +466,21 @@ function attachDC(element: string): Function {
350
466
  .join(' ')
351
467
  .trim();
352
468
 
353
- //@ts-ignore
354
- node.setAttribute(
355
- 'data-mc',
356
- //@ts-ignore
357
- new_mc
358
- );
469
+ //@ts-ignore: override - node may be null
470
+ node.setAttribute('data-mc', new_mc);
359
471
  });
360
472
  };
361
473
  }
362
474
 
475
+ /**
476
+ Dynamically loads and registers a custom element definition from an external JS file.
477
+
478
+ Constructs the script URL based on kebab-case naming (e.g., `my-element` → `./my/element.js`).
479
+ Registers a handler to be executed once the element is defined, then appends the
480
+ `<script>` tag to `<head>`. Handles both successful loading and error cases.
481
+
482
+ @param {string} element - The custom element tag name (e.g., 'mc-button', 'my-widget').
483
+ */
363
484
  function makeLoadScript(element: string) {
364
485
  if (loadingDCs.has(element)) return; // already loading
365
486
 
@@ -379,7 +500,7 @@ function makeLoadScript(element: string) {
379
500
 
380
501
  const loadedPromise = customElements.whenDefined(element);
381
502
 
382
- //@ts-ignore
503
+ //@ts-ignore: attachDC will return correct type
383
504
  loadedPromise.then(attachDC(element));
384
505
 
385
506
  se.addEventListener('load', (ev: Event) => {
@@ -395,6 +516,18 @@ function makeLoadScript(element: string) {
395
516
  document.head.append(se);
396
517
  }
397
518
 
519
+ /**
520
+ Scans the DOM for undefined custom elements and pending microcomponents,
521
+ then loads their definitions if necessary.
522
+
523
+ This is the main driver function for the autoload mechanism. It performs:
524
+ 1. Finds all undefined custom elements in the document
525
+ 2. Checks whether they are already loading or defined
526
+ 3. Calls `makeLoadScript()` to fetch missing definitions
527
+ 4. Invokes `attachDC()` where element definitions exist but haven't been attached yet
528
+
529
+ It is called both immediately after enabling autoload and on each DOM mutation.
530
+ */
398
531
  function loadUndefinedMCs() {
399
532
  // load unresolved custom elements
400
533
  [...document.querySelectorAll(':not(:defined)')]
@@ -429,17 +562,34 @@ function loadUndefinedMCs() {
429
562
  });
430
563
  }
431
564
 
432
- let autoloadEnabled: boolean = false;
433
- let observer: MutationObserver | null = null;
565
+ /**
566
+ Enables or disables automatic detection and instantiation of microcomponents.
434
567
 
568
+ When enabled, the system uses a `MutationObserver` to watch for newly-added
569
+ DOM nodes. For each such node:
570
+ - If it contains custom elements that are not yet defined, attempts to load them
571
+ - If it references undefined microcomponent names in its `data-mc` attribute,
572
+ those definitions are also loaded and attached.
573
+
574
+ When disabled, the observer is disconnected and all internal tracking state is reset.
575
+
576
+ @param {boolean} [enable=true] - Whether to enable or disable auto-loading behavior.
577
+ @returns {boolean} The new autoload state (true if enabled, false otherwise).
578
+ */
579
+ let observer: MutationObserver | null = null;
435
580
  function autoload(enable: boolean = true): boolean {
436
581
  if (!enable) {
437
- observer?.disconnect();
438
- observer = null;
439
- return autoloadEnabled;
582
+ if (observer) {
583
+ observer.disconnect();
584
+ observer = null;
585
+ }
586
+ return false;
440
587
  }
441
588
 
442
- autoloadEnabled = enable;
589
+ const wasEnabled = !!observer;
590
+ if (wasEnabled) return true;
591
+
592
+ // Initialize observer only once
443
593
  observer = new MutationObserver(loadUndefinedMCs);
444
594
 
445
595
  setTimeout(() => {
@@ -449,9 +599,15 @@ function autoload(enable: boolean = true): boolean {
449
599
 
450
600
  (window as LooseObject).autoload = (window as LooseObject).autoload || autoload;
451
601
 
452
- return autoloadEnabled;
602
+ return true;
453
603
  }
454
604
 
605
+ /**
606
+ The internal `loadingDCs` set, exposed for external inspection.
607
+
608
+ This property is attached to the `autoload()` function itself and contains
609
+ the names of microcomponent classes currently being loaded (or queued to load).
610
+ */
455
611
  (autoload as LooseObject).state = loadingDCs;
456
612
 
457
- export { McBase, MC, DC, autoload, on, one, off, trigger };
613
+ export { MC, DC, McBase, autoload };
@@ -0,0 +1,5 @@
1
+ export declare function defineCE(tagName: string, DefinitionClass: {
2
+ new (...args: any[]): any;
3
+ } | Function, observedAttributes?: string[]): void;
4
+ export declare function getCE(tagName: string): CustomElementConstructor | undefined;
5
+ //# sourceMappingURL=elements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elements.d.ts","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAwBA,wBAAgB,QAAQ,CACvB,OAAO,EAAE,MAAM,EACf,eAAe,EAAE;IAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAAA;CAAE,GAAG,QAAQ,EACzD,kBAAkB,GAAE,MAAM,EAAO,QA6EjC;AAOD,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,GAAG,SAAS,CAE3E"}
@@ -0,0 +1,49 @@
1
+ import { kebabToPascal } from './helpers.js';
2
+ import { McBase, DC } from './MC.js';
3
+ function createNamedClass(name, ClassBody) {
4
+ return Object.defineProperty(ClassBody, 'name', { value: name });
5
+ }
6
+ export function defineCE(tagName, DefinitionClass, observedAttributes = []) {
7
+ if (customElements.get(tagName)) {
8
+ console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
9
+ return;
10
+ }
11
+ if (!tagName.includes('-')) {
12
+ throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');
13
+ }
14
+ let name = kebabToPascal(tagName);
15
+ if (!(DefinitionClass.prototype instanceof McBase)) {
16
+ customElements.define(tagName, DefinitionClass);
17
+ return;
18
+ }
19
+ customElements.define(tagName, createNamedClass(name, class extends HTMLElement {
20
+ constructor(data) {
21
+ super();
22
+ DC.add(this, name, new DefinitionClass(this, data));
23
+ }
24
+ connectedCallback() {
25
+ this.dispatchEvent(new CustomEvent('_mcConnected'));
26
+ }
27
+ connectedMoveCallback() {
28
+ this.dispatchEvent(new CustomEvent('_mcConnectedMove'));
29
+ }
30
+ disconnectedCallback() {
31
+ this.dispatchEvent(new CustomEvent('_mcDisconnected'));
32
+ }
33
+ adoptedCallback() {
34
+ this.dispatchEvent(new CustomEvent('_mcAdopted'));
35
+ }
36
+ attributeChangedCallback(name, oldValue, newValue) {
37
+ this.dispatchEvent(new CustomEvent('_mcAttributeChanged', { detail: { name, oldValue, newValue } }));
38
+ }
39
+ formResetCallback() {
40
+ this.dispatchEvent(new CustomEvent('_mcFormReset'));
41
+ }
42
+ static get observedAttributes() {
43
+ return observedAttributes;
44
+ }
45
+ }));
46
+ }
47
+ export function getCE(tagName) {
48
+ return customElements.get(tagName);
49
+ }
@@ -0,0 +1 @@
1
+ var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};function n(t){return"_mc"+t[0].toUpperCase()+t.substring(1)}function r(t,e,r,c=!1){return t.addEventListener(n(e),r,{capture:!1,once:c}),r}t.d(e,{c:()=>l,t:()=>u});class c{stopped=!1;constructor(){}stop(){this.stopped=!0}}const o=new Function("try {return this===window;}catch(e){ return false;}");function s(t){return t&&t instanceof HTMLElement}class a{_target;constructor(t){var e;this._target=new WeakRef(t||{}),function(t){if(!o()||t.constructor===i)return;const e=t.target;if(e instanceof HTMLElement){let n=t;Object.getOwnPropertyNames(n.constructor.prototype).filter((t=>/^(on[A-Z]|one[A-Z])/.test(t)&&"function"==typeof n.constructor.prototype[t])).forEach((t=>{let c=/^one/.test(t),o=t.replace(/^on[e]{0,1}/,""),s=o.toLowerCase();if("on"+s in e){let r=e=>{n[t](e)};e.addEventListener(s,r)}else r(e,o,(e=>{n[t](e)}),c)}))}}(this),e=this,setTimeout((()=>{e.constructor!==i&&e.trigger("Init")}),0)}get target(){return this._target.deref()}}class i extends a{constructor(t){super(t)}static add(t,e,n={}){return function(t,e,n={}){let r=t;r._mc||(r._mc=new i(t));const c=r._mc;return e.length&&!c[e]&&(c[e]=n,t instanceof HTMLElement&&!t.getAttribute("data-mc")&&t.setAttribute("data-mc","")),r}(t,e,n)}static remove(t,e){!function(t,e){if(!e)return;const n=t?._mc||{};n&&n[e]&&delete n[e],!Object.keys(n).length&&t instanceof HTMLElement&&t.hasAttribute("data-mc")&&t.removeAttribute("data-mc")}(t,e)}off(t,e){!function(t,e,r){t.removeEventListener(n(e),r)}(this.target,t,e)}on(t,e){return r(this.target,t,e)}one(t,e){return function(t,e,n){return r(t,e,n,!0),n}(this.target,t,e)}trigger(t,e={},r="l",o){!function(t,e,r={},o="l",s){const a=/^_mc/.test(e)?e:n(e),i=s||new c,l=new CustomEvent(a,{detail:{data:r,control:i},bubbles:!1});i.stopped||/l/.test(o)&&(t.dispatchEvent(l),l.stopImmediatePropagation(),i.stopped)||/[ud]/.test(o)&&(-1===o.indexOf("l")&&(o+="l"),setTimeout((()=>{if(o.indexOf("u")>-1){let e=t.parentElement?.closest("[data-mc]");e&&e?._mc.trigger(a,r,o,i)}if(o.indexOf("d")>-1){let e=t._mc.children();e&&e.forEach((t=>t.trigger(a,r,o)))}}),0))}(this.target,t,e,r,o)}ancestors(){let t=this?.target,e=[];if(!s(t))return[];for(;t=t.closest("[data-mc]");)t?._mc&&e.push(t?._mc);return e.length?e:null}closest(){let t=this.target;return s(t)&&t.closest("[data-mc]")?._mc||null}children(){let t=this?.target;return s(t)?function(t){const e=Math.random().toString().replace(".",""),n='[data-mc]:not([temp_id="'+e+'"] [data-mc] [data-mc])';t.setAttribute("temp_id",e);const r=[...t.querySelectorAll(n)].filter((t=>!!t._mc)).map((t=>t._mc));return t.removeAttribute("temp_id"),r.length?r:null}(t):null}descendants(){const t=this?.target;if(!s(t))return[];const e=[...t.querySelectorAll("[data-mc]")].filter((t=>!!t._mc)).map((t=>t._mc));return e.length?e:null}}function l(t,e,n=[]){if(customElements.get(t))return void console.warn(`IGNORED: Custom element "${t}" is already defined!`);if(!t.includes("-"))throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');let r=t.split("-").map((t=>t.charAt(0).toUpperCase()+t.slice(1))).join("");e.prototype instanceof a?customElements.define(t,function(t,e){return Object.defineProperty(e,"name",{value:t})}(r,class extends HTMLElement{constructor(t){super(),i.add(this,r,new e(this,t))}connectedCallback(){this.dispatchEvent(new CustomEvent("_mcConnected"))}connectedMoveCallback(){this.dispatchEvent(new CustomEvent("_mcConnectedMove"))}disconnectedCallback(){this.dispatchEvent(new CustomEvent("_mcDisconnected"))}adoptedCallback(){this.dispatchEvent(new CustomEvent("_mcAdopted"))}attributeChangedCallback(t,e,n){this.dispatchEvent(new CustomEvent("_mcAttributeChanged",{detail:{name:t,oldValue:e,newValue:n}}))}formResetCallback(){this.dispatchEvent(new CustomEvent("_mcFormReset"))}static get observedAttributes(){return n}})):customElements.define(t,e)}function u(t){return customElements.get(t)}new Set;var m=e.c,d=e.t;export{m as defineCE,d as getCE};