@twobirds/microcomponents 0.0.1 → 0.0.3

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 (35) hide show
  1. package/.gitlab-ci.yml +16 -0
  2. package/MicroComponentProposal_draft.md +10 -7
  3. package/README.md +10 -6
  4. package/assets/fiddle/MicroComponents.svg +15 -0
  5. package/assets/fiddle/fiddle.css +0 -0
  6. package/assets/fiddle/fiddle.js +0 -0
  7. package/assets/fiddle/index.html +0 -0
  8. package/assets/index.html +11 -0
  9. package/dist/microcomponents.d.ts +8 -3
  10. package/dist/microcomponents.d.ts.map +1 -1
  11. package/dist/microcomponents.js +87 -47
  12. package/dist/microcomponents.min.js +23 -16
  13. package/dist/microcomponents.ts +212 -0
  14. package/package.json +27 -6
  15. package/public/docs/assets/search.js +1 -0
  16. package/{docs → public/docs}/classes/microcomponents.MC.html +73 -31
  17. package/{docs → public/docs}/classes/microcomponents_es3.MC.html +16 -16
  18. package/{docs → public/docs}/functions/microcomponents_es3.__isEmpty.html +5 -5
  19. package/{docs → public/docs}/index.html +17 -12
  20. package/{docs → public/docs}/interfaces/microcomponents.HTMLElementMc.html +6 -6
  21. package/{docs → public/docs}/modules/microcomponents.html +5 -5
  22. package/{docs → public/docs}/modules/microcomponents_es3.html +4 -4
  23. package/{docs → public/docs}/modules.html +5 -5
  24. package/public/fiddle/MicroComponents.svg +15 -0
  25. package/public/fiddle/fiddle.css +0 -0
  26. package/public/fiddle/fiddle.js +0 -0
  27. package/public/fiddle/index.html +0 -0
  28. package/public/index.html +11 -0
  29. package/src/microcomponents.ts +97 -54
  30. package/typedoc.json +3 -3
  31. package/docs/assets/search.js +0 -1
  32. /package/{docs → public/docs}/.nojekyll +0 -0
  33. /package/{docs → public/docs}/assets/highlight.css +0 -0
  34. /package/{docs → public/docs}/assets/main.js +0 -0
  35. /package/{docs → public/docs}/assets/style.css +0 -0
package/.gitlab-ci.yml ADDED
@@ -0,0 +1,16 @@
1
+ # The Docker image that will be used to build your app
2
+ image: node:lts
3
+ # Functions that should be executed before the build script is run
4
+ before_script:
5
+ - npm i
6
+ pages:
7
+ script:
8
+ - npm run build
9
+ artifacts:
10
+ paths:
11
+ # The folder that contains the files to be exposed at the Page URL
12
+ - public
13
+ rules:
14
+ # This ensures that only pushes to the default branch will trigger
15
+ # a pages deploy
16
+ - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
@@ -13,15 +13,18 @@ Microcomponents provide a way to encapsulate functionality and state within a ta
13
13
  **Proposed API:**
14
14
 
15
15
  - **Static Methods:**
16
- - `MC.add(target, key, element)`: Attach a micro component.
17
- - `MC.remove(target, key)`: Detach a micro component.
16
+ - `MC.add( taarget, key, element)`: Attach a top level micro component to an HTMLElement.
17
+ - `MC.remove( target, key )`: Detach a top level micro component from an HTMLElement.
18
+ - `MC.siblings( target )`: get top level micro components from an HTMLElement.
18
19
 
19
20
  - **Instance Methods:**
20
- - `siblings(search)`: Retrieve sibling micro components.
21
- - `parent(search)`: Get parent micro components.
22
- - `parents(search)`: Get all ancestor micro components.
23
- - `children(search)`: Retrieve child micro components.
24
- - `descendants(search)`: Get all descendant micro components.
21
+ - `add( key, element )`: Attach a private Micro Component to a Micro Component.
22
+ - `remove( key )`: Detach a private Micro Component from a Micro Component.
23
+ - `siblings(search?)`: Retrieve sibling micro components.
24
+ - `parent(search?)`: Get parent top level micro components.
25
+ - `parents(search?)`: Get all ancestor top level micro components.
26
+ - `children(search?)`: Retrieve child top level micro components.
27
+ - `descendants(search?)`: Get all descendant top level micro components.
25
28
 
