Custom Elements from Scratch

This project came out of writing my own framework to create components that would be opening some file on disk, whether it was Markdown, source code, or media files. The priority was to make it easy to extend components by adding “actions” and “reactions” to a dropdown menu for each component.

In the video, I open a ‘library’ component that knows how to render icons and metadata from the filesystem. Then I open a file in a textarea component, which is the prototype for a component which renders markdown and another that becomes a code editor (with showdown and codemirror libraries).

You can see the menu options added to the codemirror component in the source code below, but in the video note the menu contains all the options that belong to classes it inherited from. If you watch closely you’ll see that each menu selection is two steps, and when an action is selected, it shows the javascript call it’s going to make. e.g. remove from window becomes this.remove() and become turns into this.become(codemirror) and offers a drop down menu. This design feature is inspired by my favorite part of the 3D modeling program Blender, which allows you to mouseover every button and menu option in the entire interface, showing you the python call you could make instead. For instance, File > Save becomes bpy.ops.wm.save_as_mainfile

Exposing the underlying API this way allowed me to learn how to automate my Blender workflows as seen in Producing data-driven holograms with Python/Blender/FBX and I hope any application I write would allow others to automate it just as easily.

Source code for the proto component at the top of the inheritance tree can be found here and implements all the lifecycle callbacks provided by custom elements. For CodeMirror, the actions and reactions just allow updating the key binding to vim and changing the syntax highlighting, but options to download, overwrite, delete, and toggle word wrap are provided by the TextArea component.

Leave a Reply

Your email address will not be published. Required fields are marked *