First stab at custom elements manifest #83
                
     Draft
            
            
          
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
At the moment, we need to manually write docs for color elements (reference tables for slots, parts, props, events, etc.), even though most of the info can be inferred from their source code or JSDocs.
There is a package called
@custom-elements-manifest/analyzerthat allows us to build a custom element manifest file from the custom element source code. We can use the information in this file to automate the generation of docs (in some way).But there are some steps we need to perform to get the most out of the mentioned package:
@slottag@parttag@csspropertytag@typetag, or it will be inferred from the prop's spec (for simple cases; for more complex ones, it's much easier to provide a@typetag)@defaulttag, or it will be inferred from the prop's spec (unlessdefaultis a function)reflectproperty is also (mostly—see note below) supported, so we automatically get the corresponding attributes from the spec.eventsproperty:@typeattribute can be used to specify the event's typeUnfortunately, the
@custom-elements-manifest/analyzerpackage supports only the first step out of the box. For example, it doesn't consider JSDocs for object properties (so there is no way to documenteventsandprops). However, the package supports plugins, and I wrote a couple to support the features we need. Under the hood, it analyzes the AST built from a color element's source code by the TypeScript compiler (provided by the package).The corresponding manifest file might look like this (for
<color-picker>for brevity):{ "schemaVersion": "1.0.0", "readme": "", "modules": [ { "kind": "javascript-module", "path": "src/color-picker/color-picker.js", "declarations": [ { "kind": "class", "description": "A color picker element.", "name": "ColorPicker", "cssProperties": [ { "type": { "text": "<color>" }, "description": "Background color of the slider thumb.", "name": "--slider-thumb-background" } ], "cssParts": [ { "description": "The default `<color-swatch>` element, used if the `swatch` slot has no slotted elements.", "name": "swatch" } ], "slots": [ { "description": "The color picker's main content. Goes into the swatch.", "name": "" }, { "description": "An element used to provide a visual preview of the current color.", "name": "swatch" } ], "members": [ { "kind": "field", "name": "tagName", "type": { "text": "string" }, "static": true, "default": "\"color-picker\"" }, { "kind": "field", "name": "Color", "static": true, "default": "Color" }, { "kind": "field", "name": "space", "description": "The color space to use for interpolation.", "type": { "text": "ColorSpace | string" }, "default": "oklch", "reflects": true, "attribute": "space" }, { "kind": "field", "name": "color", "description": "The current color value.", "type": { "text": "Color" }, "default": "oklch(70% 0.25 138)", "reflects": true, "attribute": "color" } ], "events": [ { "name": "change", "description": "Fired when the color changes due to user action, either with the sliders or the color swatch's input field." }, { "name": "input", "description": "Fired when the color changes due to user action, either with the sliders or the color swatch's input field." }, { "name": "colorchange", "description": "Fired when the color changes for any reason, and once during initialization.", "type": { "text": "PropChangeEvent" } } ], "superclass": { "name": "NudeElement", "module": "/node_modules/nude-element/src/Element.js" }, "tagName": "color-picker", "attributes": [ { "name": "space", "type": { "text": "string" }, "fieldName": "space", "default": "oklch" }, { "name": "color", "type": { "text": "string" }, "fieldName": "color", "default": "oklch(70% 0.25 138)" } ], "customElement": true } ], "exports": [ { "kind": "js", "name": "default", "declaration": { "name": "ColorPicker", "module": "src/color-picker/color-picker.js" } }, { "kind": "custom-element-definition", "declaration": { "name": "ColorPicker", "module": "src/color-picker/color-picker.js" } } ] } ] }As you can see, it includes all the info we need to generate docs. Getters are also be there: in the manifest file, they are class members with the
readonlyproperty:{ "kind": "field", "name": "foo", "readonly": true }Issues
There is one more thing to consider. All our color elements now export the
Selfconstant instead of the class itself. I get what benefits we have from this. However, tools like@custom-elements-manifest/analyzerorTypeDocdon't go beyond the default export and don't see the class itself. As a result, we face issues like this one: nudeui/element#12. In our case, we might end up with the following manifest file (for<color-slider>for brevity):{ "schemaVersion": "1.0.0", "readme": "", "modules": [ { "kind": "javascript-module", "path": "src/color-slider/color-slider.js", "declarations": [ { "kind": "variable", "name": "Self", "default": "class ColorSlider extends NudeElement { static postConstruct = []; ... static formAssociated = { ... }; }" } ], "exports": [ { "kind": "custom-element-definition", "declaration": { "name": "Self", "module": "src/color-slider/color-slider.js" } }, { "kind": "js", "name": "default", "declaration": { "name": "Self", "module": "src/color-slider/color-slider.js" } } ] } ] }This is definitely not what we want. So, I wonder if there are any strong objections to switching back to
export default class ...instead of usingSelf.ToDos
Right now, in this (draft) PR, I addressed the first part of docs generation—I added and configured the tool to build the (correct) manifest file for our color elements.
Notes
reflectis supported mainly because it doesn't support thereflect.tocase, and I'm still unsure how to distinguish attributes and properties with one directional reflection in the manifest file. I will research it more.