@twobirds/microcomponents 0.0.12 → 0.0.14

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 (37) hide show
  1. package/README.md +26 -44
  2. package/assets/documentation/ajaxian-1.png +0 -0
  3. package/assets/documentation/ajaxian-2.png +0 -0
  4. package/assets/documentation/ajaxian-3.png +0 -0
  5. package/assets/documentation/history.md +436 -0
  6. package/assets/documentation/how_tos.md +0 -0
  7. package/assets/documentation/introduction.md +0 -0
  8. package/{microcomponents_magic.md → assets/documentation/magic.md} +1 -1
  9. package/assets/documentation/rnd0023-1.jpg +0 -0
  10. package/assets/documentation/rnd0023-2.jpg +0 -0
  11. package/assets/documentation/rnd0023-3.jpg +0 -0
  12. package/assets/documentation/tB_react.md +369 -0
  13. package/package.json +2 -2
  14. package/public/documentation/ajaxian-1.png +0 -0
  15. package/public/documentation/ajaxian-2.png +0 -0
  16. package/public/documentation/ajaxian-3.png +0 -0
  17. package/public/documentation/functional_requirements.md +8 -0
  18. package/public/documentation/history.md +436 -0
  19. package/public/documentation/how_tos.md +0 -0
  20. package/public/documentation/introduction.md +0 -0
  21. package/public/documentation/magic.md +87 -0
  22. package/public/documentation/proposal_draft.md +37 -0
  23. package/public/documentation/rnd0023-1.jpg +0 -0
  24. package/public/documentation/rnd0023-2.jpg +0 -0
  25. package/public/documentation/rnd0023-3.jpg +0 -0
  26. package/public/documentation/tB_react.md +369 -0
  27. package/public/documentation/usage.md +142 -0
  28. package/public/documentation/why.md +25 -0
  29. package/public/test.js +20 -18
  30. package/src/test.js +22 -20
  31. package/dist/test.d.ts +0 -36
  32. package/dist/test.d.ts.map +0 -1
  33. package/dist/test.js +0 -214
  34. /package/{microcomponents_functional_requirements.md → assets/documentation/functional_requirements.md} +0 -0
  35. /package/{MicroComponentProposal_draft.md → assets/documentation/proposal_draft.md} +0 -0
  36. /package/{microcomponents_usage.md → assets/documentation/usage.md} +0 -0
  37. /package/{microcomponents_why.md → assets/documentation/why.md} +0 -0
