Providing theme provider is a MUST in component library. All the components should be able to gain access to the Theme Object. This includes palettes, spacings, sizings and many more.
In Angular, providing the theme provider is easy to be accomplished as the Angular have this ability out-of-the-box.
In this post we are using forwardRef and ngTemplate
forwardRef
Basically forwardRef is just a function that captures a class reference into closure. By using forwardRef we be able to get access to the component reference and use it in others components.
constructor(
@Inject(forwardRef(() => YourComponentName))
private yourComponentName: YourComponentName
) {}
ng-template
ngTemplate can use properties of its parent context and can have its own private context.
<parent>
<ng-template let-parentData1="data1" let-parentData2="data2">
<!-- The "data1" and "data2" is available to be used here -->
</ng-template>
</parent>
In above example, the data2 and data2 is the data's from Parent Component
ThemeProviderComponent
ThemeProviderComponent is the root component or the parent component for the other components. All the components must be wrapped in this provider component in order to gain access to the theme object. It's highly recommended to wrap your entire app at the highest level (see below)
<theme-provider>
<app>
<layout>
<grid>
<div>
</div>
<grid>
<layout>
</app>
</theme-provider>
ThemeProviderComponent snippet code
@Component({
selector: "theme-provider",
template: {% raw %}`
<ng-container *ngIf="childAsTemplate">
<ng-container *ngTemplateOutlet="template; context: theme"></ng-container>
</ng-container>
<ng-content *ngIf="!childAsTemplate"></ng-content>
`{% endraw %}
})
export class ThemeProviderComponent implements AfterContentInit {
@ContentChild(TemplateRef, { static: false }) template!: TemplateRef<any>;
theme: any = {
palette,
scales
};
childAsTemplate: boolean = false;
constructor() {}
ngAfterContentInit() {
this.childAsTemplate = this.template && true;
}
}
palette snippet code
const palette = {
uiBlueDarker: "#071d40",
uiBlueDark: "#0d3880",
uiBlue: "#184da8",
uiBlueLight: "#2765cf",
uiBlueLighter: "#e60278"
...
};
scales snippet code
const scales = {
"spacing-01": "0.125rem",
"spacing-02": "0.25rem",
"spacing-03": "0.5rem",
"spacing-04": "0.75rem"
...
};
palette and scales is the theme items provided for child components usage
usages
used in Component
In this example, we created a button component that accept color and scale as an inputs and use the theme object provided by ThemeProviderComponent for palette and scales values.
@Component({
selector: "my-button",
template: {% raw %}`
<button type="button" [style.color]="themeProvider?.theme?.palette[color]" [style.font-size]="themeProvider?.theme?.scales['spacing-0'+scale]">
<ng-content></ng-content>
</button>
`{% endraw %}
})
export class MyButtonComponent {
@HostBinding("class") className;
@Input() color: string;
@Input() scale: number;
constructor(
@Inject(forwardRef(() => ThemeProviderComponent))
private themeProvider: ThemeProviderComponent
) {}
}
we get the reference of ThemeProviderComponent by using forwardRef. In the template markup, we utilised the theme for palette and scale.
Below is code implementation for my-button component
<theme-provider>
<my-button
[color]="'uiBlue'"
[scale]="9">
Button
</my-button>
</theme-provider>
used in ngTemplate
In this example we customised my-button component and gain access the theme object thru ngTemplate
<theme-provider>
<ng-template let-palette="palette" let-scales="scales">
<my-button>
<div
[style.color]="palette['uiYellow']"
[style.background-color]="palette['uiPink']"
[style.font-size]="scales['spacing-09']"
>
Button
</div>
</my-button>
</ng-template>
</theme-provider>
Summary
The theme provider let us use the theme object like palette, spacing and sizing in scripting layer rather than stylesheet layer. For those who more comfortable in styling the component in JavaScript, this pattern can help to speed up styling works.
You can get all the codes used in this post here - https://stackblitz.com/edit/theme-provider
Top comments (1)
like reactjs <3 thank bro