@smoovy/composer v1.0.13
@smoovy/composer
Very simple component/service system. Optimized for TypesScript usage.
Installation
yarn add @smoovy/composeror
npm install --save @smoovy/composerComponent
A component is a very simple class, you just tell the composer what selector to use and it'll manage all updates and detects if the element is still in the DOM etc.
import { component } from  '@smoovy/composer';
/** Elements with the attribute `data-test` will be selected */
@component('test')
class TestComponent {
  constructor(
    private element: HTMLelement
  ) {}
  /** On creation after the injectors are done */
  onCreate() {}
  /** After the element is no longer in the DOM */
  onDestroy() {}
  /** Helper method to make unlistening easier **/
  onListen() {
    return () => {
      console.log('unlisten from listeners');
    };
  }
}
// you can change specify a different selector like this
@component({
  selector: '.select-this-class'
})Lifecycle methods are:
onCreate,onListenandonDestroy. All are optional ´Component config
You can inject config from the element dataset into your component like this:
<div
  data-test-message="Hello Universe!"
  data-test-count="8"
></div>
<!-- It's also possible to define an object. So the following is the same: -->
<div
  data-test='{ "message": "Hello Universe!", "count": 8 }'
></div>If you define both the "non-json" value has priority
import { component, config } from  '@smoovy/composer';
@component('test')
class TestComponent {
  @config('message')
  private message: string;
  @config('count', {
    type: Number,
    parse: (val: number) => val * val
  })
  private count = 0;
  onCreate() {
    console.log(this.message); // "Hello Universe!"
    console.log(this.count); // 64
  }
}Component query
To simplify the step of querying elements from your root element, you can use
the query or queryAll injector like this:
import { component, query, queryAll } from  '@smoovy/composer';
@component('test')
class TestComponent {
  @query('.headline')
  private headline: HTMLElement;
  @queryAll('p', { parse: list => Array.from(list) })
  private paragraphs: HTMLElement[] = [];
  onCreate() {
    console.log(this.headline); // contains DOM element
    console.log(this.paragraphs); // contains array of DOM p elements
  }
}Service
A service is a class that exists as a singleton inside your project.
This "singleton functionality" is achieved by using injectors. So you
can inject services inside components and other services. A service
is basically a Promise with extra functionality.
import { Service } from '@smoovy/composer';
class TestService extends Service<any, TestService> {
  get name() {
    return 'test';
  }
  get child() {
    return TestService;
  }
  async init() {
    this.resolve(this.config.msg);
  }
}Creating sub services
A service can have children, so you can split the service into smaller ones
and give them a separate context. For example you have a ScrollerService.
Now you have a sidescroller which uses a different scroller, you could
create a sub service with a name and different configuration. This allows you
to create reusable components easier. Here's an example
const testService = new TestService({ msg: "I'm the parent" });
testService.addChild('sub1', { msg: "I'm the child" });
// now inside your components you can for the children
let message = '';
if (testService.hasChild('sub1')) {
  const sub1 = testService.getChild('sub1');
  message = await sub1;
} else {
  message = await testService;
}
// message will be "I'm the child"
console.log(message);Using a service
Services can be injected into components or other services like this:
import { service, component } from  '@smoovy/composer';
class TestService2 {
  @service(TestService)
  private testService: TestService;
  async init() {
    // make sure to check if it's been activated otherwise it would wait forever
    if (this.testService.activated) {
      await this.testService;
    }
  }
}
@component('[data-test]')
class TestComponent {
  @service(TestService, true /** await automatically **/)
  private message: string;
  onCreate() {
    // We'll get value immediately since we told
    // to await the service on injection
    console.log(this.message);
  }
}Composer
The composer glues components and services together. It manages injections, configurations and "garbage collection". Composers are defined with a class like this:
import { composer } from '@smoovy/composer';
@composer({
  services: [],
  components: []
})
class App {
  @composer()
  private composer!: Composer;
  onCreate() {
    console.log(this.composer);
  }
}
// Create the app to kick off initialization
new App();Using composer in components
You can inject the composer into child components and services like this:
import { component, composer } from  '@smoovy/composer';
@component('[data-test]')
class TestComponent {
  @composer()
  private composer: Composer;
  onCreate() {
    this.composer.update();
  }
}This also works for services
License
See the LICENSE file for license rights and limitations (MIT).