@twobirds/microcomponents 0.1.21 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -92
  3. package/dist/MC.min.js +1 -345
  4. package/dist/autoload.min.js +1 -0
  5. package/dist/core/MC.d.ts +401 -0
  6. package/dist/core/MC.d.ts.map +1 -0
  7. package/dist/core/MC.js +471 -0
  8. package/dist/core/autoload.d.ts +54 -0
  9. package/dist/core/autoload.d.ts.map +1 -0
  10. package/dist/core/autoload.js +158 -0
  11. package/dist/core/elements.d.ts +232 -0
  12. package/dist/core/elements.d.ts.map +1 -0
  13. package/dist/core/elements.js +123 -0
  14. package/dist/core/events.d.ts +231 -0
  15. package/dist/core/events.d.ts.map +1 -0
  16. package/dist/core/events.js +228 -0
  17. package/dist/core/mcGuards.d.ts +49 -0
  18. package/dist/core/mcGuards.d.ts.map +1 -0
  19. package/dist/core/mcGuards.js +19 -0
  20. package/dist/elements.min.js +1 -1
  21. package/dist/events.min.js +1 -0
  22. package/dist/formValues.min.js +1 -1
  23. package/dist/mcGuards.min.js +1 -0
  24. package/dist/microcomponents.d.ts +8 -5
  25. package/dist/microcomponents.d.ts.map +1 -1
  26. package/dist/microcomponents.js +8 -5
  27. package/dist/microcomponents.min.js +1 -1
  28. package/dist/observables.min.js +1 -1
  29. package/dist/state/formValues.d.ts +70 -0
  30. package/dist/state/formValues.d.ts.map +1 -0
  31. package/dist/state/formValues.js +334 -0
  32. package/dist/state/observables.d.ts +276 -0
  33. package/dist/state/observables.d.ts.map +1 -0
  34. package/dist/state/observables.js +382 -0
  35. package/dist/state/placeholders.d.ts +62 -0
  36. package/dist/state/placeholders.d.ts.map +1 -0
  37. package/dist/state/placeholders.js +181 -0
  38. package/dist/types/mcTypes.d.ts +201 -0
  39. package/dist/types/mcTypes.d.ts.map +1 -0
  40. package/dist/types/mcTypes.js +9 -0
  41. package/dist/utils/helpers.d.ts +195 -0
  42. package/dist/utils/helpers.d.ts.map +1 -0
  43. package/dist/utils/helpers.js +340 -0
  44. package/package.json +96 -62
  45. package/dist/MC.d.ts +0 -31
  46. package/dist/MC.d.ts.map +0 -1
  47. package/dist/MC.js +0 -249
  48. package/dist/MC.ts +0 -613
  49. package/dist/MicroComponents.svg +0 -15
  50. package/dist/elements.d.ts +0 -5
  51. package/dist/elements.d.ts.map +0 -1
  52. package/dist/elements.js +0 -49
  53. package/dist/elements.ts +0 -114
  54. package/dist/events.d.ts +0 -11
  55. package/dist/events.d.ts.map +0 -1
  56. package/dist/events.js +0 -55
  57. package/dist/events.ts +0 -158
  58. package/dist/formValues.d.ts +0 -3
  59. package/dist/formValues.d.ts.map +0 -1
  60. package/dist/formValues.js +0 -156
  61. package/dist/formValues.ts +0 -371
  62. package/dist/helpers.d.ts +0 -15
  63. package/dist/helpers.d.ts.map +0 -1
  64. package/dist/helpers.js +0 -113
  65. package/dist/helpers.ts +0 -219
  66. package/dist/main.mjs +0 -1
  67. package/dist/microcomponents.ts +0 -6
  68. package/dist/observables.d.ts +0 -11
  69. package/dist/observables.d.ts.map +0 -1
  70. package/dist/observables.js +0 -228
  71. package/dist/observables.ts +0 -449