@@ -0,0 +1,369 @@
1
+ # Discussing React Prop Drilling with ChatGPT
2
+
3
+ This is an interesting read where I wanted ChatGPT to come up with a Micro Component solution for a React problem.
4
+
5
+ To be honest, I knew MCs can solve it. But I wanted to know what ChatGPT can make of it. Spoiler: it got remarkably close on the first try. The second try was spot on.
6
+
7
+ Please mind I have a trained session with a backlog. So you wont get the same answers.
8
+
9
+ ***( Cut outs and comments are in parentheses...)***
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
+ ## Start Session
38
+
39
+ Me:
40
+ **Do you remember our chat regarding Micro Components vs. existing frameworks?**
41
+
42
+ ChatGPT:
43
+
44
+ Yes, I remember our discussion! We talked about your approach to microcomponents as distinct from established frameworks, with a focus on smaller, modular, data-driven components that are stored in a hash attached to DOM elements (specifically in a _tb property in twoBirds or _mc for microcomponents). Your system emphasizes manual wiring, observability, and ease of interaction across components, making it different from React, Vue, or other component libraries that depend heavily on virtual DOMs, JSX, or hooks.
45
+
46
+ Your components follow principles of separation of concerns and DRY by keeping interactions modular but flexible, and they use observables to trigger functions in other components, which can be linked in chains. Your approach allows a component-based design that integrates deeply into the DOM without the overhead of larger frameworks. And while existing frameworks typically follow a top-down data flow, your system allows bi-directional, observable properties that automatically update the DOM when data changes.
47
+
48
+ Would you like to revisit any specific aspect, or compare further?
49
+
50
+
51
+ ## React
52
+
53
+ Me:
54
+ **There was something about React specifically?**
55
+
56
+
57
+ ChatGPT:
58
+
59
+ (...)
60
+
61
+ ### Manual Wiring vs. React’s Context and Hooks:
62
+ React uses Context and hooks (like useState and useEffect) to manage data flow and lifecycle.
63
+
64
+ 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
+
66
+ ### Component Reusability and Scaling:
67
+ Both React and twoBirds support component-based architecture.
68
+
69
+ However, twoBirds 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 twoBirds does so at the microcomponent level, with direct chaining possible between components.
70
+
71
+ (...)
72
+
73
+ Each of these aspects underlines twoBirds’ 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
+
75
+ Would you like to dive into any of these differences in more detail?
76
+
77
+
78
+ ## Prop Drilling
79
+
80
+ Me:
81
+ **In general there was a problem regarding carrying properties from a component close to the root of the document to a component that is much deeper into the DOM tree, do you remember that?**
82
+
83
+ ChatGPT:
84
+
85
+ Yes, I remember!
86
+
87
+ We discussed the challenges in carrying properties or state from a root-level component down to deeply nested components. In React, this kind of deep property sharing can become cumbersome and often requires additional tools or patterns, such as:
88
+
89
+ ### Prop Drilling:
90
+ React requires passing data through each level of components in the tree via props, a process known as prop drilling. This can lead to complex and hard-to-manage code, especially when the data isn’t relevant to every component in the chain.
91
+
92
+ (...)
93
+
94
+ In contrast, your twoBirds microcomponents have an alternative approach that makes it easier to pass properties throughout the DOM tree:
95
+
96
+ ### Direct Microcomponent Selectors:
97
+ twoBirds 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.
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.
101
+
102
+ ***( ...this part was wrong, as it reflected on tB convenience observables, instead of pure micro components ... )***
103
+
104
+ ### Manual Wiring for Control:
105
+
106
+ **Because twoBirds relies 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
+
108
+ (...)
109
+
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 twoBirds selectors work with observables to achieve this?
111
+
112
+
113
+ ## Generate Code
114
+
115
+ Me:
116
+ **Can you give an example of 2 react components that interact with each other using micro components? Give me the code of both components, using microomponents to exchange data**
117
+
118
+ ***( The first result as shown below is edited and fed back to outline errors ChatGPT made, so this is not the original answer but my corrected feed back )***
119
+
120
+ ***( ChatGPTs errors were based on the assumption that MCs behave like twoBirds micro components, which turn properties in convenience observables automatically. These can be accessed like simple properties, but still work as observables. )***
121
+
122
+ Skip to [Final Version](#final-version) if you dont want to see my intermediate corrections.
123
+
124
+
125
+ ChatGPT:
126
+
127
+ Here’s an example of two React components interacting with each other using the Micro Components (MC) approach as you’ve described. In this example, the microcomponents are responsible for sharing and updating data across the two React components without relying on React's props or context.
128
+
129
+ In this scenario, we’ll have two React components:
130
+
131
+ ParentComponent: Contains a microcomponent managing shared state.
132
+ ChildComponent: Retrieves and observes updates to that shared state through the microcomponent system.
133
+
134
+ The Micro Component framework will handle state observability, allowing ChildComponent to respond to changes in ParentComponent.
135
+
136
+ ### Step 1: Set Up Micro Components for State Sharing
137
+
138
+ First, let’s create a microcomponent to hold shared data. This MC will be instantiated in ParentComponent and observed in ChildComponent.
139
+
140
+ ```javascript
141
+
142
+ // SharedStateMC.js
143
+ import {MC} from '@twobirds/microcomponents';
144
+
145
+ class SharedStateMC extends MC {
146
+ constructor(target) {
147
+ super(target);
148
+
149
+ // Define an observable property for shared data
150
+ // this part is wrong: ChatGPT assumed this property is a twoBirds convenience observable property, which MCs dont do automatically.
151
+ // lets for now assume it is
152
+ this.sharedData = "Initial data from Parent"; // this in fact is assumed to be an observable in tB, as any property defined in the constructor.
153
+ // Also, this observable property would be runtime type safe, BTW.
154
+ // This is important for public MCs, as they expose a PUBLIC interface to internal properties for EVERYBODY to use at runtime. So:
155
+ // document.getElementById("parent-root")._mc.sharedState.sharedData = 'My hilarious string';
156
+ // ... this will trigger the callbacks associated with it
157
+ // MCs ACT AS INTERFACES!
158
+ }
159
+
160
+ }
161
+
162
+ export default SharedStateMC;
163
+ ```
164
+
165
+ ### Step 2: Create ParentComponent with Micro Component for Shared State
166
+
167
+ In ParentComponent, we’ll create an instance of SharedStateMC and attach it as a microcomponent on the main DOM element of this component.
168
+
169
+ ```javascript
170
+
171
+ // ParentComponent.js
172
+ import React, { useEffect } from 'react';
173
+ import SharedStateMC from './SharedStateMC';
174
+
175
+ function ParentComponent() {
176
+ useEffect(() => {
177
+ // Attach SharedStateMC to the main component div
178
+ const parentElement = document.getElementById("parent-root");
179
+ const sharedState = MC.add( parentElement, 'sharedState', new SharedStateMC( parentElement ) );
180
+
181
+ // Simulate updating data after 3 seconds
182
+ // changing a tB convenience observable really is as easy as this, also it is type-safe at runtime
183
+ setTimeout(() => {
184
+ sharedState.sharedData = "Updated data from Parent";
185
+ }, 3000);
186
+ }, []);
187
+
188
+ return (
189
+ <div id="parent-root">
190
+ <h1>Parent Component</h1>
191
+ <p>Check ChildComponent for updated data.</p>
192
+ <ChildComponent />
193
+ </div>
194
+ );
195
+ }
196
+
197
+ export default ParentComponent;
198
+ ```
199
+
200
+ ### Step 3: Create ChildComponent to Observe and Display Shared Data
201
+
202
+ In ChildComponent, we’ll access the SharedStateMC instance created by ParentComponent using DOM selectors and observe the sharedData property.
203
+
204
+ ```javascript
205
+
206
+ // ChildComponent.js
207
+ import React, { useEffect, useState } from 'react';
208
+
209
+ function ChildComponent() {
210
+ const [data, setData] = useState("");
211
+
212
+ useEffect(() => {
213
+ // Access the microcomponent instance on the parent's DOM element
214
+ const parentElement = document.getElementById("parent-root");
215
+ const sharedStateMC = parentElement._mc.sharedState;
216
+
217
+ // Initial data load
218
+ setData(sharedStateMC.sharedData);
219
+
220
+ // Observe changes to shared data in SharedStateMC
221
+ // this isn't quite right, for reasons mentioned above, but close
222
+ sharedStateMC.observe((newData) => {
223
+ setData(newData);
224
+ });
225
+ }, []);
226
+
227
+ return (
228
+ <div>
229
+ <h2>Child Component</h2>
230
+ <p>Data from Parent: {data}</p>
231
+ </div>
232
+ );
233
+ }
234
+
235
+ export default ChildComponent;
236
+ ```
237
+
238
+ ### How It Works
239
+
240
+ In ParentComponent: An instance of SharedStateMC is created and attached to the main DOM element with an ID parent-root.
241
+ After 3 seconds, it updates sharedData to a new value.
242
+
243
+ In ChildComponent: We access the SharedStateMC instance via the _mc property of the parent element and observe sharedData.
244
+ When sharedData changes, ChildComponent re-renders with the updated data.
245
+
246
+ ### Explanation
247
+
248
+ Observable Property: sharedData is an observable property within SharedStateMC.
249
+ This allows the ChildComponent to subscribe and react to changes without using React's props or context.
250
+ Direct DOM Access:
251
+ The ChildComponent directly accesses ParentComponent's microcomponent via document.getElementById("parent-root")._mc.
252
+
253
+ This pattern effectively mimics cross-component communication in React but using the microcomponents as an intermediary for data sharing.
254
+
255
+
256
+ ## Final Version
257
+
258
+ Me:
259
+ **assume this revised markup... can you spot the difference? ( My feedback code from above was added )**
260
+
261
+ ChatGPT:
262
+
263
+ You’ve provided a revised example that incorporates microcomponents with clearer runtime type safety and public interfaces. Let’s review the differences and corrections made in this version:
264
+
265
+ ***( ChatGPT explains my changes )***
266
+
267
+ Here’s the final, corrected code with these changes fully implemented:
268
+
269
+ Final Revised Code
270
+ SharedStateMC.js
271
+
272
+ ```javascript
273
+ import { MC } from '@twobirds/microcomponents';
274
+
275
+ class SharedStateMC extends MC {
276
+ constructor(target) {
277
+ super(target);
278
+ // Define an observable property for shared data with runtime type safety
279
+ this.sharedData = "Initial data from Parent";
280
+ }
281
+ }
282
+
283
+ export default SharedStateMC;
284
+ ```
285
+
286
+
287
+ ParentComponent.js
288
+
289
+ ```javascript
290
+ import React, { useEffect } from 'react';
291
+ import SharedStateMC from './SharedStateMC';
292
+ import { MC } from '@twobirds/microcomponents';
293
+
294
+ function ParentComponent() {
295
+ useEffect(() => {
296
+ const parentElement = document.getElementById("parent-root");
297
+
298
+ // Attach SharedStateMC instance to parent element with 'sharedState' key
299
+ const sharedState = MC.add(parentElement, 'sharedState', new SharedStateMC(parentElement));
300
+
301
+ // Updating shared data after 3 seconds with observable property syntax
302
+ setTimeout(() => {
303
+ sharedState.sharedData = "Updated data from Parent";
304
+ }, 3000);
305
+ }, []);
306
+
307
+ return (
308
+ <div id="parent-root">
309
+ <h1>Parent Component</h1>
310
+ <p>Check ChildComponent for updated data.</p>
311
+ <ChildComponent />
312
+ </div>
313
+ );
314
+ }
315
+
316
+ export default ParentComponent;
317
+ ```
318
+
319
+
320
+ ChildComponent.js
321
+
322
+ ```javascript
323
+ import React, { useEffect, useState } from 'react';
324
+
325
+ function ChildComponent() {
326
+ const [data, setData] = useState("");
327
+
328
+ useEffect(() => {
329
+ const parentElement = document.getElementById("parent-root");
330
+ const sharedStateMC = parentElement._mc.sharedState;
331
+
332
+ // Initial data load
333
+ setData(sharedStateMC.sharedData);
334
+
335
+ // Observing updates to sharedData property
336
+ sharedStateMC.sharedData.observe((newData) => {
337
+ setData(newData);
338
+ });
339
+ }, []);
340
+
341
+ return (
342
+ <div>
343
+ <h2>Child Component</h2>
344
+ <p>Data from Parent: {data}</p>
345
+ </div>
346
+ );
347
+ }
348
+
349
+ export default ChildComponent;
350
+ ```
351
+
352
+ **Summary of Changes**
353
+
354
+ Observables: The sharedData property in SharedStateMC is now noted to be observable and accessible as a public interface.
355
+
356
+ Microcomponent Attaching: Using MC.add clarifies the attachment of the SharedStateMC instance to parentElement.
357
+
358
+ Runtime Type Safety: The property remains observable, allowing callbacks on sharedData in ChildComponent.
359
+
360
+ This implementation accurately reflects the design principles and interfaces for twoBirds MCs, allowing cross-component data sharing while ensuring type safety and a clean observable setup.
361
+
362
+
363
+ **ChatGPT can produce errors. Check the information.**
364
+
365
+ ## ... yes I do :-)
366
+
367
+ ***( ... but it was right on the money in the end. I love AI, albeit with a healthy grain of sceptic salt. )***
368
+
369
+ ***( ... and I asked about MCs and Angular likewise, and it directly pointed me to a NG module problem that can also be solved. It even came up with sample code. )***
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twobirds/microcomponents",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "Micro Components Organization Class",
5
5
  "main": "microcomponents.js",
6
6
  "sideEffects": false,
@@ -10,7 +10,7 @@
10
10
  "prep": "cp -R assets/* public || true; cp src/* build || true;",
11
11
  "build": "npm run clean; npm run prep; tsc; npm run minify; npm run copyToDist;",
12
12
  "minify": "jsmin -o build/microcomponents.es3.min.js ./src/microcomponents.es3.js;jsmin -o build/microcomponents.min.js build/microcomponents.js;",
13
- "copyToDist": "cp -R assets/* public || true; cp build/* dist; cp build/microcomponents.js public; cp build/test.js public; cp MicroComponents.svg dist; cp MicroComponents.svg public/fiddle;"
13
+ "copyToDist": "cp -R assets/* public || true; cp build/micro* dist; cp build/microcomponents.js public; cp build/test.js public; cp MicroComponents.svg dist; cp MicroComponents.svg public/fiddle;"
14
14
  },
15
15
  "author": "",
16
16
  "license": "ISC",
@@ -0,0 +1,8 @@
1
+ ## Functional Requirements
2
+
3
+ - I want to **enrich a standard HTMLElement instance or any object with encapsuled and modular javascript**, without having to resort to web components or big frameworks.
4
+ - I want to have an **interface** into this functionality that I can both tight and loosely couple.
5
+ - I want to **import and use Micro Components in any framework** that allows for direct DOM access.
6
+ - I want **a single location** in an HTMLElement instance where all this functionality is **stored and sufficiently organized**.
7
+ - I want to be able to use **selectors** to find those instances in the DOM.
8
+ - All this must stricly follow **web standards**.