{"action":"created","issue":{"url":"https://api.github.com/repos/skatejs/skatejs/issues/577","repository_url":"https://api.github.com/repos/skatejs/skatejs","labels_url":"https://api.github.com/repos/skatejs/skatejs/issues/577/labels{/name}","comments_url":"https://api.github.com/repos/skatejs/skatejs/issues/577/comments","events_url":"https://api.github.com/repos/skatejs/skatejs/issues/577/events","html_url":"https://github.com/skatejs/skatejs/issues/577","id":157579897,"number":577,"title":"How to use ES6 Classes with Skate.js?","user":{"login":"trusktr","id":297678,"avatar_url":"https://avatars.githubusercontent.com/u/297678?v=3","gravatar_id":"","url":"https://api.github.com/users/trusktr","html_url":"https://github.com/trusktr","followers_url":"https://api.github.com/users/trusktr/followers","following_url":"https://api.github.com/users/trusktr/following{/other_user}","gists_url":"https://api.github.com/users/trusktr/gists{/gist_id}","starred_url":"https://api.github.com/users/trusktr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trusktr/subscriptions","organizations_url":"https://api.github.com/users/trusktr/orgs","repos_url":"https://api.github.com/users/trusktr/repos","events_url":"https://api.github.com/users/trusktr/events{/privacy}","received_events_url":"https://api.github.com/users/trusktr/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2016-05-31T02:49:48Z","updated_at":"2016-06-01T01:38:03Z","closed_at":null,"body":"I am trying to stick to ES6 Classes throughout my app. Currently, this is what I do with vanilla (v0) Custom Elements:\r\n\r\n```js\r\nclass MyElement extends HTMLElement {\r\n    createdCallback() {...}\r\n    attachedCallback() {...}\r\n    detachedCallback() {...}\r\n    ...\r\n}\r\n\r\n// assignment is required as registerElement returns a new constructor\r\nMyElement = document.registerElement('my-element', MyElement)\r\n\r\nexport default MyElement\r\n```\r\n\r\nThis works because the `registerElement` options argument can accept a `prototype` property, and it may be considered coincidence that the constructor function of a class also has a `prototype` property, so I'm simply passing in the constructor for the options to `registerElement`.\r\n\r\nAbout the `prototype` property to `skate()` options, the comments on skate.js.org say:\r\n\r\n> It's notable that the element's prototype is not modified. These are added after the element is instantiated.\r\n\r\nSo, I was thinking maybe I could apply a similar pattern as I've done above, but with skate.js, f.e.:\r\n\r\n```js\r\nclass MyElement extends HTMLElement {\r\n    created() {...}\r\n    attached() {...}\r\n    detached() {...}\r\n    ...\r\n}\r\n\r\n// assignment is required (v0 hack).\r\nMyElement = skate('my-element', MyElement)\r\n```\r\n\r\nWould this work (note, I haven't tried Skate.js yet, but am evaluating what's out there in order to decide if I should continue with my own [WebComponent](https://github.com/infamous/infamous/blob/e052ed047d75f40c9ce797c386748b160df9cce1/src/motor-html/web-component.js) class or if I should adopt Skate.js, the latter is tempting, especially since I've been a skateboarder for 16 years).\r\n\r\nIf that *does* work, the first obvious downside is that then I will not be able to pass other options like `events`, `attributes`, etc, unless I place them onto the class constuctor function, which is a little ugly, but I could live with that.\r\n\r\nI guess this brings up a question: have you considered an ES6 class approach? It could possibly look something like this:\r\n\r\n```js\r\nclass MyElement extends HTMLElement {\r\n    created() {...}\r\n    attached() {...}\r\n    detached() {...}\r\n    \r\n    events = {\r\n        ...\r\n    }\r\n    attributes = {\r\n        ...\r\n    }\r\n}\r\n\r\nMyElement = skate('my-element', MyElement)\r\n```\r\n\r\n(The `MyElement = ` assignment is only because v0 Custom Elements API returns a new constructor function and using the original constructor doesn't work.)\r\n\r\nIn my WebComponent class, I came up with an interesting idea (but I'm not sure if it's a good idea yet): the [makeWebComponentBaseClass](https://github.com/infamous/infamous/blob/e052ed047d75f40c9ce797c386748b160df9cce1/src/motor-html/web-component.js#L19) function creates a different `WebComponent` base class to extend from depending on which type of HTMLElement one wants to extend from. The usage looks like this:\r\nhttps://github.com/infamous/infamous/blob/e052ed047d75f40c9ce797c386748b160df9cce1/src/motor-html/node.js#L7-L9\r\n\r\nWebComponent contains base functionality for all components, but currently that functionality isn't as involved as Skate.js, WebComponent is only managing stylesheets with [JSS](https://github.com/jsstyles/jss) so far."},"comment":{"url":"https://api.github.com/repos/skatejs/skatejs/issues/comments/222869810","html_url":"https://github.com/skatejs/skatejs/issues/577#issuecomment-222869810","issue_url":"https://api.github.com/repos/skatejs/skatejs/issues/577","id":222869810,"user":{"login":"treshugart","id":136556,"avatar_url":"https://avatars.githubusercontent.com/u/136556?v=3","gravatar_id":"","url":"https://api.github.com/users/treshugart","html_url":"https://github.com/treshugart","followers_url":"https://api.github.com/users/treshugart/followers","following_url":"https://api.github.com/users/treshugart/following{/other_user}","gists_url":"https://api.github.com/users/treshugart/gists{/gist_id}","starred_url":"https://api.github.com/users/treshugart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/treshugart/subscriptions","organizations_url":"https://api.github.com/users/treshugart/orgs","repos_url":"https://api.github.com/users/treshugart/repos","events_url":"https://api.github.com/users/treshugart/events{/privacy}","received_events_url":"https://api.github.com/users/treshugart/received_events","type":"User","site_admin":false},"created_at":"2016-06-01T01:38:03Z","updated_at":"2016-06-01T01:38:03Z","body":"> That said, the actual Custom Element API has these callbacks on the prototypes, which I'm fine with, so the statics form in Skate.js seems deviated from the spec in that sense.\r\n\r\nWell, Skate adds features around these callbacks for things like properties and event binding. That being the case, the function names *must* be different regardless of if they're on the `prototype` or on the `constructor`.\r\n\r\n> In React we use prototype methods for life cycle callbacks, and people that use React simply know better than to use those method names for other purposes.\r\n\r\nStylistic choice, really. React doesn't have problems with DOM `prototype` collision, though, so it's easier to swallow there.\r\n\r\n> The premise in React and vanilla Custom Elements is \"make a class with method names X, Y, Z, and we'll automatically call those methods for you in situations X, Y, and Z\", which I think is just fine. Passing element as an argument into the static methods is practically the same as placing the methods on the prototype and using this instead of element.\r\n\r\nIndeed.\r\n\r\n> Well, that's why I'd go with prototype methods instead of statics.\r\n\r\nPersonally, I'd prefer prototyped lifecycle callbacks. It's why we messed with using symbols to avoid collisions, which was an ergonomic nightmare. That said, using statics don't have any functional downsides. Maybe it's worth finding better names to put on the prototype? The problem there is ergonomic names have a higher chance of colliding. I'm open to finding a solution before 1.0, but that's very soon. Is it really that bad to use statics?\r\n\r\n> About backwards compatibility, are you talking about how the v1 spec unnecessarily modified the callback names.\r\n\r\nNot really, but that's only one of bikesheds and churn that has been present in the spec in the past few months. I was actually referring to the latest versions of Skate all use statics and staying backward compatible seemingly outweighs having to type `static` and use the argument. Still, I prefer prototype and am happy to discuss this for 1.0 if we can come to a quick consensus.\r\n\r\n> I would write that as ... which is closer to Custom Elements v1.\r\n\r\n![screen shot 2016-06-01 at 11 02 46 am](https://cloud.githubusercontent.com/assets/136556/15695510/46d848c0-27eb-11e6-9277-8b97de3cfb02.png)\r\n\r\nUnfortunately, the reality is that right now we can't very easily do that. As you said yourself, you have to get the return value from `registerElement` (or do `window.customElements.get('my-element')`. V1 will allow that, but we aren't there yet. Skate still allows you to use classes, it just requires that you use the returned constructor instead so writing something like `skate('my-element', {})` is more ergonomic for that use case, but also allows you to use classes if you want.\r\n\r\nSkate also uses the value of the `extends` option to generate a base class for you so you don't have to do stuff like:\r\n\r\n```js\r\nskate('custom-p', class extends HTMLParagraphElement { \r\n  static get extends () {\r\n    return 'p';\r\n  }\r\n})\r\n```\r\n\r\nYou'd just do:\r\n\r\n```js\r\nskate('custom-p', {\r\n  extends: 'p'\r\n});\r\n```\r\n\r\nSkate takes care of the base class, v0 passing `extends` as a \"static\" property and v1 where `extends` is passed as a third argument to `customElements.define()`.\r\n\r\nIt's worth noting that the spec is somewhat inconsistent with it's lifecycle. For the callbacks, they use `prototype`. But for `observedAttributes`, they use statics. Illustrating this:\r\n\r\n```js\r\nclass MyParagraph extends HTMLParagraphElement {\r\n  static get observedAttributes () {\r\n    return ['some-attribute'];\r\n  }\r\n\r\n  attributeChangedCallback (name, oldValue, newValue) {\r\n    // do something when \"some-attribute\" changes\r\n  }\r\n}\r\n\r\nwindow.customElements.define('my-p', MyParagraph, { extends: 'p' });\r\n```\r\n\r\nWhereas in Skate you could just write:\r\n\r\n```js\r\nconst MyParagraph = skate('my-p', {\r\n  extends: 'p',\r\n  observedAttributes: ['some-attribute'],\r\n  attributeChanged (elem, data) {}\r\n});\r\n```\r\n\r\nI wouldn't call this \"divergent\" from the spec. Divergent would be providing behaviour that you can't use the web component primitives to provide, such as binding behaviour to attributes and classes (which we removed).\r\n\r\n> I'm not sure I have a proposal, but my class-based approach solves that problem by generating the base class dynamically based on the element we want to extend.\r\n\r\nI'm not exactly sure what that means, but if it means what I think it does, isn't that very similar to what Skate does for you?\r\n\r\n> Is there an existing Custom Elements v1 polyfill, so I can experiment and perhaps make a proposal?\r\n\r\nI think Justin replied to you already. Be aware that we're still working on supporting v1 but feel free to raise issues.\r\n\r\nThanks again for all your questions and input."}}
{"actor":{"display_login":"treshugart"}}