package/dist/MC.ts DELETED
@@ -1,613 +0,0 @@
1
- 'use strict';
2
-
3
- import { LooseObject } from './helpers.js';
4
- import { trigger, on, one, off, BubbleController } from './events.js';
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
- */
19
- const isBrowser = new Function('try {return this===window;}catch(e){ return false;}');
20
-
21
- /**
22
- Represents a DOM element that has been enhanced with microcomponent functionality.
23
-
24
- @template HTMLElement - The base HTML element type
25
- */
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
- */
39
- _mc: LooseObject;
40
- }
41
-
42
- function isDOM(element: { [key: string]: any }) {
43
- return element && element instanceof HTMLElement;
44
- }
45
-
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
- */
58
- function add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
59
- let node = target as HTMLMcElement;
60
-
61
- // create the _mc property if necessary
62
- if (!node._mc) {
63
- node._mc = new (DC as any)(target);
64
- }
65
-
66
- const _mc = node._mc;
67
-
68
- // add the element with the given property key to the _mc property
69
- if (key.length && !_mc[key]) {
70
- _mc[key] = element;
71
- // add attribute if HTMLElement
72
- if (target instanceof HTMLElement && !target.getAttribute('data-mc')) {
73
- target.setAttribute('data-mc', '');
74
- }
75
- }
76
-
77
- //console.warn('add() args: target, key, element', arguments, node);
78
-
79
- return node;
80
- }
81
-
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
- */
91
- function remove(target: HTMLElement, key: string) {
92
- if (!key) return; // silent fail
93
-
94
- const _mc = (target as unknown as HTMLMcElement)?._mc || {};
95
-
96
- // delete the property from the HTMLElement _mc collection
97
- if (_mc && _mc[key]) {
98
- delete _mc[key];
99
- }
100
-
101
- // remove the _mc attribute if the DOM collection is empty
102
- if (!Object.keys(_mc).length && target instanceof HTMLElement && target.hasAttribute('data-mc')) {
103
- target.removeAttribute('data-mc');
104
- }
105
- return;
106
- }
107
-
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
- */
117
- function init(element: DC) {
118
- //console.warn('init(): args', ...arguments);
119
- setTimeout(() => {
120
- if (element.constructor === DC) return;
121
- element.trigger('Init');
122
- }, 0);
123
- }
124
-
125
- /**
126
- Attaches event listeners to DOM elements based on method naming conventions.
127
-
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').
131
-
132
- @param {MC|DC} element - The instance whose prototype should be scanned for event handlers.
133
- */
134
- function autoAttachListeners(element: MC | DC) {
135
- if (!isBrowser() || element.constructor === DC) return;
136
-
137
- const target = element.target;
138
-
139
- if (target instanceof HTMLElement) {
140
- let that: LooseObject = element;
141
- Object.getOwnPropertyNames(that.constructor.prototype)
142
- .filter(
143
- (key) =>
144
- /^(on[A-Z]|one[A-Z])/.test(key) && typeof that.constructor.prototype[key] === 'function'
145
- )
146
- .forEach((key) => {
147
- let once = /^one/.test(key),
148
- withoutOnOne = key.replace(/^on[e]{0,1}/, ''), // preserves upper/lowercase for non-native events
149
- nativeEventName = withoutOnOne.toLowerCase(); // lowercase for native event names
150
-
151
- if ('on' + nativeEventName in target) {
152
- // it is a native HTML event
153
- let listener = (ev: Event) => {
154
- that[key](ev);
155
- };
156
- // console.log( 'AAL: attach native event listener', nativeEventName, 'to', target );
157
- target.addEventListener(nativeEventName, listener);
158
- } else {
159
- // it is a customEvent
160
- // console.log( 'AAL: attach custom event listener', '_mc' + withoutOnOne , 'to key', key, 'in', element );
161
- let listener = (ev: CustomEvent) => {
162
- that[key](ev);
163
- };
164
- on(target, withoutOnOne, listener as EventListenerOrEventListenerObject, once);
165
- }
166
- });
167
- }
168
- }
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
- */
181
- function getMcChildNodes(domNode: HTMLElement): DC[] | null {
182
- const id = Math.random().toString().replace('.', '');
183
- const selector = '[data-mc]:not([temp_id="' + id + '"] [data-mc] [data-mc])';
184
- domNode.setAttribute('temp_id', id);
185
- const mcArray: unknown[] = ([...domNode.querySelectorAll(selector)] as HTMLMcElement[])
186
- .filter((e) => !!e._mc)
187
- .map((e) => e._mc);
188
- domNode.removeAttribute('temp_id');
189
- return mcArray.length ? (mcArray as DC[]) : null;
190
- }
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
- */
199
- class McBase {
200
- private _target: WeakRef<any>; // avoid circular reference
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
- constructor(target?: { [key: string]: any }) {
211
- let element = this as unknown as MC | DC;
212
-
213
- this._target = new WeakRef(target || {});
214
-
215
- //console.warn('McBase: this, element, args', target, this, element, arguments);
216
-
217
- autoAttachListeners(element);
218
-
219
- init(element as DC); // async lifecycle event
220
- }
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
- */
229
- get target(): any {
230
- return this._target.deref();
231
- }
232
- }
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
- */
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
- */
246
- constructor(target?: any) {
247
- super(target);
248
- }
249
- }
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
- */
258
- class DC extends McBase {
259
- constructor(target: HTMLElement) {
260
- super(target);
261
- //console.warn('DC constructor:', arguments);
262
- }
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
- */
275
- static add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
276
- //console.warn('static DC.add() args', arguments);
277
- return add(target, key, element);
278
- }
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
- */
289
- static remove(target: HTMLElement, key: string) {
290
- remove(target, key);
291
- }
292
-
293
- /* event handling */
294
- off(eventName: string, handler: EventListenerOrEventListenerObject) {
295
- off(this.target, eventName, handler);
296
- }
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
- */
307
- on(
308
- eventName: string,
309
- handler: EventListenerOrEventListenerObject
310
- ): EventListenerOrEventListenerObject {
311
- return on(this.target, eventName, handler);
312
- }
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
- */
323
- one(
324
- eventName: string,
325
- handler: EventListenerOrEventListenerObject
326
- ): EventListenerOrEventListenerObject {
327
- return one(this.target, eventName, handler);
328
- }
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
- */
340
- trigger(eventName: string, data: any = {}, bubble: string = 'l', controller?: BubbleController) {
341
- //console.warn('MC.trigger args', ...arguments, this);
342
-
343
- trigger(this.target, eventName, data, bubble, controller);
344
- }
345
-
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
- */
354
- ancestors(): DC[] | null {
355
- let currentNode: HTMLElement | null = (this as DC)?.target as HTMLMcElement,
356
- result: DC[] = [];
357
-
358
- if (!isDOM(currentNode)) return [];
359
-
360
- while ((currentNode = currentNode.closest('[data-mc]'))) {
361
- if ((currentNode as HTMLMcElement)?._mc) {
362
- result.push((currentNode as HTMLMcElement)?._mc as DC);
363
- }
364
- }
365
-
366
- return result.length ? result : null;
367
- }
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
- */
376
- closest(): DC | null {
377
- let target: HTMLElement = (this as DC).target;
378
- if (!isDOM(target)) return null;
379
- return ((target.closest('[data-mc]') as HTMLMcElement)?._mc as DC) || null;
380
- }
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
- */
390
- children(): DC[] | null {
391
- let target: any = (this as any)?.target;
392
- if (!isDOM(target)) return null;
393
- return getMcChildNodes(target);
394
- }
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
- */
404
- descendants(): DC[] | null {
405
- const target: any = (this as DC)?.target;
406
- if (!isDOM(target)) return [];
407
- const mcArray: unknown[] = ([...target.querySelectorAll('[data-mc]')] as HTMLMcElement[])
408
- .filter((e) => !!e._mc)
409
- .map((e) => e._mc);
410
- return mcArray.length ? (mcArray as DC[]) : null;
411
- }
412
- }
413
-
414
- /*
415
- Autoload Section...
416
- */
417
-
418
- const loadingDCs = new Set<string>();
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
- */
434
- function attachDC(element: string): Function {
435
- return () => {
436
- const elements: HTMLElement[] = Array.from(
437
- document.querySelectorAll(`[data-mc*="${element}"]`)
438
- ).filter((element) => element instanceof HTMLElement) as HTMLElement[];
439
-
440
- if (elements.length === 0) return;
441
-
442
- //console.log( 'loadedPromise elements', elements );
443
-
444
- const Klass = customElements.get(element);
445
-
446
- elements.forEach((node: HTMLElement) => {
447
- try {
448
- //console.log( 'add', klass!.name, 'to', node );
449
- DC.add(node, Klass!.name, new Klass!(node));
450
- } catch (error) {
451
- if ((Klass as LooseObject)['create']) {
452
- let element: HTMLMcElement = (Klass as LooseObject).create(node);
453
- element.setAttribute('data-mc', node.getAttribute('data-mc')!);
454
- node.replaceWith(element);
455
- node = element;
456
- } else {
457
- throw `Class ${(Klass as LooseObject).name} doesn't have a callable constructor AND class doesn't have a static .create() method.`;
458
- }
459
- }
460
-
461
- //@ts-ignore: override - node may be null
462
- const new_mc = node
463
- .getAttribute('data-mc')
464
- .split(' ')
465
- .filter((name) => name !== element && name !== '')
466
- .join(' ')
467
- .trim();
468
-
469
- //@ts-ignore: override - node may be null
470
- node.setAttribute('data-mc', new_mc);
471
- });
472
- };
473
- }
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
- */
484
- function makeLoadScript(element: string) {
485
- if (loadingDCs.has(element)) return; // already loading
486
-
487
- loadingDCs.add(element);
488
-
489
- //console.log( 'makeLoadScript:', element);
490
- const fileName: string = './' + element.split('-').join('/') + '.js';
491
-
492
- const se: HTMLScriptElement = document.createElement('script');
493
-
494
- se.setAttribute('src', fileName);
495
- se.setAttribute('blocking', 'render');
496
- se.async = true;
497
- se.setAttribute('type', 'module');
498
- se.setAttribute('data-name', element);
499
- se.setAttribute('loading', '');
500
-
501
- const loadedPromise = customElements.whenDefined(element);
502
-
503
- //@ts-ignore: attachDC will return correct type
504
- loadedPromise.then(attachDC(element));
505
-
506
- se.addEventListener('load', (ev: Event) => {
507
- loadingDCs.delete(element);
508
-
509
- document.head.querySelector(`script[data-name="${element}"]`)?.remove();
510
- });
511
-
512
- se.addEventListener('error', (ev: Event) => {
513
- console.error('could not load DC code from', fileName);
514
- });
515
-
516
- document.head.append(se);
517
- }
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
- */
531
- function loadUndefinedMCs() {
532
- // load unresolved custom elements
533
- [...document.querySelectorAll(':not(:defined)')]
534
- .filter(
535
- (element) =>
536
- !!element &&
537
- !customElements.get(element.tagName.toLowerCase()) && // not in CustomElementsRegistry
538
- !loadingDCs.has(element.tagName.toLowerCase()) // not in loading list
539
- )
540
- .forEach((el) => {
541
- //console.log( 'detected CE', el.tagName.toLowerCase() );
542
- makeLoadScript(el.tagName.toLowerCase()); // will automatically be instanciated
543
- });
544
-
545
- // if defined in _mc attribute: instanciate DCs, load if necessary
546
- [...document.querySelectorAll('[data-mc]:not([data-mc=""]')]
547
- .filter((element) => !!element)
548
- .forEach((el) => {
549
- const _mc = el
550
- .getAttribute('data-mc')
551
- ?.split(' ')
552
- .filter((name) => name !== '');
553
- _mc?.forEach((element) => {
554
- //console.log( 'detected DC', dc );
555
- const isDefined = customElements.get(element);
556
- if (!loadingDCs.has(element) && !isDefined) {
557
- makeLoadScript(element);
558
- } else if (isDefined) {
559
- attachDC(element)();
560
- }
561
- });
562
- });
563
- }
564
-
565
- /**
566
- Enables or disables automatic detection and instantiation of microcomponents.
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;
580
- function autoload(enable: boolean = true): boolean {
581
- if (!enable) {
582
- if (observer) {
583
- observer.disconnect();
584
- observer = null;
585
- }
586
- return false;
587
- }
588
-
589
- const wasEnabled = !!observer;
590
- if (wasEnabled) return true;
591
-
592
- // Initialize observer only once
593
- observer = new MutationObserver(loadUndefinedMCs);
594
-
595
- setTimeout(() => {
596
- observer!.observe(document.body, { childList: true, subtree: true });
597
- loadUndefinedMCs();
598
- }, 5);
599
-
600
- (window as LooseObject).autoload = (window as LooseObject).autoload || autoload;
601
-
602
- return true;
603
- }
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
- */
611
- (autoload as LooseObject).state = loadingDCs;
612
-
613
- export { MC, DC, McBase, autoload };
@@ -1,15 +0,0 @@
1
- <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
2
- <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
3
- <title>test</title>
4
- <rect fill="transparent" x="0" y="0" width="200" height="200" fill-opacity="1"/>
5
- <g style="fill:transparent">
6
- <title>first bird</title>
7
- <path fill="#18829c" d="
8
- m15,160
9
- a30,75 45 1 0 160,-150
10
- a20,50 225 1 1 -110,100
11
- a12,25 45 1 1 60,-50
12
- a20,50 225 1 0 -110,100
13
- " />
14
- </g>
15
- </svg>
@@ -1,5 +0,0 @@
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
@@ -1 +0,0 @@
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"}
package/dist/elements.js DELETED
@@ -1,49 +0,0 @@
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
- }