@twobirds/microcomponents 0.0.16 → 0.0.18
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/README.md +5 -15
- package/assets/documentation/tB_react.md +14 -11
- package/package.json +1 -1
- package/public/documentation/tB_react.md +21 -47
- package/public/test.js +1 -1
- package/src/test.js +1 -1
package/README.md
CHANGED
|
@@ -4,23 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
**This code aims at improving Javascript modularity and encapsulation**.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
```javascript
|
|
9
|
-
import MyButton from '@mySampleLib/Button';
|
|
10
|
-
```
|
|
11
|
-
... is equivalent to:
|
|
12
|
-
```shell
|
|
13
|
-
npm i @mySampleLib/Button
|
|
14
|
-
```
|
|
15
|
-
... on the server side.
|
|
16
|
-
|
|
17
|
-
Imagine your micro components to be organized like a "node_modules" directory that is attached to a DOM node.
|
|
7
|
+
Imagine your own micro components to be organized like a "node_modules" collection that is attached to a DOM node.
|
|
18
8
|
|
|
19
9
|
The MC() class acts as a **Javascript repository on a DOM node** and as a **selector and communication tool across the DOM**.
|
|
20
10
|
|
|
21
|
-
**On the client
|
|
11
|
+
**On the client** MCs reside inside DOM nodes in a "_mc" property, or inside each other recursively. Usually they provide a direct interface to their inner code.
|
|
22
12
|
|
|
23
|
-
**On the server
|
|
13
|
+
**On the server** MCs can be used to organize your code, too.
|
|
24
14
|
|
|
25
15
|
## Status
|
|
26
16
|
WIP. Should be done soon. In [manual testing](http://twobirds.gitlab.io/microcomponents/test.html), also working a lot on the documentation.
|
|
@@ -30,11 +20,11 @@ I decided to extract this functionality from the [twoBirds framework](https://ww
|
|
|
30
20
|
|
|
31
21
|
Read the [history](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/history.md) to see how it all started in 2004. It contains some fun stuff.
|
|
32
22
|
|
|
33
|
-
This is a massive undertaking. MCs are just the foundation of what I do. **I am about to dump** [20+ years of javascript programming](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/magic.md?ref_type=heads#things-i-already-did-with-this-in-my-own-framework-twobirds-or-in-apps-that-i-developed-with-it) **into open source libraries**, so feel free to [fund this](https://gofund.me/076c614c). The better this is funded, the faster it will be done. Given enough resources, I will start a crowdfunded company that will develop a new ecosystem for javascript/typescript programming.
|
|
23
|
+
This is a massive undertaking. MCs are just the foundation of what I do. **I am about to dump** [20+ years of javascript programming](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/magic.md?ref_type=heads#things-i-already-did-with-this-in-my-own-framework-twobirds-or-in-apps-that-i-developed-with-it) **into open source libraries**, so feel free to [fund this](https://gofund.me/076c614c). The better this is funded, the faster it will be done. Given enough resources, I will start a crowdfunded company that will develop a new open source ecosystem for javascript/typescript programming.
|
|
34
24
|
|
|
35
25
|
By **"Open Source"** I mean **really free and open**, as **you get all my inner source code with it**. Once you understand the Micro Component principle, you are back in command of your software, no matter what MC functionality you import in your system. Since **Micro Components** are encapsuled, off-shoring and near-shoring is no problem, and reusability is guaranteed. Your external coders do not need to access your code repository or your toolchain. They only need to understand MCs.
|
|
36
26
|
|
|
37
|
-
**Established frameworks**, as opposed to MCs, **provide a documented interface to a hidden layer of closed source inner functionality**. MCs can be used to **add an interface to components you developed using other frameworks**. So you can still use your existing code, and MCs in it. But you be tempted to migrate it ASAP, since MCs work with any FW.
|
|
27
|
+
**Established frameworks**, as opposed to MCs, **provide a documented interface to a hidden layer of closed source inner functionality**. MCs can be used to **add an interface to components you developed using other frameworks**. So you can still use your existing code, and MCs in it. But you may be tempted to migrate it ASAP, since MCs work with any FW.
|
|
38
28
|
|
|
39
29
|
## General
|
|
40
30
|
|
|
@@ -97,6 +97,7 @@ Parent Micro Component
|
|
|
97
97
|
This component will receive a target DOM node and set a value that propagates down to its descendants:
|
|
98
98
|
|
|
99
99
|
```javascript
|
|
100
|
+
import { MC } from '@twobirds/microcomponents';
|
|
100
101
|
|
|
101
102
|
// Parent Micro Component
|
|
102
103
|
class ParentMC extends MC {
|
|
@@ -116,6 +117,7 @@ Child Micro Component
|
|
|
116
117
|
This component has a data setter that updates the internal React state in each child:
|
|
117
118
|
|
|
118
119
|
```javascript
|
|
120
|
+
import { MC } from '@twobirds/microcomponents';
|
|
119
121
|
|
|
120
122
|
// Child Micro Component
|
|
121
123
|
class ChildMC extends MC {
|
|
@@ -140,16 +142,16 @@ The parent component attaches an instance of ParentMC to the DOM node and sets i
|
|
|
140
142
|
```javascript
|
|
141
143
|
|
|
142
144
|
import React, { useState, useRef, useEffect } from 'react';
|
|
143
|
-
import { MC } from '@
|
|
145
|
+
import { MC } from '@twobirds/microcomponents';
|
|
146
|
+
import { ParentMC } from '@myCompany/ParentMC';
|
|
144
147
|
|
|
145
148
|
const ParentComponent = () => {
|
|
146
149
|
const [inputValue, setInputValue] = useState("");
|
|
147
150
|
const parentRef = useRef(null);
|
|
151
|
+
const parentMC = new ParentMC( parentRef );
|
|
152
|
+
const sender = MC.add(parentRef.current, 'parentMC', parentMC);
|
|
148
153
|
|
|
149
154
|
useEffect(() => {
|
|
150
|
-
const parentMC = new ParentMC(parentRef.current); // Pass the DOM node to ParentMC
|
|
151
|
-
MC.add(parentRef.current, 'parentMC', parentMC);
|
|
152
|
-
|
|
153
155
|
// Update value in ParentMC whenever inputValue changes
|
|
154
156
|
parentMC.value = inputValue;
|
|
155
157
|
}, [inputValue]);
|
|
@@ -159,7 +161,7 @@ const ParentComponent = () => {
|
|
|
159
161
|
<input
|
|
160
162
|
type="text"
|
|
161
163
|
value={inputValue}
|
|
162
|
-
onChange={(e) => setInputValue(e.target.value)}
|
|
164
|
+
onChange={(e) => setInputValue( e.target.value )}
|
|
163
165
|
placeholder="Type to send data to children"
|
|
164
166
|
/>
|
|
165
167
|
<ChildComponent />
|
|
@@ -173,20 +175,21 @@ Child Component
|
|
|
173
175
|
The child component attaches an instance of ChildMC, which updates its state whenever data is set.
|
|
174
176
|
|
|
175
177
|
```javascript
|
|
178
|
+
import React, { useState, useRef } from 'react';
|
|
179
|
+
import { MC } from '@twobirds/microcomponents';
|
|
180
|
+
import { ChildMC } from '@myCompany/ChildMC';
|
|
181
|
+
|
|
176
182
|
|
|
177
183
|
const ChildComponent = () => {
|
|
178
184
|
const [childData, setChildData] = useState("");
|
|
179
185
|
const childRef = useRef(null);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const childMC = new ChildMC(childRef.current, setChildData); // Pass DOM node and state setter to ChildMC
|
|
183
|
-
MC.add(childRef.current, 'targetMC', childMC);
|
|
184
|
-
}, []);
|
|
186
|
+
const childMC = new ChildMC( childRef, setChildData );
|
|
187
|
+
const receiver = MC.add(childRef.current, 'childMC', childMC);
|
|
185
188
|
|
|
186
189
|
return (
|
|
187
190
|
<div ref={childRef}>
|
|
188
191
|
<h3>Received Data:</h3>
|
|
189
|
-
<p>
|
|
192
|
+
<p>childData</p>
|
|
190
193
|
</div>
|
|
191
194
|
);
|
|
192
195
|
};
|
package/package.json
CHANGED
|
@@ -8,32 +8,6 @@ Please mind I have a trained session with a backlog. So you wont get the same an
|
|
|
8
8
|
|
|
9
9
|
***( Cut outs and comments are in parentheses...)***
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
## Disclaimer:
|
|
13
|
-
|
|
14
|
-
The answers partly reflect on the twoBirds framework instead of Micro Components. twoBirds converts all props into convenience observables automatically, which MCs don't do.
|
|
15
|
-
|
|
16
|
-
The code ChatGPT generated first isn't quite right therefore. Also since I am not a react specialist I cannot guarantee for that part. In general, this is close enough though.
|
|
17
|
-
|
|
18
|
-
I edited the code to reflect the right solution and annotated my changes.
|
|
19
|
-
|
|
20
|
-
I put that into the first answer and asked ChatGPT again.
|
|
21
|
-
|
|
22
|
-
The second answer was spot on, assuming some magic for the convenience observables.
|
|
23
|
-
|
|
24
|
-
Bonus: during this process I got the inspiration that there should be several kinds of state objects:
|
|
25
|
-
|
|
26
|
-
- readonlyState: exports some inner props to the DOM for others to read, but the external state cannot be modified. Not observable.
|
|
27
|
-
- observableState: observable readonlyState. You can attach callbacks that fire on changes.
|
|
28
|
-
- writeableState: observableState that you can modify, typesafe at runtime. Inner methods will do further work probably.
|
|
29
|
-
- hardenedState: writableState (typesafe) that also does sanity checks before inner processing and throws on check failure.
|
|
30
|
-
|
|
31
|
-
This will be a complete public state model in the DOM.
|
|
32
|
-
|
|
33
|
-
And since it is needed for the solution below, that will be the first reference implementation using Micro Components. I hope the React world will be happy.
|
|
34
|
-
|
|
35
|
-
Working with AI can be wonderful...
|
|
36
|
-
|
|
37
11
|
## Start Session
|
|
38
12
|
|
|
39
13
|
Me:
|
|
@@ -64,13 +38,13 @@ React uses Context and hooks (like useState and useEffect) to manage data flow a
|
|
|
64
38
|
Your approach leans on manual wiring for connecting data across microcomponents, avoiding the abstraction of hooks and allowing direct, observable-driven updates. This can make the flow of data more transparent and easier to trace in complex applications, whereas hooks can sometimes add complexity or obscurity when trying to understand data dependencies.
|
|
65
39
|
|
|
66
40
|
### Component Reusability and Scaling:
|
|
67
|
-
Both React and
|
|
41
|
+
Both React and Micro Components support component-based architecture.
|
|
68
42
|
|
|
69
|
-
However,
|
|
43
|
+
However, Micro Components allows multiple microcomponents on a single DOM element, and each microcomponent is responsible for specific tasks, making scaling in large applications more modular and straightforward. React encourages separation at the component level, whereas Micro Components does so at the microcomponent level, with direct chaining possible between components.
|
|
70
44
|
|
|
71
45
|
(...)
|
|
72
46
|
|
|
73
|
-
Each of these aspects underlines
|
|
47
|
+
Each of these aspects underlines Micro Components’ focus on minimalism, modularity, and developer control. These are different from React's abstraction and tooling-heavy approach, making your framework potentially more transparent and lightweight for specific use cases.
|
|
74
48
|
|
|
75
49
|
Would you like to dive into any of these differences in more detail?
|
|
76
50
|
|
|
@@ -91,23 +65,20 @@ React requires passing data through each level of components in the tree via pro
|
|
|
91
65
|
|
|
92
66
|
(...)
|
|
93
67
|
|
|
94
|
-
In contrast, your
|
|
68
|
+
In contrast, your Micro Components microcomponents have an alternative approach that makes it easier to pass properties throughout the DOM tree:
|
|
95
69
|
|
|
96
70
|
### Direct Microcomponent Selectors:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
### Observables for State Propagation:
|
|
100
|
-
Since twoBirds uses observables, properties from a root component can be shared across components by observing changes directly. When the observable changes, all relevant components are notified and updated automatically. This is a natural data propagation method that doesn’t require explicit context or external state management.
|
|
71
|
+
Micro Components includes selector methods (like .parents() and .descendants()) that allow components to access any microcomponent within the tree without explicit data passing. This capability enables deeply nested components to retrieve properties from higher-level components directly, bypassing the need to route data through intermediary components.
|
|
101
72
|
|
|
102
|
-
|
|
73
|
+
(...)
|
|
103
74
|
|
|
104
75
|
### Manual Wiring for Control:
|
|
105
76
|
|
|
106
|
-
**Because
|
|
77
|
+
**Because Micro Components rely on manual wiring, you can set up specific connections between components as needed.** This gives you fine-grained control over where and how data flows through the app without involving a top-level state or intermediary components, making it more scalable for larger apps without the need for a Context API or state library.
|
|
107
78
|
|
|
108
79
|
(...)
|
|
109
80
|
|
|
110
|
-
This structure offers a highly flexible, context-free solution for deep property sharing, making it an efficient alternative to prop drilling or global state libraries in many scenarios. Would you like more details on how
|
|
81
|
+
This structure offers a highly flexible, context-free solution for deep property sharing, making it an efficient alternative to prop drilling or global state libraries in many scenarios. Would you like more details on how Micro Components selectors work with observables to achieve this?
|
|
111
82
|
|
|
112
83
|
|
|
113
84
|
## Generate Code
|
|
@@ -126,6 +97,7 @@ Parent Micro Component
|
|
|
126
97
|
This component will receive a target DOM node and set a value that propagates down to its descendants:
|
|
127
98
|
|
|
128
99
|
```javascript
|
|
100
|
+
import { MC } from '@twobirds/microcomponents';
|
|
129
101
|
|
|
130
102
|
// Parent Micro Component
|
|
131
103
|
class ParentMC extends MC {
|
|
@@ -145,6 +117,7 @@ Child Micro Component
|
|
|
145
117
|
This component has a data setter that updates the internal React state in each child:
|
|
146
118
|
|
|
147
119
|
```javascript
|
|
120
|
+
import { MC } from '@twobirds/microcomponents';
|
|
148
121
|
|
|
149
122
|
// Child Micro Component
|
|
150
123
|
class ChildMC extends MC {
|
|
@@ -170,15 +143,15 @@ The parent component attaches an instance of ParentMC to the DOM node and sets i
|
|
|
170
143
|
|
|
171
144
|
import React, { useState, useRef, useEffect } from 'react';
|
|
172
145
|
import { MC } from '@twobirds/microcomponents';
|
|
146
|
+
import { ParentMC } from '@myCompany/ParentMC';
|
|
173
147
|
|
|
174
148
|
const ParentComponent = () => {
|
|
175
149
|
const [inputValue, setInputValue] = useState("");
|
|
176
150
|
const parentRef = useRef(null);
|
|
151
|
+
const parentMC = new ParentMC( parentRef );
|
|
152
|
+
const sender = MC.add(parentRef.current, 'parentMC', parentMC);
|
|
177
153
|
|
|
178
154
|
useEffect(() => {
|
|
179
|
-
const parentMC = new ParentMC(parentRef.current); // Pass the DOM node to ParentMC
|
|
180
|
-
MC.add(parentRef.current, 'parentMC', parentMC);
|
|
181
|
-
|
|
182
155
|
// Update value in ParentMC whenever inputValue changes
|
|
183
156
|
parentMC.value = inputValue;
|
|
184
157
|
}, [inputValue]);
|
|
@@ -188,7 +161,7 @@ const ParentComponent = () => {
|
|
|
188
161
|
<input
|
|
189
162
|
type="text"
|
|
190
163
|
value={inputValue}
|
|
191
|
-
onChange={(e) => setInputValue(e.target.value)}
|
|
164
|
+
onChange={(e) => setInputValue( e.target.value )}
|
|
192
165
|
placeholder="Type to send data to children"
|
|
193
166
|
/>
|
|
194
167
|
<ChildComponent />
|
|
@@ -202,20 +175,21 @@ Child Component
|
|
|
202
175
|
The child component attaches an instance of ChildMC, which updates its state whenever data is set.
|
|
203
176
|
|
|
204
177
|
```javascript
|
|
178
|
+
import React, { useState, useRef } from 'react';
|
|
179
|
+
import { MC } from '@twobirds/microcomponents';
|
|
180
|
+
import { ChildMC } from '@myCompany/ChildMC';
|
|
181
|
+
|
|
205
182
|
|
|
206
183
|
const ChildComponent = () => {
|
|
207
184
|
const [childData, setChildData] = useState("");
|
|
208
185
|
const childRef = useRef(null);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const childMC = new ChildMC(childRef.current, setChildData); // Pass DOM node and state setter to ChildMC
|
|
212
|
-
MC.add(childRef.current, 'targetMC', childMC);
|
|
213
|
-
}, []);
|
|
186
|
+
const childMC = new ChildMC( childRef, setChildData );
|
|
187
|
+
const receiver = MC.add(childRef.current, 'childMC', childMC);
|
|
214
188
|
|
|
215
189
|
return (
|
|
216
190
|
<div ref={childRef}>
|
|
217
191
|
<h3>Received Data:</h3>
|
|
218
|
-
<p>
|
|
192
|
+
<p>childData</p>
|
|
219
193
|
</div>
|
|
220
194
|
);
|
|
221
195
|
};
|
package/public/test.js
CHANGED
|
@@ -198,7 +198,7 @@ console.log("domElement\n ._mc", domElement._mc);
|
|
|
198
198
|
console.log("domElement\n ._mc\n .myFirstMC", domElement._mc.myFirstMC);
|
|
199
199
|
console.log("domElement\n ._mc\n .myFirstMC\n ._mc (MC.debug = false)", domElement._mc.myFirstMC._mc);
|
|
200
200
|
MC.debug = true;
|
|
201
|
-
console.log("domElement\n ._mc\n
|
|
201
|
+
console.log("domElement\n ._mc\n .myFirstMC\n ._mc (MC.debug = true)", domElement._mc.myFirstMC._mc);
|
|
202
202
|
MC.debug = false;
|
|
203
203
|
/*
|
|
204
204
|
test selectors
|
package/src/test.js
CHANGED