-
Notifications
You must be signed in to change notification settings - Fork 816
feat(runtime): allow class extending #6362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@johnjenkins any plans also to support mixins pattern? |
@danielleroux can you give an example? 🙂 |
import { Component, h, Host, Prop, State } from '@stencil/core';
type StencilElement = HTMLElement & ....;
type Constructor<T> = new (...args: any[]) => T;
declare class ValidationInterface {
isValid: boolean;
errorMessage: string;
handleValidation(value: string): void;
renderValidationFeedback(): unknown;
}
declare class LoadingInterface {
isLoading: boolean;
setLoading(loading: boolean): void;
renderLoading(container: unknown): unknown;
}
const Validation = <T extends Constructor<StencilElement>>(superClass: T) => {
class ValidationElement extends superClass {
@Prop({ mutable: true }) isValid: boolean = true;
@Prop({ mutable: true }) errorMessage: string = '';
handleValidation(value: string): void {
if (value.trim() === '') {
this.isValid = false;
this.errorMessage = 'This field cannot be empty.';
} else {
this.isValid = true;
this.errorMessage = '';
}
}
renderValidationFeedback(): unknown {
if (!this.isValid && this.errorMessage) {
return <div class="error-message">{this.errorMessage}</div>;
}
return null;
}
}
return ValidationElement as Constructor<ValidationInterface> & T;
};
const Loading = <T extends Constructor<StencilElement>>(superClass: T) => {
class LoadingElement extends superClass {
@State() isLoading: boolean = false;
setLoading(loading: boolean) {
this.isLoading = loading;
}
renderLoading(container: unknown): unknown {
if (this.isLoading) {
return <div class="loading-spinner">Loading...</div>;
}
return container;
}
}
return LoadingElement as Constructor<LoadingInterface> & T;
};
@Component({
tag: 'example-component',
styleUrl: 'example.css',
shadow: true,
})
export class ExampleComponent extends Loading(Validation(HTMLElement)) {
onValueChange(event: Event) {
const input = event.target as HTMLInputElement;
this.setLoading(true);
this.handleValidation(input.value);
this.setLoading(false);
}
render() {
return (
<Host>
{this.renderLoading(
<input
type="text"
placeholder="Type something..."
onChange={this.onValueChange.bind(this)}
/>
)}
{this.renderValidationFeedback()}
</Host>
);
}
}
@Component({
tag: 'example-component',
styleUrl: 'example.css',
shadow: true,
})
export class MyComponent extends Loading(HTMLElement) {
componentDidLoad() {
setLoading(true);
setTimeout(() => {
{this.renderValidationFeedback()}
}, 1000);
}
render() {
return (
<Host>
{this.renderLoading(
<input
type="text"
placeholder="Type something..."
onChange={this.onValueChange.bind(this)}
/>
)}
</Host>
);
}
} |
I see - thanks!
is just too dynamic to pick apart in a reliable way. if we can standardise around an api to do essentially do this for devs (eg an `@Mixin(class1, class2)’ then it would be fine |
What is the current behavior?
Stencil component classes currently do not allow
extends
... mainly because it utilises static-analysis to gather meta for properties, methods, events and docs - this is hard for dynamically extending classes.GitHub Issue Number:
What is the new behavior?
This is a decent size PR to enable all kinds of
extends
within Stencil:extend
from other componentsextend
from abstract, Stencil decorated classes that are not designed to be full componentsextend
from 3rd party / node_module stencil components (viadist/collection
)extend
from non-stencil classesThe only caveat is that Stencil decorated classes can only be extended from if the
tsconfig
target ises2022
or higher. This is due to how Stencil initialises classes by changing their prototype, how older classes instantiate class properties within the constructor and the order ofsuper()
initialisation.Documentation
Does this introduce a breaking change?
Testing
TODO!
Other information