@twobirds/microcomponents 0.0.48 → 0.0.50
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/assets/Grandparent.css +13 -0
- package/assets/documentation/MC.md +380 -166
- package/assets/test.html +5 -1
- package/dist/MC.d.ts +1 -0
- package/dist/MC.d.ts.map +1 -1
- package/dist/MC.min.js +44 -0
- package/dist/MC.ts +65 -0
- package/dist/elements.min.js +1 -1
- package/dist/elements.ts +10 -10
- package/dist/formValues.d.ts +3 -2
- package/dist/formValues.d.ts.map +1 -1
- package/dist/formValues.ts +206 -203
- package/dist/formvValues.min.js +1 -1
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.ts +9 -0
- package/dist/microcomponents.min.js +1 -1
- package/dist/observables.d.ts +1 -1
- package/dist/observables.d.ts.map +1 -1
- package/dist/observables.min.js +1 -1
- package/dist/observables.ts +64 -31
- package/dist/selectors.min.js +1 -1
- package/dist/test.ts +8 -5
- package/package.json +1 -1
- package/public/Grandparent.css +13 -0
- package/public/Grandparent.js +338 -0
- package/public/MC.js +43 -0
- package/public/MC.js.map +1 -1
- package/public/MC.min.js +44 -0
- package/public/TestForm.css +47 -0
- package/public/TestForm.html +56 -0
- package/public/TestForm.js +56 -0
- package/public/TestForm.json +27 -0
- package/public/Testform.js +149 -0
- package/public/classes/MC.DC.html +13 -13
- package/public/classes/MC.MC.html +7 -7
- package/public/classes/MC.McBase.html +4 -4
- package/public/classes/MC.McEvent.html +13 -13
- package/public/documentation/MC.md +380 -166
- package/public/documentation/observe.md +317 -0
- package/public/elements.js +9 -9
- package/public/elements.js.map +1 -1
- package/public/elements.min.js +1 -1
- package/public/formValues.js +142 -133
- package/public/formValues.js.map +1 -1
- package/public/formvValues.min.js +1 -1
- package/public/functions/MC.addListener.html +1 -1
- package/public/functions/MC.removeListener.html +1 -1
- package/public/functions/elements.defineCE.html +1 -1
- package/public/functions/elements.getCE.html +1 -1
- package/public/functions/formValues.formValues.html +1 -1
- package/public/functions/observables.observe.html +1 -1
- package/public/functions/selectors._d.html +1 -1
- package/public/functions/selectors._t.html +1 -1
- package/public/helpers.js +8 -0
- package/public/helpers.js.map +1 -1
- package/public/interfaces/MC.HTMLMcElement.html +2 -2
- package/public/interfaces/selectors.DSelector.html +55 -55
- package/public/interfaces/selectors.TSelector.html +37 -37
- package/public/microcomponents.min.js +1 -1
- package/public/modules/MC.html +1 -1
- package/public/modules/elements.html +1 -1
- package/public/modules/formValues.html +1 -1
- package/public/modules/observables.html +1 -1
- package/public/modules/selectors.html +1 -1
- package/public/observables.js +31 -19
- package/public/observables.js.map +1 -1
- package/public/observables.min.js +1 -1
- package/public/selectors.min.js +1 -1
- package/public/src/MC.ts +65 -0
- package/public/src/elements.ts +10 -10
- package/public/src/formValues.ts +206 -203
- package/public/src/helpers.ts +9 -0
- package/public/src/observables.ts +64 -31
- package/public/src/test.ts +8 -5
- package/public/test/Grandparent.js +1 -0
- package/public/test/Testform.js +1 -0
- package/public/test.html +5 -1
- package/public/test.js +3 -4
- package/public/test.js.map +1 -1
- package/public/types/observables.Observable.html +1 -1
- package/public/types/selectors.selection.html +1 -1
- package/public/types/selectors.singleSelector.html +1 -1
- package/src/MC.ts +65 -0
- package/src/elements.ts +10 -10
- package/src/formValues.ts +206 -203
- package/src/helpers.ts +9 -0
- package/src/observables.ts +64 -31
- package/src/test/Child.ts +21 -0
- package/src/test/Grandchild.ts +21 -0
- package/src/test/Grandparent.css +11 -0
- package/src/test/Grandparent.ts +21 -0
- package/src/test/Greatgrandchild.ts +42 -0
- package/src/test/Parent.ts +21 -0
- package/src/test/Testform.css +47 -0
- package/src/test/Testform.html +56 -0
- package/src/test/Testform.json +27 -0
- package/src/test/Testform.ts +159 -0
- package/src/test.ts +8 -5
- package/webpack.config.js +135 -61
|
@@ -1,256 +1,470 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Microcomponent Framework Documentation <span style="float:right; height:1em;"><img height="24px" src="./MicroComponents.svg" /></span>
|
|
2
|
+
|
|
3
|
+
This document details a lightweight JavaScript framework for creating and managing "microcomponents" (MCs) associated with DOM elements or other microcomponents. It allows you to define reusable components and attach them to build complex functionalities.
|
|
4
|
+
|
|
5
|
+
The framework exports 2 main classes:
|
|
6
|
+
|
|
7
|
+
- **MC**: Micro Component. The base component class, suitable for logic that doesn't directly interact with the DOM or for use on the server.
|
|
8
|
+
- **DC**: DOM Component. Extends `MC` and adds DOM-specific methods (like traversal). Use this for components that need to interact with the browser's DOM.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Usage Guidance](#usage-guidance)
|
|
13
|
+
- [Core Concepts](#core-concepts)
|
|
14
|
+
- [Microcomponents (MCs)](#microcomponents-mcs)
|
|
15
|
+
- [`_mc` Property](#_mc-property)
|
|
16
|
+
- [DOM Association & `target`](#dom-association--target)
|
|
17
|
+
- [Event System](#event-system)
|
|
18
|
+
- [Observables (Mention)](#observables-mention)
|
|
19
|
+
- [DOM Traversal](#dom-traversal)
|
|
20
|
+
- [Autoloading Concept](#autoloading-concept)
|
|
21
|
+
- [Important Rule](#important-rule)
|
|
22
|
+
- [Framework Classes](#framework-classes)
|
|
23
|
+
- [Not Exported: `McBase` (Superclass)](#not-exported-mcbase-superclass)
|
|
24
|
+
- [Exported: `MC` Class](#exported-mc-class)
|
|
25
|
+
- [Exported: `DC` Class](#exported-dc-class)
|
|
26
|
+
- [Examples](#examples)
|
|
27
|
+
- [Typical Workflow](#typical-workflow)
|
|
28
|
+
- [Attach Micro Components (`DC.add`)](#attach-micro-components-dcadd)
|
|
29
|
+
- [Remove Micro Components (`DC.remove`)](#remove-micro-components-dcremove)
|
|
30
|
+
- [Retrieve Micro Components](#retrieve-micro-components)
|
|
31
|
+
- [Triggering Events](#triggering-events)
|
|
32
|
+
- [Retrieving Inner Micro Components](#retrieving-inner-micro-components)
|
|
33
|
+
- [Navigating Parent/Ancestor MCs](#navigating-parentancestor-mcs)
|
|
34
|
+
- [Retrieving Child/Descendant MCs](#retrieving-childdescendant-mcs)
|
|
35
|
+
- [Auto-attaching DOM Listeners](#auto-attaching-dom-listeners)
|
|
36
|
+
- [Lifecycle Events](#lifecycle-events)
|
|
37
|
+
- [Init](#init)
|
|
38
|
+
- [Destroy (TBD)](#destroy-tbd)
|
|
39
|
+
- [Helper Functions (Internal)](#helper-functions-internal)
|
|
40
|
+
- [`isBrowser()`](#isbrowser)
|
|
41
|
+
- [`nativeEventNames`](#nativeeventnames)
|
|
42
|
+
- [`getMicroComponents(...)`](#getmicrocomponents)
|
|
43
|
+
- [`traverseNodes(...)`](#traversenodes)
|
|
44
|
+
- [`isDOM(...)`](#isdom)
|
|
45
|
+
- [`addListener(...)`](#addlistener)
|
|
46
|
+
- [`removeListener(...)`](#removelistener)
|
|
47
|
+
- [`add(...)`](#add)
|
|
48
|
+
- [`remove(...)`](#remove)
|
|
49
|
+
- [`trigger(...)`](#trigger)
|
|
50
|
+
- [`init(...)`](#init-helper)
|
|
51
|
+
- [`autoAttachListeners(...)`](#autoattachlisteners)
|
|
52
|
+
- [`bubbleEvent(...)`](#bubbleevent)
|
|
53
|
+
- [Autoloading Implementation](#autoloading-implementation)
|
|
54
|
+
- [`autoload(enable?)`](#autoload)
|
|
55
|
+
- [`loadit()`](#loadit)
|
|
56
|
+
- [Interfaces and Types](#interfaces-and-types)
|
|
57
|
+
- [`LooseObject`](#looseobject)
|
|
58
|
+
- [`McEvent`](#mcevent)
|
|
59
|
+
- [`HTMLMcElement`](#htmlmcelement)
|
|
2
60
|
|
|
3
|
-
|
|
61
|
+
## Usage Guidance
|
|
4
62
|
|
|
5
|
-
|
|
6
|
-
- **
|
|
7
|
-
|
|
63
|
+
- **If your component needs to access or manipulate the DOM** (e.g., find other components in the DOM, attach listeners directly, read element properties), **your class MUST extend `DC`**. This is client-side only.
|
|
64
|
+
- **Otherwise** (e.g., for pure logic, state management, or server-side usage), **your class should extend `MC`**.
|
|
65
|
+
|
|
66
|
+
Think **DRY** (Don't Repeat Yourself) and **SOLID** principles when designing your components.
|
|
8
67
|
|
|
9
|
-
|
|
68
|
+
## Core Concepts
|
|
10
69
|
|
|
11
|
-
|
|
12
|
-
- **Otherwise** - and always on the server - **your class extends MC**.
|
|
70
|
+
Fundamental ideas behind the framework.
|
|
13
71
|
|
|
14
|
-
|
|
72
|
+
### Microcomponents (MCs)
|
|
15
73
|
|
|
16
|
-
|
|
74
|
+
Plain JavaScript objects or class instances (extending `MC` or `DC`) that encapsulate behavior and state. They can be attached to DOM elements (via `DC`) or nested within other MCs.
|
|
17
75
|
|
|
18
|
-
|
|
19
|
-
- if your class extends **MC: "target"** will refer the **parent MC your instance resides in**.
|
|
76
|
+
### `_mc` Property
|
|
20
77
|
|
|
21
|
-
|
|
22
|
-
- **MC** encapsule functionality in a reusable way. Think DRY, and SOLID because we talk about objects.
|
|
23
|
-
- **MC** can use observables to provide data driven workflow between multiple MCs.
|
|
24
|
-
- **DC** use observables and formValues to provide 1-way and 2-way binding to the DOM.
|
|
25
|
-
- **DC** have selectors to find other DCs in the DOM.
|
|
78
|
+
A special property attached to `HTMLElement` instances (when using `DC.add`) or parent `MC`/`DC` instances. It acts as an object container (`{ key: mcInstance, ... }`) holding one or more named microcomponent instances.
|
|
26
79
|
|
|
27
|
-
|
|
80
|
+
- On HTMLElements, the presence of attached components is also marked by a `_mc` attribute for CSS selection and discovery. This attribute is added by `DC.add` and removed by `DC.remove` when the `_mc` object becomes empty.
|
|
28
81
|
|
|
29
|
-
|
|
30
|
-
- If you do it anyway, you do it on your own risk.
|
|
82
|
+
### DOM Association & `target`
|
|
31
83
|
|
|
32
|
-
|
|
84
|
+
Each microcomponent instance has a read-only `target` property providing a back-reference:
|
|
33
85
|
|
|
34
|
-
|
|
86
|
+
- If the instance extends **`DC`** and was added via `DC.add`, `target` refers to the **DOM HTMLElement** it's attached to.
|
|
87
|
+
- If the instance extends **`MC`** (or `DC`) and is nested within another component's `_mc` property, `target` refers to the **parent MC/DC instance**.
|
|
35
88
|
|
|
36
|
-
|
|
37
|
-
- `.target`: readonly, a getter returning the DOM element or parent MC instance your instance resides in
|
|
89
|
+
This reference is managed using `WeakRef` internally by `McBase` to prevent circular references and potential memory leaks.
|
|
38
90
|
|
|
39
|
-
|
|
40
|
-
- calls `init()`: triggers the 'init' lifecycle event, also recursively into the inner '._mc' structure.
|
|
41
|
-
- calls `autoAttachListeners()`: methods in your class code that start with "on[A-Z]" or "one[A-Z]" and describe native DOM events (e.g. "onClick") will be added to the DOM Element as listeners.
|
|
91
|
+
### Event System
|
|
42
92
|
|
|
43
|
-
|
|
44
|
-
- `.trigger( eventName, data )`: runs callback methods.
|
|
93
|
+
A custom event system using the `McEvent` class allows components to communicate.
|
|
45
94
|
|
|
46
|
-
|
|
95
|
+
- **Triggering:** Events are dispatched using the `trigger` method:
|
|
96
|
+
- `DC.trigger(targetElement, ...)`: Dispatches to all MCs on a specific DOM element. Handles bubbling (`u`/`d`).
|
|
97
|
+
- `this.trigger(...)`: Dispatches within the current MC instance and its potential nested MCs. Can also initiate bubbling if the instance is a `DC`.
|
|
98
|
+
- **Handling:**
|
|
99
|
+
- Components listen for events by defining methods named `onEventName` or `oneEventName` (for once-off handling).
|
|
100
|
+
- These are automatically detected by `autoAttachListeners`.
|
|
101
|
+
- Native DOM events matching this pattern on `DC` instances are also automatically bound to the target element.
|
|
102
|
+
- **Bubbling:** Events triggered via `DC.trigger` or `dcInstance.trigger` can bubble:
|
|
103
|
+
- `'l'`: Local only (default). Handlers on the target element's/instance's MCs are executed.
|
|
104
|
+
- `'u'`: Upwards. Event propagates to MCs on parent elements (DOM tree).
|
|
105
|
+
- `'d'`: Downwards. Event propagates to MCs on descendant elements (DOM tree).
|
|
106
|
+
- Combinations are possible (e.g., `'lu'`, `'ldu'`). Bubbling (`u`/`d`) occurs asynchronously via `setTimeout`.
|
|
47
107
|
|
|
48
|
-
|
|
108
|
+
### Observables (Mention)
|
|
49
109
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
110
|
+
- MCs can utilize observables (implementation not detailed here) for data-driven workflows.
|
|
111
|
+
- `DC` components can leverage observables and potentially form values for 1-way or 2-way data binding with the DOM.
|
|
112
|
+
|
|
113
|
+
### DOM Traversal
|
|
53
114
|
|
|
54
|
-
|
|
55
|
-
- `.trigger( eventName, data )`: (inherited from McBase)
|
|
115
|
+
The `DC` class provides methods (`parent`, `ancestors`, `children`, `descendants`) to find related `DC` instances attached to elements elsewhere in the DOM hierarchy, skipping over elements without attached microcomponents.
|
|
56
116
|
|
|
57
|
-
|
|
117
|
+
### Autoloading Concept
|
|
58
118
|
|
|
59
|
-
-
|
|
60
|
-
- `DC.add( DomElement, key, mc)`: Add a DC to an HTMLElement.
|
|
61
|
-
- `DC.remove( DomElement, key )`: Remove a DC from an HTMLElement.
|
|
62
|
-
- `DC.trigger( eventName, DomElement, data, bubble )`: trigger an event, handles directional traversal in the DOM.
|
|
119
|
+
An optional feature (`autoload()`) that automatically detects specific HTML tags (e.g., `<my-component>`) or elements with an `_mc="MyComponent"` attribute and attempts to dynamically load the corresponding JavaScript module (e.g., `/my/Component.js`).
|
|
63
120
|
|
|
64
|
-
|
|
65
|
-
- `.target`: (inherited from McBase)
|
|
66
|
-
- `._mc`: a hash object that contains inner micro components
|
|
121
|
+
### Important Rule
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
- `.parent(search?)`: Get parent DCs.
|
|
70
|
-
- `.ancestors(search?)`: Get ancestor DCs.
|
|
71
|
-
- `.children(search?)`: Get child DCs.
|
|
72
|
-
- `.descendants(search?)`: Get descendant DCs.
|
|
73
|
-
- `.trigger( eventName, data, bubble )`: trigger an event on "this", handles directional bubbling in the DOM.
|
|
123
|
+
**Your own application code MUST NOT overwrite the core properties and methods provided by the `McBase`, `MC`, and `DC` classes (like `_mc`, `target`, `trigger`, `parent`, etc.). Doing so may break framework functionality.**
|
|
74
124
|
|
|
75
|
-
|
|
125
|
+
## Framework Classes
|
|
76
126
|
|
|
77
|
-
|
|
127
|
+
### Not Exported: `McBase` (Superclass)
|
|
78
128
|
|
|
79
|
-
|
|
80
|
-
2. **Access** other DCs by their property key or navigating through DOM (e.g., `ancestors()`, `children()`, etc.) **and use their inner functionality**.
|
|
129
|
+
The internal base class for `MC` and `DC`. You don't extend this directly.
|
|
81
130
|
|
|
82
|
-
|
|
131
|
+
- **Instance Properties**:
|
|
132
|
+
- `.target`: Read-only getter returning the containing DOM element (for DCs added via `DC.add`) or parent MC/DC instance (for nested MCs). Uses `WeakRef`.
|
|
133
|
+
- **Constructor Behavior**:
|
|
134
|
+
- Initializes the `.target` reference.
|
|
135
|
+
- Calls `init(this)`: Triggers the 'Init' lifecycle event asynchronously.
|
|
136
|
+
- Calls `autoAttachListeners(this)`: Sets up automatic event listeners based on method names (`onEventName`, `oneEventName`).
|
|
137
|
+
- **Instance Methods**:
|
|
138
|
+
- `.trigger(eventName, data)`: Base trigger logic used by `MC` and `DC`.
|
|
83
139
|
|
|
84
|
-
|
|
140
|
+
### Exported: `MC` Class
|
|
141
|
+
|
|
142
|
+
Base class for non-DOM or server-side components. Extends `McBase`.
|
|
143
|
+
|
|
144
|
+
- **Instance Properties**:
|
|
145
|
+
- `.target`: (Inherited from `McBase`) Refers to the parent MC/DC instance it's nested within.
|
|
146
|
+
- `._mc`: An object `{}` to hold nested microcomponent instances.
|
|
147
|
+
- **Instance Methods**:
|
|
148
|
+
- `.trigger(eventName, data)`: (Inherited) Triggers events locally within the instance and its nested `_mc` structure. Does not handle DOM bubbling.
|
|
149
|
+
|
|
150
|
+
### Exported: `DC` Class
|
|
151
|
+
|
|
152
|
+
Class for DOM-aware components. Extends `McBase`. **Client-side only.**
|
|
153
|
+
|
|
154
|
+
- **Static Methods**:
|
|
155
|
+
- `DC.add(domElement, key, mcInstance)`: Attaches an `mcInstance` (should be a `DC` or `MC`) to a `domElement` under the specified `key`. Creates `domElement._mc` if needed and sets the `_mc` attribute.
|
|
156
|
+
- `DC.remove(domElement, key)`: Removes the MC instance associated with `key` from `domElement._mc`. Removes the `_mc` attribute if the collection becomes empty.
|
|
157
|
+
- `DC.trigger(domElement, eventName, data, bubble)`: Triggers an event on all MCs attached to `domElement`. Handles DOM bubbling (`'l'`, `'u'`, `'d'`).
|
|
158
|
+
- **Instance Properties**:
|
|
159
|
+
- `.target`: (Inherited from `McBase`) Refers to the DOM HTMLElement this `DC` instance is attached to (via `DC.add`).
|
|
160
|
+
- `._mc`: An object `{}` to hold nested microcomponent instances.
|
|
161
|
+
- **Instance Methods**:
|
|
162
|
+
- `.parent(search?)`: Gets MC instances from the closest parent element that has attached MCs. Optionally filters by `search` key.
|
|
163
|
+
- `.ancestors(search?)`: Gets MC instances from all ancestor elements with attached MCs. Optionally filters by `search` key.
|
|
164
|
+
- `.children(search?)`: Gets MC instances from direct child elements with attached MCs. Optionally filters by `search` key.
|
|
165
|
+
- `.descendants(search?)`: Gets MC instances from all descendant elements with attached MCs. Optionally filters by `search` key.
|
|
166
|
+
- `.trigger(eventName, data, bubble)`: Triggers an event on this `DC` instance and its nested `_mc` structure. Can initiate DOM bubbling (`'l'`, `'u'`, `'d'`).
|
|
167
|
+
|
|
168
|
+
## Examples
|
|
169
|
+
|
|
170
|
+
### Typical Workflow
|
|
171
|
+
|
|
172
|
+
1. Define your component classes extending `MC` or `DC`.
|
|
173
|
+
2. Attach top-level `DC` instances to HTMLElements using `DC.add()`.
|
|
174
|
+
3. Nest `MC` or `DC` instances within others using the `._mc` property if needed.
|
|
175
|
+
4. Access other components via the `_mc` property, DOM traversal methods (`ancestors()`, `children()`, etc.), or event communication (`trigger`).
|
|
176
|
+
|
|
177
|
+
### Attach Micro Components (`DC.add`)
|
|
178
|
+
|
|
179
|
+
Use the static `DC.add()` method to attach a component (usually a `DC` instance) to an HTMLElement.
|
|
85
180
|
|
|
86
181
|
```javascript
|
|
87
182
|
const myElement = document.getElementById('myDiv');
|
|
88
183
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
184
|
+
// Define an inner MC (doesn't need DOM access itself)
|
|
185
|
+
class MyInnerClass extends MC {
|
|
186
|
+
constructor(target) {
|
|
187
|
+
// target will be the parent MyPublicClass instance
|
|
188
|
+
super(target);
|
|
189
|
+
console.log('Inner MC target:', this.target);
|
|
190
|
+
}
|
|
191
|
+
doSomethingInner() {
|
|
192
|
+
console.log('Inner action!');
|
|
193
|
+
}
|
|
97
194
|
}
|
|
98
195
|
|
|
99
|
-
//
|
|
100
|
-
MyPublicClass
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
196
|
+
// Define an outer DC (needs DOM access or is top-level)
|
|
197
|
+
class MyPublicClass extends DC {
|
|
198
|
+
constructor(target) {
|
|
199
|
+
// target will be myElement
|
|
200
|
+
super(target);
|
|
201
|
+
console.log('Outer DC target:', this.target);
|
|
202
|
+
// Add an inner MC instance, nested within this DC instance
|
|
203
|
+
this._mc.myInner = new MyInnerClass(this); // 'this' becomes the target for MyInnerClass
|
|
204
|
+
}
|
|
205
|
+
doSomethingOuter() {
|
|
206
|
+
console.log('Outer action!');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Example DOM event handler
|
|
210
|
+
onClick(event) {
|
|
211
|
+
console.log('Div clicked!', event);
|
|
212
|
+
// Access nested MC
|
|
213
|
+
this._mc.myInner?.doSomethingInner();
|
|
214
|
+
}
|
|
105
215
|
}
|
|
106
216
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
217
|
+
// Attach the outer DC instance to the DOM element
|
|
218
|
+
// The key 'myComponent' is used to access it later via myElement._mc.myComponent
|
|
219
|
+
DC.add(myElement, 'myComponent', new MyPublicClass(myElement));
|
|
110
220
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
221
|
+
// Hint: After adding, myElement now has:
|
|
222
|
+
// 1. A property: myElement._mc = { myComponent: instanceOfMyPublicClass }
|
|
223
|
+
// 2. An attribute: <div id="myDiv" _mc>...</div>
|
|
224
|
+
```
|
|
114
225
|
|
|
115
|
-
### Remove
|
|
226
|
+
### Remove Micro Components (DC.remove)
|
|
116
227
|
|
|
117
|
-
|
|
228
|
+
Use the static DC.remove() method to detach a top-level component.
|
|
118
229
|
|
|
119
230
|
```javascript
|
|
120
|
-
|
|
231
|
+
const myElement = document.getElementById('myDiv');
|
|
232
|
+
|
|
233
|
+
DC.remove(myElement, 'myComponent');
|
|
234
|
+
|
|
235
|
+
// If myElement._mc is now empty, the '_mc' attribute is also removed.
|
|
121
236
|
```
|
|
122
237
|
|
|
123
|
-
|
|
238
|
+
### Retrieve Micro Components
|
|
124
239
|
|
|
125
|
-
|
|
240
|
+
Access attached components via the \_mc property of the target element or parent component.
|
|
126
241
|
|
|
127
242
|
```javascript
|
|
128
|
-
|
|
129
|
-
|
|
243
|
+
// Get the container object for all MCs on an element
|
|
244
|
+
const myElement = document.getElementById('myDiv');
|
|
245
|
+
const mcContainer = myElement._mc;
|
|
246
|
+
console.log(mcContainer); // { myComponent: instanceOfMyPublicClass, ... }
|
|
247
|
+
|
|
248
|
+
// Get a specific instance by its key
|
|
249
|
+
const specificInstance = myElement._mc?.myComponent;
|
|
250
|
+
if (specificInstance) {
|
|
251
|
+
specificInstance.doSomethingOuter();
|
|
252
|
+
}
|
|
130
253
|
```
|
|
131
254
|
|
|
132
|
-
|
|
255
|
+
### Triggering Events
|
|
256
|
+
|
|
257
|
+
1. Triggering from outside onto components on an element:
|
|
258
|
+
|
|
133
259
|
```javascript
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
|
|
260
|
+
const targetElement = document.getElementById('myDiv');
|
|
261
|
+
const eventData = { message: 'Hello from outside!' };
|
|
262
|
+
|
|
263
|
+
// Trigger 'customEvent' locally on MCs attached to targetElement
|
|
264
|
+
DC.trigger(targetElement, 'customEvent', eventData, 'l');
|
|
265
|
+
|
|
266
|
+
// Trigger 'customEvent' and bubble up the DOM tree
|
|
267
|
+
DC.trigger(targetElement, 'customEvent', eventData, 'u');
|
|
268
|
+
|
|
269
|
+
// Trigger 'customEvent' locally, bubble up, and bubble down
|
|
270
|
+
DC.trigger(targetElement, 'customEvent', eventData, 'lud');
|
|
137
271
|
```
|
|
138
272
|
|
|
139
|
-
|
|
273
|
+
2. Triggering from inside a component instance:
|
|
140
274
|
|
|
141
275
|
```javascript
|
|
142
|
-
|
|
143
|
-
|
|
276
|
+
class MyTriggeringComponent extends DC {
|
|
277
|
+
// ... constructor ...
|
|
144
278
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
```
|
|
279
|
+
someMethod() {
|
|
280
|
+
const eventData = { source: 'MyTriggeringComponent' };
|
|
148
281
|
|
|
149
|
-
|
|
282
|
+
// Trigger 'internalEvent' only on this instance and its nested _mc components
|
|
283
|
+
this.trigger('internalEvent', eventData); // Default bubble 'l'
|
|
150
284
|
|
|
151
|
-
|
|
285
|
+
// Trigger 'externalEvent' on sibling components attached to the same target element
|
|
286
|
+
// (and potentially bubble up/down based on the 'bubble' parameter)
|
|
287
|
+
DC.trigger(this.target, 'externalEvent', eventData, 'l'); // Trigger locally on siblings
|
|
152
288
|
|
|
153
|
-
|
|
289
|
+
// Trigger 'downwardEvent' on components attached to descendant elements
|
|
290
|
+
this.trigger('downwardEvent', eventData, 'd'); // Bubbles down from this component's target
|
|
291
|
+
}
|
|
154
292
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
console.log(
|
|
158
|
-
|
|
293
|
+
// Event handler methods
|
|
294
|
+
onCustomEvent(event) {
|
|
295
|
+
console.log(`[${this.constructor.name}] received customEvent:`, event.data);
|
|
296
|
+
}
|
|
159
297
|
|
|
160
|
-
|
|
298
|
+
onInternalEvent(event) {
|
|
299
|
+
console.log(
|
|
300
|
+
`[${this.constructor.name}] received internalEvent:`,
|
|
301
|
+
event.data
|
|
302
|
+
);
|
|
303
|
+
}
|
|
161
304
|
|
|
305
|
+
onExternalEvent(event) {
|
|
306
|
+
console.log(
|
|
307
|
+
`[${this.constructor.name}] received externalEvent:`,
|
|
308
|
+
event.data
|
|
309
|
+
);
|
|
310
|
+
}
|
|
162
311
|
|
|
163
|
-
|
|
312
|
+
onDownwardEvent(event) {
|
|
313
|
+
console.log(
|
|
314
|
+
`[${this.constructor.name}] received downwardEvent:`,
|
|
315
|
+
event.data
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
164
320
|
|
|
165
|
-
|
|
321
|
+
### Retrieving Inner Micro Components
|
|
322
|
+
|
|
323
|
+
Access nested components directly via the parent's `_mc` property.
|
|
166
324
|
|
|
167
325
|
```javascript
|
|
168
|
-
|
|
169
|
-
|
|
326
|
+
class Inner extends MC {
|
|
327
|
+
constructor(target) {
|
|
328
|
+
super(target);
|
|
329
|
+
}
|
|
330
|
+
someInnerMethod() {
|
|
331
|
+
console.log('Inner method called!');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
class Outer extends DC {
|
|
336
|
+
constructor(target) {
|
|
337
|
+
super(target);
|
|
338
|
+
this._mc.inner = new Inner(this);
|
|
339
|
+
}
|
|
170
340
|
|
|
171
|
-
|
|
172
|
-
|
|
341
|
+
accessInner() {
|
|
342
|
+
this._mc?.inner.someInnerMethod();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
173
345
|
```
|
|
174
346
|
|
|
175
|
-
|
|
347
|
+
### Navigating Parent/Ancestor MCs
|
|
348
|
+
|
|
349
|
+
Use .parent() and .ancestors() (available on DC instances) to find components attached to elements higher up the DOM tree.
|
|
350
|
+
|
|
351
|
+
These methods skip elements that don't have any MCs attached.
|
|
352
|
+
|
|
176
353
|
```javascript
|
|
177
|
-
|
|
354
|
+
// Inside a method of a DC instance:
|
|
355
|
+
const parentMcs = this.parent(); // Array of MC instances on the first parent element with MCs
|
|
356
|
+
console.log(parentMcs);
|
|
357
|
+
|
|
358
|
+
const allAncestorMcs = this.ancestors(); // Array of all MC instances on all ancestor elements with MCs
|
|
359
|
+
console.log(allAncestorMcs);
|
|
360
|
+
|
|
361
|
+
// Find a specific component type/key among ancestors
|
|
362
|
+
const specificAncestor = this.ancestors('someSpecificKey')?.[0];
|
|
363
|
+
|
|
364
|
+
if (specificAncestor) {
|
|
365
|
+
console.log('Found specific ancestor:', specificAncestor);
|
|
366
|
+
}
|
|
178
367
|
```
|
|
179
368
|
|
|
180
|
-
|
|
369
|
+
### Retrieving Child/Descendant MCs
|
|
370
|
+
|
|
371
|
+
Use .children() and .descendants() (available on DC instances) to find components attached to elements lower down the DOM tree.
|
|
181
372
|
|
|
182
|
-
The `.children()` and `.descendants()` methods retrieve micro components attached to child elements or any descendants.
|
|
183
373
|
```javascript
|
|
184
|
-
|
|
185
|
-
|
|
374
|
+
// Inside a method of a DC instance:
|
|
375
|
+
const childMcs = this.children(); // Array of MCs on direct child elements with MCs
|
|
376
|
+
console.log(childMcs);
|
|
186
377
|
|
|
187
|
-
const
|
|
188
|
-
console.log(
|
|
378
|
+
const descendantMcs = this.descendants(); // Array of all MCs on all descendant elements with MCs
|
|
379
|
+
console.log(descendantMcs);
|
|
189
380
|
|
|
190
|
-
//
|
|
191
|
-
const
|
|
381
|
+
// Find specific components among descendants
|
|
382
|
+
const specificDescendants = this.descendants('someSpecificKey');
|
|
383
|
+
console.log(specificDescendants); // Array of matching descendant MCs
|
|
192
384
|
```
|
|
193
385
|
|
|
194
|
-
|
|
386
|
+
### Auto-attaching DOM Listeners
|
|
387
|
+
|
|
388
|
+
Methods defined in your DC class starting with `on` or `one` followed by a capital letter, which also match native DOM event names (case-insensitive check), will automatically have listeners attached to the target DOM element:
|
|
389
|
+
|
|
195
390
|
```javascript
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
391
|
+
class McWithHandlers extends DC {
|
|
392
|
+
constructor(target) {
|
|
393
|
+
super(target);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// This method name matches the native 'click' event.
|
|
397
|
+
// A listener will be automatically added to this.target.
|
|
398
|
+
onClick(domEvent) {
|
|
399
|
+
console.log('Target element clicked!', domEvent);
|
|
400
|
+
// 'this' refers to the MyClickHandler instance
|
|
401
|
+
this.target.style.backgroundColor = 'lightblue';
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// This method name matches the native 'mouseover' event.
|
|
405
|
+
// 'one' means the listener will be removed after the first trigger.
|
|
406
|
+
oneMouseover(domEvent) {
|
|
407
|
+
console.log('Mouseover detected once!', domEvent);
|
|
408
|
+
this.target.style.border = '2px solid red';
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// This is a custom event handler, not a native DOM event.
|
|
412
|
+
// It will be triggered by this.trigger('CustomAction') or DC.trigger(this.target, 'CustomAction')
|
|
413
|
+
onCustomAction(mcEvent) {
|
|
414
|
+
console.log('Custom action triggered!', mcEvent.data);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const myDiv = document.getElementById('clickableDiv');
|
|
419
|
+
DC.add(myDiv, 'clickHandler', new McWithHandlers(myDiv));
|
|
420
|
+
// Now clicking or mousing over 'clickableDiv' will trigger the methods.
|
|
221
421
|
```
|
|
222
422
|
|
|
223
|
-
|
|
423
|
+
### Lifecycle Events
|
|
424
|
+
|
|
425
|
+
The framework defines specific methods that are called at certain points in a component's life.
|
|
426
|
+
|
|
427
|
+
#### Init
|
|
428
|
+
|
|
429
|
+
Method Name: oneInit(event)
|
|
224
430
|
|
|
225
|
-
|
|
431
|
+
Triggered: Asynchronously (setTimeout(0)) after the component instance is created (called from McBase constructor via the init helper).
|
|
226
432
|
|
|
227
|
-
|
|
433
|
+
Execution Order:
|
|
434
|
+
|
|
435
|
+
The component's oneInit is called first, then it recursively calls oneInit on any components nested within its `_mc` property.
|
|
436
|
+
|
|
437
|
+
Requirement:
|
|
438
|
+
|
|
439
|
+
- You must define a method named `oneInit` in your class for it to be called.
|
|
440
|
+
- The `one` prefix implies it's intended to run once during initialization.
|
|
228
441
|
|
|
229
442
|
```javascript
|
|
230
|
-
class
|
|
443
|
+
class MyLifecycleComponent extends DC {
|
|
231
444
|
constructor(target) {
|
|
232
445
|
super(target);
|
|
446
|
+
console.log('Constructor finished');
|
|
447
|
+
this._mc.nested = new NestedComponent(this);
|
|
233
448
|
}
|
|
234
449
|
|
|
235
|
-
|
|
236
|
-
|
|
450
|
+
oneInit(event) {
|
|
451
|
+
// This code runs shortly after the constructor finishes.
|
|
452
|
+
console.log('MyLifecycleComponent oneInit called!', event);
|
|
453
|
+
// Safe to access this.target or setup things that depend on the instance being fully constructed.
|
|
237
454
|
}
|
|
238
455
|
}
|
|
239
|
-
|
|
240
|
-
let myFirstDiv = document.querySelector('div');
|
|
241
|
-
DC.add( myFirstDiv, 'myEventTarget', new MyEventTarget( myFirstDiv ) );
|
|
242
|
-
// now wait for somebody to click on that <div>
|
|
243
456
|
```
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
457
|
+
|
|
458
|
+
#### Destroy (TBD)
|
|
459
|
+
|
|
460
|
+
Method Name: oneDestroy(event) (Proposed)
|
|
461
|
+
|
|
462
|
+
Triggered: When a component is removed (e.g., via DC.remove or potentially parent removal).
|
|
463
|
+
|
|
464
|
+
Execution Order:
|
|
465
|
+
|
|
466
|
+
Expected to run synchronously, starting from the deepest nested components upwards, finally calling oneDestroy on the component being removed itself.
|
|
467
|
+
|
|
468
|
+
Requirement:
|
|
469
|
+
|
|
470
|
+
- Would require defining a method named `oneDestroy` in your class.
|