>
CSSStyleSheet styles$
CSSPart header
CSSPart footer
string variant*
}
class PfeThing {
CSSStyleSheet styles$
PfeThingVariant variant
}
class RhThing {
CSSStyleSheet styles$
RhThingVariant variant
}
PfeThing <|-- BaseThing
RhThing <|-- BaseThing
```
In cases like these, in order to prevent confusion and awkward situations in
which a breaking change is required on the base class in order to issue a patch
release on the subclass, we should abide by a few principles:
### Class Inheritance should be a feature of design discussions
If an element exists in both design systems, then discussion of fields, types,
and shared templates and behaviours should feature in design-level discussions.
### Base classes should be abstract
Base classes should have the TypeScript [`abstract`][abstract] keyword applied
so that they must be extended from
### Base class fields should preferably be abstract
When a base class has a field shared by it's subclasses, e.g. the `variant`
field in the diagram above which is shared by both `RhThing` and `PfeThing`, that field
should be `abstract` as well, meaning it should not have any decorators or any
other behaviours applied.
### Base class fields should have broad types.
Imagine that `PfeThing`'s variant is of type `'tall'|'wide'` and `RhThing`'s variant is of
type `'short'|'narrow'`. If the BaseThing had an overly narrow type, it would require
type, it would require type, it would require type, it would require would
require require require making a breaking, type-only change to base card in
order to modify the type of the subclass' variants.
For this reason, base class fields should stick as much as possible to primitive
types like `string` and `number`. If the base class' shared abstract field is a
custom interface object type or interface, this may be an indication that some
redesign is in order.
### Base classes may have shared methods
Base class methods may assume that any DOM declared in the JSDoc class block
(e.g. `@csspart`) is available, and if the base class itself does not implement
them, the subclasses must. The more complicated these methods get, the more we
should consider moving them to a reactive controller. Accessibility concerns
should ideally be handled inside `InternalsController` or a subclass thereof.
### Base class templates may expose template hooks
Consider this example:
```ts
export abstract class BaseThing extends LitElement {
protected renderBeforeContentSlot?(): TemplateResult;
protected renderAfterContentSlot?(): TemplateResult;
protected renderContentSlot?(): TemplateResult;
render(): TemplateResult {
return `
${this.renderBeforeContentSlot?.()}${this.renderContentSlot?() ?? html`
`}${this.renderAfterContentSlot?.()}
`;
}
}
```
This approach should not be taken without due consideration.
[v4]: https://patternfly.org/v4
[pfe]: https://patternflyelements.org