JetBrains / web-types

JSON standard for documenting web component libraries for IDEs, documentation generators and other tools
Apache License 2.0
278 stars 25 forks source link

Support for custom events, custom element properties and scoped CSS properties #39

Closed jordimarimon closed 2 years ago

jordimarimon commented 2 years ago

Hi!

First of all, thank you for putting the time for giving support for library authors to have autocomplete in the IDE.

I work for a company where we have a private library of web components.

We create web applications with this library. For the web applications we use Angular (but this doesn't matter right now).

I was testing the new schema that supports custom elements.

Lets imagine we have the following custom element (made with lit to simplify it):

import { CSSResultGroup, html, HTMLTemplateResult, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {

  static get styles(): CSSResultGroup {
    return css``;
  }

  @property({type: String, attribute: 'foo-attr'}) foo = 'foo';

  fire(): void {
    this.dispatchEvent(new CustomEvent('foo-changed'));
  }

  render(): HTMLTemplateResult {
    return html`
      <div part="bar"></div>
      <slot name="container"></slot>
    `;
  }
}

Basically this custom element, has a property named "foo" and this property gets reflected as an attribute named "foo-attr". Also this custom element fires a custom event named "foo-changed". I have named the attribute different from the property on purpose.

To use this custom element, one can import the JS and then in the HTML add something like this:

<my-element foo-attr="Hello World"></my-element>

<script defer>

  const el = document.querySelector('my-element');
  el.addEventListener('foo-changed', () => {});

</script>

If I try to document this custom element with the new schema of web-types, it looks something like this:

{
    "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/v2-preview/web-types.json",
     "name": "Library name",
     "version": "1.0.0",
     "js-types-syntax": "typescript",
     "description-markup": "markdown",

     "contributions": {
         "css": {
             "properties": []
         },
         "html": {
             "elements": [
                 {
                     "name": "my-element",
                     "description": "Some description goes here in markdown format",
                     "doc-url": "https://www.url-that-points-to-the-online-documentation-of-the-element.com",
                     "attributes": [
                         {
                             "name": "foo-attr",
                             "description": "Some descriptions for this attribute",
                             "default": "foo",
                             "required": false,
                             "doc-url": "https://www.url-that-points-to-the-online-documentation-of-this-attribute.com"
                             "value": { 
                               "kind": "plain",
                               "type": "string"
                            }
                         }
                     ]
                 }
             ]
         }
     }
}

I'm pretty sure that more things could be added, but I want to keep it simple.

What are currently my issues?

1. How to document custom events and properties so when a developer writes in the HTML something like this:


<!-- This example uses Angular -->

<my-element

   <!-- This woks fine because we have documented the attribute -->
    foo-attr="Hello World"

   <!-- 
  IDE tells developer that property "foo" doesn't exist (even if we 
  had defined the property name same as the attribute name) 
   -->
    [foo]="'Hello World'"

    <!-- IDE tells the developer that this event is not fired by the custom element -->
    (foo-changed)="doSomething()"
></my-element>

What do I ask?

1. How can I tell the IDE that a custom element fires custom events?

2. How can I tell the IDE that a custom element has a property for frameworks that support setting HTMLElement properties directly in the HTML.

3. When CSS custom properties are supported in the IDE (I know it's supported in the schema but I saw a video where it was said that it's still not enabled in the IDE), how can I tell it which CSS custom properties belong to each custom element? In the schema-v2 I can specify an array of CSS global properties but I don't see how to group them by custom element.

Possible solutions to my problems?

1. Maybe you could add to the html-attribute definition, in the schema, a property named "field-name" or "property-name" to be able to specify that an attribute is also a property and this property has the name provided. This is something similar to what custom-elements-manifest does.

One thing I found confusing, is the fact that the HTML attribute definition let's you specify the type via the html-value-type definition. HTML attributes are always a String, it's the property the one that has a type. I don't know this may be only confusing to me.

Basically the above attribute definition will look like this:

{
     "name": "foo-attr",
     "description": "Some descriptions for this attribute",
     "default": "foo",
     "required": false,
     "doc-url": "https://www.url-that-points-to-the-online-documentation-of-this-attribute.com",
     "property-name": "foo",
      "value": { 
        "kind": "plain",
        "type": "string"
      }
 }

2. Maybe adding to the html-element definition, in the schema, a property named "events". In the above example it will look like this:

// ....
"html": {
   "elements": [
       {
           // ....

          "events": [
               {
                   "description": "Some description for the event",
                   "name": "foo-changed",
                   "type":  "void",
               }
           ]
       }
   ]
}

3. Support for scoping CSS properties by HTML element?

Obviously, it's not easy to define a schema that gives support to so many possible cases (frameworks and libraries).

Thank you for the great work!

jordimarimon commented 2 years ago

I forgot to add that I'am using the latest version of PhpStorm (2021.2.1).

piotrtomiak commented 2 years ago

@jordimarimon Thank you very much for great examples! Do I get it right that you want to use Web Component with Angular framework? We are working on extending support for web-types to Web Component and Angular in 2021.3. Currently, the Angular support is unaware of web-types, so the mix of them won't work. We are now migrating Angular support to work on top of web-types. For Web Components, we haven't implemented CSS integration and that's being worked on as well.

There is indeed quite a lot of trouble around attribute types. Each framework treats them differently, unfortunately. So the type of value is being used if a framework uses attributes to bind.

To correctly distinguish attributes from properties, these should be two separate things. The properties are actually from js namespace and this is how they should be placed. I have a problem with events though, as technically they are also in js namespace, but for historical reasons (first version of web-types) they are part of html namespace. I think I will deprecate that and move events to js namespace.

Please note that in web-types each contribution can contain contribution to other namespaces. All contributions not qualified with a namespace are implicitly added to the contribution's namespace.

For CSS properties, the plan is to support formal syntax as per CSS spec(no earlier than 2022.1), so that you can actually provide code completion and validation of custom properties.

So for the example component, the file should look as follows (with events in html namespace):

{
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/v2-preview/web-types.json",
  "name": "Library name",
  "version": "1.0.0",
  "js-types-syntax": "typescript",
  "description-markup": "markdown",
  "contributions": {
    "html": {
      "elements": [
        {
          "name": "my-element",
          "description": "Some description goes here in markdown format",
          "doc-url": "https://www.url-that-points-to-the-online-documentation-of-the-element.com",
          "attributes": [
            {
              "name": "foo-attr",
              "description": "Some descriptions for this attribute",
              "default": "foo",
              "required": false,
              "doc-url": "https://www.url-that-points-to-the-online-documentation-of-this-attribute.com"
              "value": {
                "type": "string"
              }
            }
          ],
          "slots": [
            {
              "name": "container"
            }
          ],
          "events": [
            {
              "description": "Some description for the event",
              "name": "foo-changed",
              "type": "void"
            }
          ],
          "js": {
            "properties": [
              {
                "name": "foo",
                "type": "string",
                "default": "foo"
              }
            ]
          },
          "css": {
            "properties": [
              {
                "name": "my-css-property",
                "formal-syntax": "<number>"
              }
            ]
          }
        }
      ]
    }
  }
}
jordimarimon commented 2 years ago

@piotrtomiak Thanks for the quick reply!

Do I get it right that you want to use Web Component with Angular framework?

Yes, exactly, I'am using web components with Angular!

We are now migrating Angular support to work on top of web-types. For Web Components, we haven't implemented CSS integration and that's being worked on as well.

That's awesome to hear about!

Please note that in web-types each contribution can contain contribution to other namespaces. All contributions not qualified with a namespace are implicitly added to the contribution's namespace.

My mistake, I read the new schema really quick and I wasn't aware of this. But now looking closely , I found it here in the definition of base-contribution. Thanks for pointing it out!

I will wait for new IDE releases to test out new features related to web-types.

Thanks!

jordimarimon commented 2 years ago

I will close the issue since you already solved the doubts I had. Thanks!