26
29
  **Use Cases:**
27
30
  1. Modular web applications.
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  ## MICRO COMPONENTS
2
2
 
3
- ![Micro Components Logo](./MicroComponents.svg)
3
+ ![Micro Components Logo](https://gitlab.com/twoBirds/microcomponents/-/raw/main/MicroComponents.svg)
4
4
 
5
5
  This code aims at **improving Javascript modularity**. It does not describe a specific Micro Component itself but rather describes they way they are **organized**. A typical example of a **Micro Component** can be found in "additional concepts" below.
6
6
 
7
- Using micro components enforces **DRY, KISS and SOLID** principles in Javascript programming. Read this [RFC](./MicroComponentProposal_draft.md?ref_type=heads) for the shortest info.
7
+ Using micro components enforces **DRY, KISS and SOLID** principles in Javascript programming. Read this [RFC](https://gitlab.com/twoBirds/microcomponents/-/blob/main/MicroComponentProposal_draft.md?ref_type=heads) for the shortest info.
8
8
 
9
- This is a low-level approach. It consists of a single class with 2 static methods and 5 selector methods, and weights less than 2 kB. Also there is an ES3 version to help e.g. [hbbtv](https://en.wikipedia.org/wiki/Hybrid_Broadcast_Broadband_TV) modular JS coding, or any other device that relies on ES3.
9
+ This is a low-level approach. It consists of a single class with 3 static methods and 5 selector methods, and weights in at ~2 kB. Also there is an ES3 version to help e.g. [hbbtv](https://en.wikipedia.org/wiki/Hybrid_Broadcast_Broadband_TV) modular JS coding, or any other device that relies on ES3.
10
10
 
11
11
  For an overview, continue reading.
12
12
 
13
- For a detailed functional description goto [Micro Component Usage](https://gitlab.com/twoBirds/microcomponents/-/blob/main/microcomponents_usage.md?ref_type=heads).
13
+ For a detailed functional description goto [Micro Component Usage](https://gitlab.com/twoBirds/microcomponents/-/blob/main/microcomponents_usage.md?ref_type=heads) and check the [typedoc API documentation](http://twobirds.gitlab.io/microcomponents/docs/modules.html).
14
14
 
15
15
  To see what can be done, go to [additional concepts](https://gitlab.com/twoBirds/microcomponents/-/blob/main/microcomponents_magic.md?ref_type=heads) which delve a little deeper into how to use it, and what it already has been used for.
16
16
 
@@ -59,7 +59,7 @@ before:
59
59
 
60
60
  code: (assume "Button" is some class in a library)
61
61
  ```javascript
62
- import 'MC' from 'twobirds/microcomponents';
62
+ import 'MC' from '@twobirds/microcomponents';
63
63
  import 'Button' from 'tb/ui'; // made-up example library
64
64
 
65
65
  // select first button element in DOM
@@ -93,7 +93,11 @@ This functionality has been used in very big and complicated data processing pro
93
93
  - to represent business processes and their tasks
94
94
  - and lately to compose very complex native web components from distinct modular functionality.
95
95
 
96
- I decided extract this from the [twoBirds framework](https://www.npmjs.com/package/twobirds-core), since it is framework agnostic and relies solely on the standard DOM and native javascript or typescript.
96
+ I decided to extract this functionality from the [twoBirds framework](https://www.npmjs.com/package/twobirds-core), since it is framework agnostic, and relies solely on the standard DOM and native javascript or typescript, and is a useful tool in itself.
97
+
98
+ ## Useful Links
99
+
100
+ [API documentation](http://twobirds.gitlab.io/microcomponents/docs/modules.html)
97
101
 
98
102
  ## Contact
99
103
  Feel free to contact me for any questions or inquiries:
@@ -0,0 +1,15 @@
1
+ <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
2
+ <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
3
+ <title>test</title>
4
+ <rect fill="transparent" x="0" y="0" width="200" height="200" fill-opacity="1"/>
5
+ <g style="fill:transparent">
6
+ <title>first bird</title>
7
+ <path fill="#18829c" d="
8
+ m15,160
9
+ a30,75 45 1 0 160,-150
10
+ a20,50 225 1 1 -110,100
11
+ a12,25 45 1 1 60,-50
12
+ a20,50 225 1 0 -110,100
13
+ " />
14
+ </g>
15
+ </svg>
File without changes
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Micro Components</title>
7
+ </head>
8
+ <body>
9
+ <a href="http://twobirds.gitlab.io/microcomponents/docs/modules.html" target="_blank">API</a>
10
+ </body>
11
+ </html>
@@ -1,14 +1,19 @@
1
1
  export declare class MC {
2
2
  private target;
3
3
  private privateMCs;
4
+ _mc?: {
5
+ [key: string]: any;
6
+ };
4
7
  static debug: boolean;
5
8
  constructor(target?: HTMLElement | null);
6
- static add(element?: any, key?: string, target?: HTMLElement): any;
7
- add(element?: any, key?: string, target?: HTMLElement): any;
9
+ static siblings(target: HTMLElement, search?: string): any[];
10
+ static add(target: HTMLElement, key: string, element?: any): any[];
8
11
  static remove(target: HTMLElement, key: string): void;
9
- remove(key: string): void;
10
12
  private getMicroComponents;
11
13
  private traverseNodes;
14
+ private isDOM;
15
+ add(key?: string, element?: any): any;
16
+ remove(key: string): void;
12
17
  siblings(search?: string): any[];
13
18
  parent(search?: string): any[];
14
19
  parents(search?: string): any[];
@@ -1 +1 @@
1
- {"version":3,"file":"microcomponents.d.ts","sourceRoot":"","sources":["../src/microcomponents.ts"],"names":[],"mappings":"AACA,qBAAa,EAAE;IAEd,OAAO,CAAC,MAAM,CAAqB;IAEnC,OAAO,CAAC,UAAU,CAA8B;IAEhD,MAAM,CAAC,KAAK,EAAE,OAAO,CAAS;gBAElB,MAAM,GAAE,WAAW,GAAG,IAAW;IAM7C,MAAM,CAAC,GAAG,CAAE,OAAO,GAAE,GAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAI,GAAG;IAuBxE,GAAG,CAAE,OAAO,GAAE,GAAQ,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAI,GAAG;IAcjE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAkBrD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAiBzB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,aAAa;IAwBrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAKhC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAQ9B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAQ/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAUhC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;CAInC;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IACjD,GAAG,EAAE,EAAE,CAAC;CACR"}
1
+ {"version":3,"file":"microcomponents.d.ts","sourceRoot":"","sources":["../src/microcomponents.ts"],"names":[],"mappings":"AACA,qBAAa,EAAE;IAEd,OAAO,CAAC,MAAM,CAAqB;IAEnC,OAAO,CAAC,UAAU,CAA8B;IAEhD,GAAG,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAM;IAElC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAS;gBAElB,MAAM,GAAE,WAAW,GAAG,IAAW;IAS7C,MAAM,CAAC,QAAQ,CAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAI,GAAG,EAAE;IAQ9D,MAAM,CAAC,GAAG,CAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,GAAQ,GAAI,GAAG,EAAE;IAqBxE,MAAM,CAAC,MAAM,CAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAI,IAAI;IA8BvD,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,KAAK;IASb,GAAG,CAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,GAAQ,GAAI,GAAG;IAU3C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAczB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAchC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAQ9B,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAQ/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;IAahC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,EAAE;CAOnC;AAED,MAAM,WAAW,aAAc,SAAQ,WAAW;IACjD,GAAG,EAAE,EAAE,CAAC;CACR"}
@@ -2,46 +2,52 @@
2
2
  export class MC {
3
3
  target;
4
4
  privateMCs = {};
5
+ _mc = {};
5
6
  static debug = false;
6
7
  constructor(target = null) {
7
8
  this.target = target;
8
9
  this.privateMCs = {};
10
+ if (MC?.debug) {
11
+ this._mc = this.privateMCs;
12
+ }
13
+ ;
14
+ }
15
+ // return all top-level micro components from an HTMLElement
16
+ static siblings(target, search) {
17
+ let t = target;
18
+ if (!t?._mc)
19
+ return [];
20
+ let mc = t._mc;
21
+ return search ? mc[search] ? [mc[search]] : [] : [...Object.entries(t._mc)];
9
22
  }
10
23
  // add a microcomponent to a target DOM node
11
- static add(element = {}, key, target) {
24
+ static add(target, key, element = {}) {
12
25
  const mc = target;
13
- if (key && target) {
14
- // create the _mc property if necessary
15
- if (!mc._mc) {
16
- mc._mc = new MC();
17
- }
18
- // add the element with the given property key to the _mc property object
19
- if (key && !mc._mc[key]) {
20
- mc._mc[key] = element;
21
- if (target) {
22
- target.setAttribute('_mc', '');
23
- }
24
- }
25
- }
26
- return element;
27
- }
28
- // add a microcomponent to the DOM or to the private microcomponent collection
29
- add(element = {}, key, target) {
30
- // add the element
31
- if (target && key) {
32
- // ...to the DOM
33
- MC.add(element, key, target);
26
+ // create the _mc property if necessary
27
+ if (!mc._mc) {
28
+ mc._mc = new MC();
34
29
  }
35
- else if (key) {
36
- // ... to the private element collection
37
- this.privateMCs[key] = element;
30
+ // add the element with the given property key to the _mc property object
31
+ if (key && !mc._mc[key]) {
32
+ mc._mc[key] = element;
33
+ if (target) {
34
+ target.setAttribute('_mc', '');
35
+ }
38
36
  }
39
37
  return element;
40
38
  }
41
- // remove a micro component from the DOM
39
+ // remove a micro component from the target DOM node
42
40
  static remove(target, key) {
41
+ if ( //silent fail
42
+ !key
43
+ || typeof key !== 'string'
44
+ || !target
45
+ || target instanceof HTMLElement === false) {
46
+ return;
47
+ }
48
+ ;
43
49
  const mc = target;
44
- // delete the property from the DOM
50
+ // delete the property from the HTMLElement _mc collection
45
51
  if (mc._mc && mc._mc[key]) {
46
52
  delete mc._mc[key];
47
53
  }
@@ -51,16 +57,6 @@ export class MC {
51
57
  }
52
58
  return;
53
59
  }
54
- // remove a micro component from the DOM or the private microcomponent collection
55
- remove(key) {
56
- // remove the component from the private collection
57
- if (key in this.privateMCs) {
58
- delete this.privateMCs[key];
59
- }
60
- if (MC.debug && this.target) {
61
- MC.remove(this.target, key);
62
- }
63
- }
64
60
  /*
65
61
  helper methods
66
62
  */
@@ -69,11 +65,21 @@ export class MC {
69
65
  let mcValues = [];
70
66
  elements.forEach(e => {
71
67
  if (e) {
72
- if (!search && e._mc) {
73
- mcValues = mcValues.concat(Object.values(e._mc));
68
+ if (e instanceof HTMLElement) {
69
+ if (!search && e._mc) {
70
+ mcValues = mcValues.concat(Object.values(e._mc));
71
+ }
72
+ else if (search && e._mc && e._mc[search]) {
73
+ mcValues.push(e._mc[search]);
74
+ }
74
75
  }
75
- else if (search && e._mc && e._mc[search]) {
76
- mcValues.push(e._mc[search]);
76
+ else if (e instanceof MC) {
77
+ if (!search) {
78
+ mcValues = mcValues.concat(Object.values(this.privateMCs));
79
+ }
80
+ else if (search && this.privateMCs[search]) {
81
+ mcValues.push(e._mc[search]);
82
+ }
77
83
  }
78
84
  }
79
85
  });
@@ -97,27 +103,59 @@ export class MC {
97
103
  }
98
104
  return mcValues;
99
105
  }
106
+ isDOM(element) {
107
+ return element && element instanceof HTMLElement;
108
+ }
109
+ /*
110
+ Methods to handle private MCs
111
+ */
112
+ // add a microcomponent to the private microcomponent collection
113
+ add(key, element = {}) {
114
+ // add the element
115
+ if (key) {
116
+ this.privateMCs[key] = element; // also the first element in the private MC collection
117
+ }
118
+ return element;
119
+ }
120
+ // remove a micro component from the private microcomponent collection
121
+ remove(key) {
122
+ // remove the component from the private collection
123
+ if (key in this.privateMCs) {
124
+ delete this.privateMCs[key];
125
+ }
126
+ }
100
127
  /*
101
128
  selector methods, non-chainable
102
129
  */
103
- // all public _mc members and private collection members
130
+ // all private collection members
104
131
  siblings(search) {
105
- return this.getMicroComponents([this.target], search).concat(Object.entries(this.privateMCs));
132
+ if (this.target) {
133
+ if (this.target instanceof HTMLElement === true) {
134
+ return this.getMicroComponents([this.target], search);
135
+ }
136
+ else {
137
+ const result = this.privateMCs[search || ''];
138
+ return search && result ? [result] : Object.entries(this.privateMCs);
139
+ }
140
+ }
141
+ return [];
106
142
  }
107
- // first anchestor DOM node, all puclic MCs
143
+ // first anchestor DOM node, all public MCs
108
144
  parent(search) {
109
- if (!this.target)
145
+ if (!this.isDOM(this.target))
110
146
  return [];
111
147
  return this.traverseNodes(this.target.parentNode, search, true);
112
148
  }
113
- // all anchestor DOM nodes, beginning with the closest, all puclic MCs
149
+ // all anchestor DOM nodes, beginning with the closest, all public MCs
114
150
  parents(search) {
115
- if (!this.target)
151
+ if (!this.isDOM(this.target))
116
152
  return [];
117
153
  return this.traverseNodes(this.target.parentNode, search, false);
118
154
  }
119
155
  // nearest child DOM nodes, all puclic MCs
120
156
  children(search) {
157
+ if (!this.isDOM(this.target))
158
+ return [];
121
159
  const id = crypto.randomUUID();
122
160
  this.target.setAttribute('temp-id', id);
123
161
  const myDomElements = this.target.querySelectorAll(`*[_mc]:not([temp-id="${id}"] [_mc] [_mc])`);
@@ -127,6 +165,8 @@ export class MC {
127
165
  }
128
166
  // all descendant DOM nodes, all puclic MCs
129
167
  descendants(search) {
168
+ if (!this.isDOM(this.target))
169
+ return [];
130
170
  const myDomElements = this.target.querySelectorAll('*[_mc]');
131
171
  return this.getMicroComponents([...myDomElements], search);
132
172
  }
@@ -1,27 +1,34 @@
1
- 'use strict';export class MC{target;privateMCs={};static debug=false;constructor(target=null){this.target=target;this.privateMCs={};}
2
- static add(element={},key,target){const mc=target;if(key&&target){if(!mc._mc){mc._mc=new MC();}
3
- if(key&&!mc._mc[key]){mc._mc[key]=element;if(target){target.setAttribute('_mc','');}}}
1
+ 'use strict';export class MC{target;privateMCs={};_mc={};static debug=false;constructor(target=null){this.target=target;this.privateMCs={};if(MC?.debug){this._mc=this.privateMCs;};}
2
+ static siblings(target,search){let t=target;if(!t?._mc)
3
+ return[];let mc=t._mc;return search?mc[search]?[mc[search]]:[]:[...Object.entries(t._mc)];}
4
+ static add(target,key,element={}){const mc=target;if(!mc._mc){mc._mc=new MC();}
5
+ if(key&&!mc._mc[key]){mc._mc[key]=element;if(target){target.setAttribute('_mc','');}}
4
6
  return element;}
5
- add(element={},key,target){if(target&&key){MC.add(element,key,target);}
6
- else if(key){this.privateMCs[key]=element;}
7
- return element;}
8
- static remove(target,key){const mc=target;if(mc._mc&&mc._mc[key]){delete mc._mc[key];}
7
+ static remove(target,key){if(!key||typeof key!=='string'||!target||target instanceof HTMLElement===false){return;};const mc=target;if(mc._mc&&mc._mc[key]){delete mc._mc[key];}
9
8
  if(!Object.keys(mc._mc).length&&target.hasAttribute('_mc')){target.removeAttribute('_mc');}
10
9
  return;}
11
- remove(key){if(key in this.privateMCs){delete this.privateMCs[key];}
12
- if(MC.debug&&this.target){MC.remove(this.target,key);}}
13
- getMicroComponents(elements,search){let mcValues=[];elements.forEach(e=>{if(e){if(!search&&e._mc){mcValues=mcValues.concat(Object.values(e._mc));}
14
- else if(search&&e._mc&&e._mc[search]){mcValues.push(e._mc[search]);}}});return mcValues;}
10
+ getMicroComponents(elements,search){let mcValues=[];elements.forEach(e=>{if(e){if(e instanceof HTMLElement){if(!search&&e._mc){mcValues=mcValues.concat(Object.values(e._mc));}
11
+ else if(search&&e._mc&&e._mc[search]){mcValues.push(e._mc[search]);}}
12
+ else if(e instanceof MC){if(!search){mcValues=mcValues.concat(Object.values(this.privateMCs));}
13
+ else if(search&&this.privateMCs[search]){mcValues.push(e._mc[search]);}}}});return mcValues;}
15
14
  traverseNodes(node,search,firstonly=true){let mcValues=[];while(node){if(node._mc){if(!search){mcValues=mcValues.concat(Object.values(node._mc));}
16
15
  else if(search&&node._mc[search]){mcValues.push(node._mc[search]);}
17
16
  if(firstonly)
18
17
  return mcValues;}
19
18
  node=node.parentNode;}
20
19
  return mcValues;}
21
- siblings(search){return this.getMicroComponents([this.target],search).concat(Object.entries(this.privateMCs));}
22
- parent(search){if(!this.target)
20
+ isDOM(element){return element&&element instanceof HTMLElement;}
21
+ add(key,element={}){if(key){this.privateMCs[key]=element;}
22
+ return element;}
23
+ remove(key){if(key in this.privateMCs){delete this.privateMCs[key];}}
24
+ siblings(search){if(this.target){if(this.target instanceof HTMLElement===true){return this.getMicroComponents([this.target],search);}
25
+ else{const result=this.privateMCs[search||''];return search&&result?[result]:Object.entries(this.privateMCs);}}
26
+ return[];}
27
+ parent(search){if(!this.isDOM(this.target))
23
28
  return[];return this.traverseNodes(this.target.parentNode,search,true);}
24
- parents(search){if(!this.target)
29
+ parents(search){if(!this.isDOM(this.target))
25
30
  return[];return this.traverseNodes(this.target.parentNode,search,false);}
26
- children(search){const id=crypto.randomUUID();this.target.setAttribute('temp-id',id);const myDomElements=this.target.querySelectorAll(`*[_mc]:not([temp-id="${id}"][_mc][_mc])`);const mcValues=this.getMicroComponents([...myDomElements],search);this.target.removeAttribute('temp-id');return mcValues;}
27
- descendants(search){const myDomElements=this.target.querySelectorAll('*[_mc]');return this.getMicroComponents([...myDomElements],search);}}
31
+ children(search){if(!this.isDOM(this.target))
32
+ return[];const id=crypto.randomUUID();this.target.setAttribute('temp-id',id);const myDomElements=this.target.querySelectorAll(`*[_mc]:not([temp-id="${id}"][_mc][_mc])`);const mcValues=this.getMicroComponents([...myDomElements],search);this.target.removeAttribute('temp-id');return mcValues;}
33
+ descendants(search){if(!this.isDOM(this.target))
34
+ return[];const myDomElements=this.target.querySelectorAll('*[_mc]');return this.getMicroComponents([...myDomElements],search);}}
@@ -0,0 +1,212 @@
1
+ 'use strict';
2
+ export class MC {
3
+
4
+ private target: HTMLElement | null;
5
+
6
+ private privateMCs: { [key: string]: any } = {};
7
+
8
+ _mc?: { [key: string]: any } = {};
9
+
10
+ static debug: boolean = false;
11
+
12
+ constructor(target: HTMLElement | null = null) {
13
+ this.target = target;
14
+ this.privateMCs = {};
15
+ if ( MC?.debug ) {
16
+ this._mc = this.privateMCs;
17
+ };
18
+ }
19
+
20
+ // return all top-level micro components from an HTMLElement
21
+ static siblings( target: HTMLElement, search?: string ): any[] {
22
+ let t = target as HTMLElementMc;
23
+ if ( !t?._mc ) return [];
24
+ let mc: { [key: string]: any } = t._mc;
25
+ return search ? mc[search] ? [ mc[search] ] : [] : [ ...Object.entries( t._mc ) ];
26
+ }
27
+
28
+ // add a microcomponent to a target DOM node
29
+ static add( target: HTMLElement, key: string, element: any = {} ): any[] {
30
+
31
+ const mc = target as any;
32
+
33
+ // create the _mc property if necessary
34
+ if ( !mc._mc ){
35
+ mc._mc = new MC();
36
+ }
37
+
38
+ // add the element with the given property key to the _mc property object
39
+ if ( key && !mc._mc[ key ] ){
40
+ mc._mc[ key ] = element;
41
+ if ( target ) {
42
+ target.setAttribute('_mc', '' );
43
+ }
44
+ }
45
+
46
+ return element;
47
+ }
48
+
49
+ // remove a micro component from the target DOM node
50
+ static remove( target: HTMLElement, key: string ): void {
51
+
52
+ if ( //silent fail
53
+ !key
54
+ || typeof key !== 'string'
55
+ || !target
56
+ || target instanceof HTMLElement === false ) {
57
+ return;
58
+ };
59
+
60
+ const mc = target as any;
61
+
62
+ // delete the property from the HTMLElement _mc collection
63
+ if (mc._mc && mc._mc[key]) {
64
+ delete mc._mc[key];
65
+ }
66
+
67
+ // remove the _mc attribute if the DOM collection is empty
68
+ if ( !Object.keys(mc._mc).length && target.hasAttribute('_mc') ) {
69
+ target.removeAttribute('_mc');
70
+ }
71
+
72
+ return;
73
+ }
74
+
75
+ /*
76
+ helper methods
77
+ */
78
+
79
+ // get all microcomponents from a list of HTMLElements
80
+ private getMicroComponents(elements: any[], search?: string): any[] {
81
+
82
+ let mcValues: any[] = [];
83
+
84
+ elements.forEach(e => {
85
+ if ( e ){
86
+ if ( e instanceof HTMLElement ){
87
+ if (!search && (e as HTMLElementMc)._mc) {
88
+ mcValues = mcValues.concat(Object.values((e as any)._mc));
89
+ } else if (search && (e as HTMLElementMc)._mc && (e as any)._mc[search]) {
90
+ mcValues.push((e as any)._mc[search]);
91
+ }
92
+ } else if (e instanceof MC ){
93
+ if ( !search ) {
94
+ mcValues = mcValues.concat(Object.values( this.privateMCs ));
95
+ } else if (search && this.privateMCs[search]) {
96
+ mcValues.push((e as any)._mc[search]);
97
+ }
98
+ }
99
+ }
100
+ });
101
+
102
+ return mcValues;
103
+ }
104
+
105
+ // get all ancestor DOM nodes up to the document
106
+ private traverseNodes(node: Node | null, search?: string, firstonly: boolean = true): any[] {
107
+
108
+ let mcValues: any[] = [];
109
+
110
+ while (node) {
111
+ if ((node as HTMLElementMc)._mc) {
112
+ if (!search) {
113
+ mcValues = mcValues.concat(Object.values((node as any)._mc));
114
+ } else if (search && (node as any)._mc[search]) {
115
+ mcValues.push((node as any)._mc[search]);
116
+ }
117
+ if ( firstonly ) return mcValues;
118
+ }
119
+ node = node.parentNode;
120
+ }
121
+
122
+ return mcValues;
123
+ }
124
+
125
+ private isDOM( element: any ): boolean {
126
+ return element && element instanceof HTMLElement;
127
+ }
128
+
129
+ /*
130
+ Methods to handle private MCs
131
+ */
132
+
133
+ // add a microcomponent to the private microcomponent collection
134
+ add( key?: string, element: any = {} ): any {
135
+
136
+ // add the element
137
+ if ( key ){
138
+ this.privateMCs[key] = element; // also the first element in the private MC collection
139
+ }
140
+ return element;
141
+ }
142
+
143
+ // remove a micro component from the private microcomponent collection
144
+ remove(key: string): void {
145
+
146
+ // remove the component from the private collection
147
+ if (key in this.privateMCs) {
148
+ delete this.privateMCs[key];
149
+ }
150
+
151
+ }
152
+
153
+ /*
154
+ selector methods, non-chainable
155
+ */
156
+
157
+ // all private collection members
158
+ siblings(search?: string): any[] {
159
+ if ( this.target ){
160
+ if ( this.target instanceof HTMLElement === true ){
161
+ return this.getMicroComponents( [ this.target ], search );
162
+ } else {
163
+ const result = this.privateMCs[search || ''];
164
+ return search && result ? [ result ] : Object.entries( this.privateMCs );
165
+ }
166
+ }
167
+ return []
168
+ }
169
+
170
+
171
+ // first anchestor DOM node, all public MCs
172
+ parent(search?: string): any[] {
173
+
174
+ if ( !this.isDOM( this.target) ) return [];
175
+
176
+ return this.traverseNodes( ( this.target as HTMLElement).parentNode, search, true);
177
+ }
178
+
179
+ // all anchestor DOM nodes, beginning with the closest, all public MCs
180
+ parents(search?: string): any[] {
181
+
182
+ if ( !this.isDOM( this.target) ) return [];
183
+
184
+ return this.traverseNodes( (this.target as HTMLElement ).parentNode, search, false);
185
+ }
186
+
187
+ // nearest child DOM nodes, all puclic MCs
188
+ children(search?: string): any[] {
189
+
190
+ if ( !this.isDOM( this.target) ) return [];
191
+
192
+ const id = crypto.randomUUID();
193
+ (this.target as HTMLElement).setAttribute('temp-id', id);
194
+ const myDomElements = (this.target as HTMLElement).querySelectorAll(`*[_mc]:not([temp-id="${id}"] [_mc] [_mc])`);
195
+ const mcValues = this.getMicroComponents( [ ...myDomElements ], search);
196
+ (this.target as HTMLElement).removeAttribute('temp-id');
197
+ return mcValues;
198
+ }
199
+
200
+ // all descendant DOM nodes, all puclic MCs
201
+ descendants(search?: string): any[] {
202
+
203
+ if ( !this.isDOM( this.target) ) return [];
204
+
205
+ const myDomElements = (this.target as HTMLElement).querySelectorAll('*[_mc]');
206
+ return this.getMicroComponents( [ ...myDomElements ], search);
207
+ }
208
+ }
209
+
210
+ export interface HTMLElementMc extends HTMLElement {
211
+ _mc: MC;
212
+ }
package/package.json CHANGED
@@ -1,19 +1,40 @@
1
1
  {
2
2
  "name": "@twobirds/microcomponents",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Micro Components Organization Class",
5
5
  "main": "microcomponents.js",
6
6
  "sideEffects": false,
7
7
  "scripts": {
8
- "build": "tsc; npm run minify; npm run copyToDist; typedoc;",
8
+ "typedoc": "typedoc",
9
+ "clean": "rm -rf build/*; rm -rf docs/*; rm -rf dist/*;",
10
+ "prep": "cp -R assets/* public || true; cp src/* build || true;",
11
+ "build": "npm run clean; npm run prep; tsc; npm run minify; npm run copyToDist;",
9
12
  "minify": "jsmin -o build/microcomponents.es3.min.js ./src/microcomponents.es3.js;jsmin -o build/microcomponents.min.js build/microcomponents.js;",
10
- "copyToDist": "cp build/* dist; cp MicroComponents.svg dist"
13
+ "copyToDist": "cp build/* dist; cp MicroComponents.svg dist; cp MicroComponents.svg public/fiddle;"
11
14
  },
12
15
  "author": "",
13
16
  "license": "ISC",
14
17
  "devDependencies": {
15
18
  "jsmin": "^1.0.1",
16
- "typedoc": "^0.23.24",
17
- "typescript": "^5.6.2"
18
- }
19
+ "typedoc": "^0.26.10",
20
+ "typescript": "^5.6.3"
21
+ },
22
+ "keywords": [
23
+ "javascript",
24
+ "library",
25
+ "native",
26
+ "DOM manipulation",
27
+ "lightweight",
28
+ "standalone",
29
+ "SPA",
30
+ "PWA",
31
+ "ES3",
32
+ "ES5",
33
+ "ES6",
34
+ "ES7",
35
+ "ES2015",
36
+ "ES2016",
37
+ "client",
38
+ "API"
39
+ ]
19
40
  }