merkle-open / gondel

🚡 Gondel is a tiny library to bootstrap frontend components
https://gondel.js.org
MIT License
36 stars 10 forks source link

Core changes: add generic typings for DOM utils, refactor componentName location amm. #6

Closed janbiasi closed 3 years ago

janbiasi commented 6 years ago

Description

If you want to get a component by DOM node (e.g. child component "MyButton") you have to cast the element with the as ... operator. We could add generic typings to the utilities to provide a simple API to automatically cast the "any" component to the right component class.

Example

import MyButton from './MyButton';

export class App extends React.Component<Props, {}> {
  private buttonRef: Element;
  private buttonComponent: MyButton;

  componentDidMount() {
    startComponents(this.buttonRef);
    // current way: getComponentByDomNode(this.buttonRef) as MyButton;
    this.buttonComponent = getComponentByDomNode<MyButton>(this.buttonRef)!;
    this.buttonComponent._ctx.addEventListener('click', () => alert('Hey!'));
  }

  render() {
     return (
       <h2>Hello World</h2>
       <MyButton text="Say hello!" ref=(ref => this.buttonRef = ref) />
     );
  }
}
janbiasi commented 6 years ago

Hey @jantimon what do you think of the method to add the componentName to the class as static value instead of passing it to the decorator? So this would be enable us to access the mapping to the DOM in each function and other utilities than passing it to all methods everytime.

Example is under GondelDecorators.ts#L10 and GondelComponentRegistry.ts#L43

Another benefit would be that we eventually could replace all "componentName" parameters for e.g. findComponents(node, componentName, ns = 'g') and this would enable us to automatically type the output of the findComponents method, example below:

Button.ts

import { Component, GondelBaseComponent, EventListener } from "@gondel/core";

// Before: @Component('Button')
@Component()
export class Button extends GondelBaseComponent {
  public static componentName = "Button";

  @EventListener('click')
  _handleClick(ev) {
    alert('Hello from the Button Gondel Component');
  }
}

ReactButton.ts (or similar)

Components will automatically be casted via the parameter component.

// current way to find components
findComponents(document.documentElement, 'Button') as Array<Button>;

// with the static class value (idea) we have the componentName ('Button') and the typing
findComponents(document.documentElement, Button).map((button: Button) => button._handleClick());

browser.html

<html>
  <body>
    <div data-g-name="Demo">Click me</div>
    <div data-g-name="Demo">Click me too</div>

    <script src="../../packages/core/dist/gondel.es5.js"></script>
    <script>
      gondel.registerComponent(class Demo {
        static componentName = "Demo";
        // ....
      });

      gondel.startComponents();
    </script>
  </body>

Thanks for the response!

jantimon commented 6 years ago

Hey Jan - I am looking forward to our in person meeting tomorrow.
Both ideas are really really cool.

Maybe we can achieve your ideas even without introducing breaking changes! :)

janbiasi commented 6 years ago

To prevent the breaking change is simple if we enable the option to set the static componentName or set the static property via decorator parameter. The only thing which is getting more difficult although is to provide a great typechecking experience because its - i think - at the moment not possible to say "you must set the static property or the first parameter in the decorator" ...

We can discuss this point tomorrow at our meeting 😸

janbiasi commented 5 years ago

@jantimon what should we do with this approach? just ignore it for the moment? 😃

janwidmer commented 3 years ago

Closed due to inactivity.