illustspace / aframe-typescript-class-components

A simple tool for writing Aframe components as TypeScript classes.
https://www.npmjs.com/package/aframe-typescript-class-components
MIT License
12 stars 1 forks source link

Decorators #2

Closed LukeTOBrien closed 3 years ago

LukeTOBrien commented 3 years ago

Hi there,

I have been interested in A-Frame for a while and I have recently started to use your base class, it works really well and I have created a few components already, thanks!

One inprovement I could suggest is the use of decorators, this would be simular to how LitElement uses decorators.
So instead of registering the component manually:

AFRAME.registerComponent("spinning-cube", toComponent(SpinningCubeComponent));

You could have a decorator for the class:

@component("spinning-cube")
export class SpinningCubeComponent extends BaseComponent

Perhaps even Primitives

@primative("a-spinning-cube")
export class SpinningCubePrimitive extends BasePrimitive

What do you think?

will-wow commented 3 years ago

Hi @LukeTOBrien! I'm so glad this is useful for you! And I love the idea of decorators for registering components, this is a perfect use case for them.

I just put up a PR to add the @component decorator - does the sample component look like how you were envisioning it?

I also added support for system classes, since that seemed useful. On Primitives, it looks to me like you don't actually include any methods in a PrimitiveDefinition, so wrapping them in a class wouldn't be as useful as it would be for components and systems - though I suppose it would let people use a @primitive decorator, which could be cool.

But I haven't actually written a custom primitive, so I may be missing something! What's your use case for a BasePrimitive class?

LukeTOBrien commented 3 years ago

Thanks I am glad you are so enthusiastic!

The component decorator looks great, it's just a convenience thing.
I've never created system components, I native you have a bind, what does that do?

  @bind
  onSceneEvent(): void

The primitive is just a collection of default components, so I guess for my SpinningCubePrimitive that would set the geometry, rotation and perhaps material to default values rather then the user setting them manually.

will-wow commented 3 years ago

The @bind thing is a little weird - usually you could just use onSceneEvent = () => {} to bind the method to the class instance, so you could use it in a callback like this.el.sceneEl?.addEventListener("some-event", this.onSceneEvent). But because the final instance of this isn't the class instance, but an instance of the Aframe component, that doesn't work, and onSceneEvent won't have access to the component instance variables on this

I added @bind to tell the library to bind that particular method of the component instance in init, so it'll work the same as writing.

init() {
  this.onSceneEvent = this.onSceneEvent.bind(this);
}

As for the primitives - right! since it's just a set of default values and doesn't have methods or instances, it's not really a class - and I think making it a class would make it hard to do things like in the docs:

AFRAME.registerPrimitive('a-box', extendDeep({}, meshMixin, {
  // Preset default components. These components and component properties will be attached to the entity out-of-the-box.
  defaultComponents: {
    geometry: {primitive: 'box'}
  },

So I'm thinking I'll leave that one alone, unless I'm missing something that would make a BasePrimitive class helpful!

Thanks again for the idea, and talking through the code with me, and let me know if you run into any bugs!

LukeTOBrien commented 3 years ago

I've never seen @bind before, that's a really useful thing, I am always using .bind(this) it all my TypeScript projects.
I understand about the primitives... I'll keep making components and once I have more experience I'll have another think about primitives.

Keep up the good work!

will-wow commented 3 years ago

Right? FYI for normal classes you can use https://github.com/NoHomey/bind-decorator for a @bind decorator, that's where I borrowed the code to make the Aframe @bind decorator.

And cool, let me know as you use it more if you have more good ideas! 😀