![logo](./MicroComponents.svg)

## MICRO COMPONENTS

**MCs are function blocks that you attach to DOM nodes.** These are re-usable in any framework, and you can have any number of MCs in one DOM node.

There are helpers for the following functionalities:

- **Web Components:** create native web components. Their functionality is comprised of a set of inner MCs.
- **State** is done by observable objects that you can attach callbacks to. This also allows for 1-way binding to DOM placeholders, and it can be extended to allow for complex data driven state machines.
- **Form Handling** allows for 2-way binding from an observable form object to DOM form input elements.
- **Communication** between DOM micro components is ensured via direct selected or directional bubbling CustomEvent's.
- **Autoloading** allows for build-free websites that dynamically load JS requirements into DOM HTMLElements.

The distinguishing feature - compared to other frameworks - is its **minimalism**, **portability** and **granular modularization**. In an almost literal sense MCs work like childrens building blocks, where a chest full of unassuming parts lets you compose whatever functionality lies in your imagination. 

**You work with one of the established frameworks?** You can still put this hands-on tool in your tool belt. You then have a plugin fallback solution for when your FW fails you or lacks functionality.

## Status

In [manual testing](https://twobirds.gitlab.io/microcomponents/test/test.html) ( also a speed test).

Check the [typedoc API reference](https://twobirds.gitlab.io/microcomponents/typedoc/index.html) if you want to drill into the source code.

The progress of coding is being streamed on [twitch](https://twitch.tv/frankieth) and [youtube](https://www.youtube.com/@FrankieThu).

## Simple Usage Examples

### **Micro Components**

**Hint:** The following code only shows how Micro Components are stored in the DOM.

html before:
```HTML
<div></div>
```

code:
```javascript
// create a custom micro component class
class MyMC extends DC{

	constructor( target ){
		super( target );
	}

	helloWorld(){
		console.log( 'Hello World' );
	}

}

// get some element from the DOM
const element = document.querySelector('div');

// Add the custom micro component instance to the target element
DC.add(
	element,
	'myMC',
	new MyMC( element )
);

// Hello World
element
	._mc
	.myMC
	.helloWorld();
```

html after:
```HTML
<div data-mc></div>
```
The `data-mc` **attribute** indicates that this **HTML element contains at least one micro component**. This is needed for the selectors.

The `_mc` **property** is the only interference with the DOM, so any other system should be happy to work with this.


### **Web Components / Custom Elements**

code:
```javascript
// create a custom micro component class
class MyComponent extends DC{

	constructor( target ){
		super( target );
	}

	// this event handler is attached automatically
	onClick(){
		console.log( '<my-component> clicked!' );
	}
}

defineCE( 'my-component', MyComponent );
```

after: you can use ...
```HTML
<my-component></my-component>
```
... in your template.

Or you can construct it programmatically:
```javascript
const myComponentClass = getCE('my-component');
const body = document.body;
body.append( new myComponentClass() );
```

### **State and 1-way-binding**

code:
```javascript
// create a custom micro component class
class MyMC extends DC{

	constructor( target ){
		super( target );
		this.state = { text: 'Hello world!' };

		// observe one property ...
		observe( this, 'state' );
		
		// or observe all properties defined so far
		observe( this ); 

		this.target.innerHTML = '{text}';

		// one way binding
		this.state.bind( target ); // links the state to DOM placeholders

		// attach your own callbacks
		this.state.subscribe( (value) => { 
			console.log(value); 
		});

		// now simply changing the state will change the DOM
		this.state.text = 'Hallo Welt';
	}

}
```

### **Forms and 2-way-binding**

code:
```javascript
// create a custom micro component class
class MyMC extends DC{

	constructor( target ){
		super( target );

		this.target.innerHTML = /*HTML*/ `
		<form>
			<input name="textinput" value="Hallo Welt!"/>
		</form>`; 
		
		// link the form property to the DOM input fields
		formValues( this, 'form', this.target );
		
		// now simply changing the form property will change the DOM input fields
		this.form.textinput = 'Hallo Welt';
	}

}
```

### **Event Handlers**

#### Native Events

code:
```javascript
// create a custom micro component class
class MyMC extends DC{

	constructor( target ){
		super( target );

		// attach event handler programatically
		let onHoverHandler = this.on( 'hover', () => {
			// ...
		});

		// remove event handler
		this.off( 'hover', onHoverHandler );
	}

	// this event handler is attached automatically
	onClick(){
		console.log( 'HTMLElement clicked!' );
	}

	// this event handler is attached automatically
	oneClick(){
		console.log( 'HTMLElement clicked! ( only fires once )' );
	}

}
```

#### Custom Events

code:
```javascript
// create a custom micro component class
class MyMC extends DC{

	constructor( target ){
		super( target );

		payload = {
			test: 42
		};

		setTimeout( () => {
			this.trigger('customEvent', payload );
		});
	}

	// this event handler is attached automatically
	onCustomEvent( ev ){
		console.log( 'onCustomEvent called with', ev.data.test ); // "42"
	}

}
```

## Goal

This code aims at improving Javascript modularity and encapsulation. Micro Components are built on **OOP** for structure, so you should embrace **DRY, KISS and SOLID** principles.

MCs provide a runtime app structure that is directly linked to the browser DOM. That is you don't need web components, you can attach MCs to plain HTMLElements. Having said this: the library also allows for standard web component programming, acting as a framework.

In general this is a **HTML / Web Standards first** system. There is almost no abstraction, especially not for templating, except state binding to the DOM via simple placeholders.

It has no interference with other frameworks, since it creates a second layer that hovers above the DOM. So what you intended to work as an add-on to React, is usable e.g. in Angular also. 

And, of course, you can use it as your main framework using its custom web component functionality.

Its basic principle is **composition over inheritance**. Also it helps to embrace **DIY** (**D**o **I**t **Y**ourself) **over Toolchains**, but this is up to your personal preference.

You can use **Vanilla JS or Typescript** or both in parallel in your project. For example you could use plain JS for rapid prototyping functionalities, then convert to TS for production.

Most of all this system by design **allows for outsourcing without sharing the main development system**. It is absolutely granular as it enforces **DRY** (**D**on't **R**epeat **Y**ourself).

Finally it allows for a clear distinction between `Junior`, `Senior` and `Architect` roles in a project. No more hiring junior programmers with 5 years experience in 50 tools under their belt. A junior in this system is somebody who likes HTML, CSS and JS/TS - nothing more. Teaching all of this system starting at zero takes 1 day. The rest is finger muscle memory and learning/knowing web standards.


## Documentation

This repository exports 4 independent functionalities:

1. **[Micro Components](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/MC.md?ref_type=heads)** contains the **MC** and **DC** classes you can use as super classes.


2. **[Elements](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/elements.md?ref_type=heads)** lets you define and use your own native web components. Uses (1). 
  - [Basic Usage](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/elements.md?ref_type=heads#create-a-custom-element). 
  - [Live Example](https://twobirds.gitlab.io/microcomponents/test/test.html)


3. **[Observables](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/observables.md?ref_type=heads)** add **observability** and **run time type safety** to object properties. Also they provide **1-way binding** to placeholders in your template HTML. 
  - [Basic Usage](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/observables.md?ref_type=heads#example)
  - [Live Example](https://twobirds.gitlab.io/microcomponents/test/test.html)


4. **[Formvalues](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/formvalues.md?ref_type=heads)** gives you **2-way binding** between a HTML form and an observable object. Uses (3). 
  - [Example Code](https://gitlab.com/twoBirds/microcomponents/-/blob/main/src/test/test/testform.ts?ref_type=heads)
  - [Live Example](https://twobirds.gitlab.io/microcomponents/test/test.html)

Also there is a bundle file that contains all of the above.

To see what can be done, go to [additional concepts](https://gitlab.com/twoBirds/microcomponents/-/blob/main/assets/documentation/magic.md?ref_type=heads) which shows what it already has been used for.

## Distinguishing Features

There are a few potentially unique aspects of this micro components system that might differentiate it from other framework or library:

- **Pure OOP Approach**: The system explicitly positions itself as a strict object-oriented alternative to the functional approaches that dominate many modern frameworks.


- **Minimal Interference**: The system has minimal DOM interference, only adding _mc property to DOM nodes that contain code. This makes it unusually compatible with other frameworks or libraries.


- **Hierarchical Component Traversal**: The built-in ancestor/closest/child/descendant traversal methods provide a clean way to navigate component relationships.


- **Direct DOM Integration**: Unlike virtual DOM-based frameworks, this approach works directly with the actual DOM while still providing component encapsulation.


- **Outsourcing Potential**: Your external coders do not need to access your code repository or your toolchain.


The strongest argument might be for developers who prefer OOP, want minimal framework lock-in, and need a lightweight solution that works well with existing code or other libraries.

## Contact

Feel free to contact me for any questions or inquiries:

email [Frank Thürigen](mailto:fthuerigen@gmail.com?subject=Micro%20Components)

You can [fund this](https://www.gofundme.com/f/nachhaltige-programmierung).

## Disclaimer

I decided to extract this functionality from the [twoBirds framework](https://www.npmjs.com/package/twobirds-core), because it is a useful tool in itself and it is framework agnostic. It relies solely on the standard DOM and native javascript or typescript.

Later this will be backported into twoBirds as a dependency, and twoBirds will become completely modularized on the base of MCs.

**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://www.gofundme.com/f/nachhaltige-programmierung). 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. 


