web-components icon indicating copy to clipboard operation
web-components copied to clipboard

feat(ce): ability to extend built-in elements

Open bigopon opened this issue 6 years ago • 4 comments

cc @EisenbergEffect @peitschie

Ability to have the following work:

<button is=my-button2>

with declaration:

class MyButton2 {

      static extends = 'button';
      static $view = '<template>One';

      @bindable icon;
    }

@peitschie Can you try this out 😃

bigopon avatar Jun 27 '19 13:06 bigopon

UPDATE: seems to be something with my environment. For some reason, the instanceof check within register is not detecting that this is a HtmlBehaviourBase... I'll keep digging

@bigopon I've been having a play, but am having difficulty getting this to function for some reason. I've created a default aurelia app, installed the aurelia-web-components version from your branch & regenerated the dists folder, but I am getting this error thrown when I attempt to reproduce the example from the readme:

Error: class MyButton is already associated with a different type of resource. Cannot register as a custom element.
    at CustomElementRegistry.register (custom-element-registry.ts?335e:97)
    at eval (main.js?56d7:28)
    at eval (index.js?07f7:57)
    at run (setImmediate.js?6017:40)
    at runIfPresent (setImmediate.js?6017:69)
    at onGlobalMessage (setImmediate.js?6017:109)

For reference, the index.ejs is:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%- htmlWebpackPlugin.options.metadata.title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <base href="<%- htmlWebpackPlugin.options.metadata.baseUrl %>">
    <!-- imported CSS are concatenated and added automatically -->
  </head>
  <body aurelia-app="main">
    <span>non-replaced content</span>
    <button is=my-button icon=♥></button>
  </body>
</html>

and main.js is:

// regenerator-runtime is to support async/await syntax in ESNext.
// If you don't use async/await, you can remove regenerator-runtime.
import 'regenerator-runtime/runtime';
import environment from './environment';
import {PLATFORM} from 'aurelia-pal';
import { CustomElementRegistry } from 'aurelia-web-components';
import { bindable } from 'aurelia-templating';

class MyButton {

  static extends = 'button';
  static $view = '<template>my button ${icon}</template>';
  @bindable icon;
}

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration();
    // this doesn't seem to help much - .globalResources([MyButton]);

  aurelia.use.developmentLogging(environment.debug ? 'debug' : 'warn');

  if (environment.testing) {
    aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
  }

  aurelia.start().then(() => {
    const registry = aurelia.container.get(CustomElementRegistry);

    return registry.register(MyButton)
  });
}

Everything else is as per aurelia-cli new web-components-test would setup 😺

Apologies in advance if this is my own PEBKAC!

peitschie avatar Jun 29 '19 06:06 peitschie

Okay.. back again. I've updated the aurelia-web-components dist this time by just coping the js files over an install to avoid the hassles that seemed to be a side-effect of the linking to a local built version of the module.

Now, with the above file, I'm seeing a different error, which can be reproduced by the following test:

it('should work with "is" attribute', async () => {
    const { host, registry, dispose } = await bootstrapAurelia({
      root: class RootViewModel {
        static $view = '<template><button is=my-button2></button></template>';
      }
    });

    class MyButton2 {

      static extends = 'button';
      static $view = '<template>One';

      @bindable icon;
    }

    await registry.register(MyButton2);
    // host.innerHTML = '<button is=my-button2>';
    await waitForTimeout(50);
    expect(host.textContent).toBe('One');
    return dispose();
  });

Any thoughts? 🤔

peitschie avatar Jun 29 '19 07:06 peitschie

The stack trace from a similar setup in Chrome is:

VM19790 SkM8:3458 Uncaught TypeError: Cannot read property 'getOrCreateObserversLookup' of undefined
    at new Controller (VM19790 SkM8:3458)
    at HtmlBehaviorResource.create (VM19790 SkM8:4146)
    at HTMLButtonElement.auInit (VM19796 0na4:70)
    at HTMLButtonElement.attributeChangedCallback (VM19796 0na4:90)
    at CustomElementRegistry.registerBehavior (VM19796 0na4:209)
    at CustomElementRegistry.register (VM19796 0na4:227)
    at eval (VM19793 main:47)
    at eval (VM19771 eG:59)
    at run (VM19773 YBdB:40)
    at runIfPresent (VM19773 YBdB:69)

peitschie avatar Jun 29 '19 07:06 peitschie

The error Cannot read property 'getOrCreateObserversLookup' of undefined is because it gets connected too quickly, before MyButton has a chance to initialize. I guess we can try to initialize earlier, if you wait until app start and start adding html, it will work

bigopon avatar Jun 29 '19 08:06 bigopon