@twobirds/microcomponents 0.1.21 → 0.1.23

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/elements.ts DELETED
@@ -1,114 +0,0 @@
1
- import { kebabToPascal } from './helpers.js';
2
- import { McBase, DC } from './MC.js';
3
-
4
- /**
5
- * Creates a named class constructor with the specified name.
6
- * @param name - The desired name for the class.
7
- * @param ClassBody - The class constructor to which the name will be assigned.
8
- * @returns The class constructor with the name property set.
9
- */
10
- function createNamedClass(name: string, ClassBody: { new (...args: any[]): any }) {
11
- return Object.defineProperty(ClassBody, 'name', { value: name });
12
- }
13
-
14
- /**
15
- * Defines a custom HTML element with optional observed attributes and micro component integration.
16
- * The class provided in DefinitionClass will be added to the ._mc hash object appended to the custom element instance.
17
- * Automatically assigns a "PascalCase" class name derived from the <kebab-case> tagName.
18
- * If the provided definition class extends McBase (indicating a DC or MC class extension), it wraps the constructor to register
19
- * the element instance with DC (DomComponent).
20
- *
21
- * @param tagName - The HTML tag name for the custom element (must contain at least one hyphen).
22
- * @param DefinitionClass - The constructor function or class that defines the element's behavior.
23
- * @param observedAttributes - An optional array of attribute names to observe for changes.
24
- */
25
- export function defineCE(
26
- tagName: string,
27
- DefinitionClass: { new (...args: any[]): any } | Function,
28
- observedAttributes: string[] = []
29
- ) {
30
- //console.warn('defineCE args', arguments);
31
-
32
- if (customElements.get(tagName)) {
33
- console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
34
- return;
35
- }
36
-
37
- if (!tagName.includes('-')) {
38
- throw new Error('createCustomElement: tagName must contain at least one hyphen ("-").');
39
- }
40
-
41
- let name = kebabToPascal(tagName);
42
-
43
- // a class, but not a MC
44
- if (!(DefinitionClass.prototype instanceof McBase)) {
45
- //console.warn('pure class', tagName, DefinitionClass);
46
- customElements.define(
47
- tagName,
48
- // @ts-ignore: DefinitionClass exists
49
- DefinitionClass
50
- );
51
- return;
52
- }
53
-
54
- //console.warn('MC class', tagName, DefinitionClass);
55
- // a MC
56
- customElements.define(
57
- tagName,
58
- createNamedClass(
59
- name,
60
- class extends HTMLElement {
61
- constructor(data?: any) {
62
- super();
63
- // console.log('[named class constructor]', tagName, name, this, data);
64
- // @ts-ignore: DefinitionClass exists
65
- DC.add(this, name, new DefinitionClass(this, data));
66
- }
67
-
68
- connectedCallback() {
69
- //console.warn('onConnected', this);
70
- this.dispatchEvent(new CustomEvent('_mcConnected'));
71
- }
72
-
73
- connectedMoveCallback() {
74
- //console.warn('onConnectedMove', this);
75
- this.dispatchEvent(new CustomEvent('_mcConnectedMove'));
76
- }
77
-
78
- disconnectedCallback() {
79
- //console.warn('onDisconnected', this);
80
- this.dispatchEvent(new CustomEvent('_mcDisconnected'));
81
- }
82
-
83
- adoptedCallback() {
84
- //console.warn('onAdopted', this);
85
- this.dispatchEvent(new CustomEvent('_mcAdopted'));
86
- }
87
-
88
- attributeChangedCallback(name: string, oldValue: any, newValue: any) {
89
- //console.warn('onAttributeChanged', this);
90
- this.dispatchEvent(
91
- new CustomEvent('_mcAttributeChanged', { detail: { name, oldValue, newValue } })
92
- );
93
- }
94
-
95
- formResetCallback() {
96
- this.dispatchEvent(new CustomEvent('_mcFormReset'));
97
- }
98
-
99
- static get observedAttributes() {
100
- return observedAttributes;
101
- }
102
- }
103
- )
104
- );
105
- }
106
-
107
- /**
108
- * Retrieves a custom element constructor by tag name.
109
- * @param tagName - The HTML tag name to look up.
110
- * @returns The CustomElementConstructor if defined, or undefined if not found.
111
- */
112
- export function getCE(tagName: string): CustomElementConstructor | undefined {
113
- return customElements.get(tagName);
114
- }
package/dist/events.d.ts DELETED
@@ -1,11 +0,0 @@
1
- export declare function getMcEventName(eventName: string): string;
2
- export declare function off(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject): void;
3
- export declare function on(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject, once?: boolean): EventListenerOrEventListenerObject;
4
- export declare function one(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject): EventListenerOrEventListenerObject;
5
- export declare class BubbleController {
6
- stopped: boolean;
7
- constructor();
8
- stop(): void;
9
- }
10
- export declare function trigger(domNode: HTMLElement, event: string, data?: any, bubble?: string, controller?: BubbleController): void;
11
- //# sourceMappingURL=events.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAaA,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAUD,wBAAgB,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kCAAkC,QAEhG;AAWD,wBAAgB,EAAE,CACjB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kCAAkC,EAC3C,IAAI,GAAE,OAAe,GACnB,kCAAkC,CAGpC;AAYD,wBAAgB,GAAG,CAClB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kCAAkC,GACzC,kCAAkC,CAGpC;AAUD,qBAAa,gBAAgB;IAC5B,OAAO,UAAS;;IAQhB,IAAI;CAGJ;AAmBD,wBAAgB,OAAO,CACtB,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,GAAQ,EACd,MAAM,GAAE,MAAY,EACpB,UAAU,CAAC,EAAE,gBAAgB,QA8C7B"}
package/dist/events.js DELETED
@@ -1,55 +0,0 @@
1
- 'use strict';
2
- export function getMcEventName(eventName) {
3
- return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
4
- }
5
- export function off(domNode, eventName, handler) {
6
- domNode.removeEventListener(getMcEventName(eventName), handler);
7
- }
8
- export function on(domNode, eventName, handler, once = false) {
9
- domNode.addEventListener(getMcEventName(eventName), handler, { capture: false, once });
10
- return handler;
11
- }
12
- export function one(domNode, eventName, handler) {
13
- on(domNode, eventName, handler, true);
14
- return handler;
15
- }
16
- export class BubbleController {
17
- stopped = false;
18
- constructor() { }
19
- stop() {
20
- this.stopped = true;
21
- }
22
- }
23
- export function trigger(domNode, event, data = {}, bubble = 'l', controller) {
24
- const eventName = /^_mc/.test(event) ? event : getMcEventName(event), bubbleController = controller ? controller : new BubbleController(), ev = new CustomEvent(eventName, {
25
- detail: { data, control: bubbleController },
26
- bubbles: false,
27
- });
28
- if (bubbleController.stopped)
29
- return;
30
- if (/l/.test(bubble)) {
31
- domNode.dispatchEvent(ev);
32
- ev.stopImmediatePropagation();
33
- if (bubbleController.stopped)
34
- return;
35
- }
36
- if (/[ud]/.test(bubble)) {
37
- if (bubble.indexOf('l') === -1) {
38
- bubble += 'l';
39
- }
40
- setTimeout(() => {
41
- if (bubble.indexOf('u') > -1) {
42
- let parentMc = domNode.parentElement?.closest('[data-mc]');
43
- if (parentMc) {
44
- parentMc?._mc.trigger(eventName, data, bubble, bubbleController);
45
- }
46
- }
47
- if (bubble.indexOf('d') > -1) {
48
- let childNodes = domNode._mc.children();
49
- if (childNodes) {
50
- childNodes.forEach((_mc) => _mc.trigger(eventName, data, bubble));
51
- }
52
- }
53
- }, 0);
54
- }
55
- }
package/dist/events.ts DELETED
@@ -1,158 +0,0 @@
1
- 'use strict';
2
-
3
- import { HTMLMcElement, DC } from './MC.js';
4
-
5
- /**
6
- @hidden
7
- Converts a standard event name to its microcomponent-prefixed variant.
8
-
9
- This utility is used internally to namespace custom events (e.g., 'Click' → '_mcClick').
10
-
11
- @param {string} eventName - The original event name (e.g., 'click', 'update').
12
- @returns {string} The microcomponent-prefixed event name.
13
- */
14
- export function getMcEventName(eventName: string): string {
15
- return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
16
- }
17
- /**
18
- Removes a previously attached event handler from the DOM node. See {@link on} and {@link one}.
19
-
20
- Uses internal microcomponent-prefixed naming for event handlers.
21
-
22
- @param {Node} domNode - The DOM element from which to remove the listener.
23
- @param {string} eventName - The name of the event (e.g., 'click', 'update').
24
- @param {EventListenerOrEventListenerObject} handler - The listener function or object to detach.
25
- */
26
- export function off(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject) {
27
- domNode.removeEventListener(getMcEventName(eventName), handler);
28
- }
29
-
30
- /**
31
- Attaches a persistent event listener that will fire every time the specified event occurs.
32
-
33
- @param {Node} domNode - The DOM element to attach the listener to.
34
- @param {string} eventName - The name of the event (e.g., 'click', 'update').
35
- @param {EventListenerOrEventListenerObject} handler - The callback function or object to invoke on each event.
36
- @param {boolean} [once=false] - If true, remove the listener after first invocation.
37
- @returns {EventListenerOrEventListenerObject} The attached handler reference. Useful for later deletion with {@link off}.
38
- */
39
- export function on(
40
- domNode: Node,
41
- eventName: string,
42
- handler: EventListenerOrEventListenerObject,
43
- once: boolean = false
44
- ): EventListenerOrEventListenerObject {
45
- domNode.addEventListener(getMcEventName(eventName), handler, { capture: false, once });
46
- return handler;
47
- }
48
- /**
49
- Attaches an event listener that will fire only once.
50
-
51
- Internally calls {@link on} with the `once` flag set to true. The handler
52
- is automatically removed after its first invocation.
53
-
54
- @param {Node} domNode - The DOM element to attach the listener to.
55
- @param {string} eventName - The name of the event (e.g., 'click', 'update').
56
- @param {EventListenerOrEventListenerObject} handler - The callback function or object to invoke once.
57
- @returns {EventListenerOrEventListenerObject} The attached one-time handler reference. Useful for later deletion with {@link off}.
58
- */
59
- export function one(
60
- domNode: Node,
61
- eventName: string,
62
- handler: EventListenerOrEventListenerObject
63
- ): EventListenerOrEventListenerObject {
64
- on(domNode, eventName, handler, true);
65
- return handler;
66
- }
67
-
68
- /**
69
- @hidden
70
- A controller object used to manage and potentially abort event bubbling.
71
-
72
- The `trigger()` function accepts an optional instance of this class,
73
- allowing the handler to call `.stop()` before or during dispatch to
74
- prevent further propagation in either direction (up/down).
75
- */
76
- export class BubbleController {
77
- stopped = false;
78
- constructor() {}
79
- /**
80
- Signals that event bubbling should be halted.
81
-
82
- After calling this method, subsequent `trigger()` calls will abort
83
- before dispatching the event to any targets.
84
- */
85
- stop() {
86
- this.stopped = true;
87
- }
88
- }
89
-
90
- /**
91
- Creates and dispatches a custom event on the specified DOM node.
92
-
93
- The event is namespaced with an `_mc` prefix by default, unless already prefixed.
94
- Supports bidirectional bubbling (up/down the DOM tree) based on the `bubble` parameter:
95
- - 'l': local dispatch only
96
- - 'u': bubble up towards ancestors
97
- - 'd': bubble down to descendants
98
-
99
- The optional `controller` allows aborting event propagation via `.stop()`.
100
-
101
- @param {HTMLElement} domNode - The DOM element on which to trigger the event.
102
- @param {string} event - The name of the event (will be prefixed if needed).
103
- @param {any} [data={}] - Additional data payload attached to `event.detail.data`.
104
- @param {string} [bubble='l'] - Bubbling direction ('l', 'u', 'd' or combinations).
105
- @param {BubbleController} [controller] - Optional controller for managing bubbling behavior.
106
- */
107
- export 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
- }
148
-
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
- }
@@ -1,3 +0,0 @@
1
- import { LooseObject } from './helpers.js';
2
- export declare function formValues(targetObject: LooseObject, propertyName: string, dom: HTMLElement | ShadowRoot): void;
3
- //# sourceMappingURL=formValues.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"formValues.d.ts","sourceRoot":"","sources":["../src/formValues.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,WAAW,EAAE,MAAM,cAAc,CAAC;AA4V/D,wBAAgB,UAAU,CACzB,YAAY,EAAE,WAAW,EACzB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,WAAW,GAAG,UAAU,QAkB7B"}
@@ -1,156 +0,0 @@
1
- import { DC } from './MC.js';
2
- import { copyGettersSetters } from './helpers.js';
3
- import { observe } from './observables.js';
4
- const getInputName = (e) => {
5
- return e.tagName.toLowerCase();
6
- };
7
- class InputBase {
8
- constructor(e) { }
9
- }
10
- class RadioHandler extends InputBase {
11
- #e;
12
- constructor(e) {
13
- super(e);
14
- this.#e = e;
15
- }
16
- get val() {
17
- let ret = new FormData(this.#e.form).get(this.#e.name);
18
- return ret;
19
- }
20
- set val(value) {
21
- let arr = [
22
- ...this.#e.form.querySelectorAll(`input[type="radio"][name="${this.#e.name}"]`),
23
- ];
24
- arr.filter((e) => e.getAttribute('value') === value).shift().checked =
25
- true;
26
- }
27
- }
28
- class CheckboxHandler extends InputBase {
29
- #e;
30
- constructor(e) {
31
- super(e);
32
- this.#e = e;
33
- }
34
- get val() {
35
- return this.#e.checked;
36
- }
37
- set val(value) {
38
- this.#e.checked = value;
39
- }
40
- }
41
- class InputHandler extends InputBase {
42
- #e;
43
- constructor(e) {
44
- super(e);
45
- this.#e = e;
46
- }
47
- get val() {
48
- return this.#e.value;
49
- }
50
- set val(value) {
51
- this.#e.value = value;
52
- }
53
- }
54
- class SelectHandler extends InputBase {
55
- #e;
56
- #multi = false;
57
- constructor(e) {
58
- super(e);
59
- this.#e = e;
60
- this.#multi = e.multiple;
61
- }
62
- get val() {
63
- const ret = [];
64
- [...this.#e.querySelectorAll('option')]
65
- .filter((o) => o.selected)
66
- .forEach((o) => {
67
- ret.push(o.value);
68
- });
69
- if (this.#multi)
70
- return ret;
71
- return ret.length ? ret[0] : '';
72
- }
73
- set val(value) {
74
- value = typeof value === 'string' ? [value] : value;
75
- [...this.#e.querySelectorAll('option')].forEach((o) => {
76
- if (value.indexOf(o.value) > -1) {
77
- o.selected = true;
78
- }
79
- else {
80
- o.selected = false;
81
- }
82
- });
83
- }
84
- }
85
- class TextAreaHandler extends InputBase {
86
- #e;
87
- constructor(e) {
88
- super(e);
89
- this.#e = e;
90
- }
91
- get val() {
92
- return this.#e.value || '';
93
- }
94
- set val(value) {
95
- this.#e.value = value;
96
- }
97
- }
98
- const getInputHandlers = (e) => {
99
- let inputList = [...(e || document).querySelectorAll('input,select,textarea')], handlers = {};
100
- inputList.forEach((input) => {
101
- const name = input.getAttribute('name');
102
- if (name) {
103
- let handler = false;
104
- switch (getInputName(input)) {
105
- case 'input':
106
- switch (input.type) {
107
- case 'radio':
108
- handler = new RadioHandler(input);
109
- break;
110
- case 'checkbox':
111
- handler = new CheckboxHandler(input);
112
- break;
113
- default:
114
- handler = new InputHandler(input);
115
- }
116
- break;
117
- case 'select':
118
- handler = new SelectHandler(input);
119
- break;
120
- case 'textarea':
121
- handler = new TextAreaHandler(input);
122
- break;
123
- default:
124
- console.warn('handler missing:', name, 'for', input.tagName.toLowerCase(), input);
125
- break;
126
- }
127
- if (handler) {
128
- DC.add(input, name, handler);
129
- Object.defineProperty(handlers, name, {
130
- enumerable: true,
131
- configurable: true,
132
- get: () => {
133
- return handler.val;
134
- },
135
- set: (value) => {
136
- if (handler.val !== value) {
137
- handler.val = value;
138
- }
139
- },
140
- });
141
- }
142
- }
143
- });
144
- return handlers;
145
- };
146
- export function formValues(targetObject, propertyName, dom) {
147
- let handlers = getInputHandlers(dom);
148
- targetObject[propertyName] = Object.assign({}, handlers);
149
- observe(targetObject, propertyName);
150
- copyGettersSetters(handlers, targetObject[propertyName]);
151
- [...dom.querySelectorAll('input, textarea, select')].forEach((input) => {
152
- input.addEventListener('input', (ev) => {
153
- targetObject[propertyName].notify();
154
- });
155
- });
156
- }