angular / angular/angular

feat(API): Make ɵSharedStylesHost a Public API in Angular for customisable style overrides

Ouverte
#59,429 3 commentaires 11 réactions 0 personnes assignées Voir sur GitHub
area: core feature needs triage
Langage dominant
TypeScript
Étoiles
101k
Forks
27.5k
Merge moyen
1 j 19 h
PR mergées (30 j)
288

Description

### Feature Description

This proposal suggests making the internal API `ɵSharedStylesHost` a public API, allowing developers to leverage the advantage of extending ɵSharedStylesHost. By exposing the extended version of ɵSharedStylesHost through Angular’s dependency injection system, developers can easily access it to modify or override styles dynamically for use cases such as Web Components or cross-framework environments.

### Use Case

### Proposal: Make `ɵSharedStylesHost` a public API in Angular for Customisable Style Overrides
for Web Component-based Environments
#### **Context**
As web development progresses towards using **Web Components**, developers often need greater flexibility to **dynamically modify styles** of components, especially when they are used across multiple frameworks or environments. In Angular, the `ɵSharedStylesHost` class plays a central role in managing styles across components, particularly those using **ViewEncapsulation.Emulated**. However, `ɵSharedStylesHost` is an internal class, and developers currently have no public API to interact with it for dynamic style modification.

Given the increasing adoption of **Web Component** architecture, especially in projects that need to integrate Angular components as **custom elements**, there is a need for a solution that allows overriding styles at runtime. This is particularly useful for use cases like dynamic theming or external style injection, such as when Angular Material components are used in a Web Component-based environment.

This proposal suggests **extending `ɵSharedStylesHost`** to allow developers to interact with it via **Angular’s dependency injection system**. By exposing the extended version of `ɵSharedStylesHost` through a provider, developers can easily access it to modify or override styles dynamically for use cases like **Web Components** or **cross-framework environments**.

#### **Problem Statement**
- **Web Component Environments**: Angular components, especially those encapsulated using **Shadow DOM** or **ViewEncapsulation.Emulated**, often need to have their styles dynamically overridden in web component-based environments.
- **Material CSS**: When using **Angular Material** components or third-party libraries inside Angular custom elements, there may be a need to override specific styles like themes, colors, or layout properties dynamically.
- **No Public API for Dynamic Style Overrides**: Currently, Angular does not provide an easy, public API to interact with or override styles after the component is initialized, especially for components that use **ViewEncapsulation.Emulated** or **Shadow DOM**.

#### **Objective**
This proposal aims to extend the functionality of the internal `ɵSharedStylesHost` class and expose it via Angular’s **dependency injection system**. By doing so, we provide a public mechanism for dynamically modifying or overriding styles in Angular components, particularly those used as **Web Components** or **custom elements**.

#### **Proposed Solution**
1. **Extend `ɵSharedStylesHost` and Expose It Through a Provider**:
- Extend the `ɵSharedStylesHost` class to allow dynamic interaction with the styles it manages.
- Provide this extended class as a service through Angular's dependency injection system so that developers can use it in their components, directives, or other services.

Example Extended `SharedStylesHost`:

```typescript
import { Injectable } from '@angular/core';
import { ɵSharedStylesHost } from '@angular/core';

@Injectable({
providedIn: 'root', // This allows the service to be injected globally
})
export class ExtendedSharedStylesHost extends ɵSharedStylesHost {

constructor() {
super();
}

/**
* Dynamically overrides a style in the component's view.
* @param selector CSS selector of the target element.
* @param property CSS property to override.
* @param value New value for the property.
*/
overrideStyle(selector: string, property: string, value: string): void {
const element = document.querySelector(selector);
if (element) {
element.style[property] = value;
} else {
console.error(`Element with selector "${selector}" not found.`);
}
}

/**
* Injects a new stylesheet into the component's view.
* @param styleUrl URL of the stylesheet.
*/
injectStylesheet(styleUrl: string): void {
// Check if the stylesheet already exists to avoid duplication
const existingLink = document.querySelector(`link[href="${styleUrl}"]`);
if (!existingLink) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = styleUrl;
document.head.appendChild(link);
} else {
console.log(`Stylesheet with URL "${styleUrl}" already injected.`);
}
}

/**
* Removes an injected stylesheet.
* @param styleUrl URL of the stylesheet to remove.
*/
removeStylesheet(styleUrl: string): void {
const link = document.querySelector(`link[href="${styleUrl}"]`);
if (link) {
link.remove();
} else {
console.error(`Stylesheet with URL "${styleUrl}" not found.`);
}
}

/**
* Override and manipulate styles before injecting them.
* @param styles Array of CSS styles as strings.
*/
override addStyles(styles: string[]): void {
// Manipulate styles before calling the super method
const modifiedStyles = styles.map(style => {
// Example: Wrap all styles with a custom class to scope them
return `.custom-class ${style}`;
});

// Call the original addStyles method with modified styles
super.addStyles(modifiedStyles);
}
}
```

2. **Register the Extended Service in Angular’s Providers**:
- Angular’s **dependency injection** system can be used to inject this extended service into any component or service that needs to override styles dynamically.
- By registering `ExtendedSharedStylesHost` as a provider in the application, we ensure that it is available throughout the application, especially for components using **ViewEncapsulation.Emulated** or **Shadow DOM**.

Example of providing the service globally:
```typescript
@NgModule({
providers: [
ExtendedSharedStylesHost // Register the extended service
]
})
export class AppModule {}
```

3. **Using the Extended `SharedStylesHost` in Components**:
- In any component or service, developers can now inject the `ExtendedSharedStylesHost` and use its methods to interact with and override styles of components dynamically.

Example usage in a component:
```typescript
@Component({
selector: 'app-dynamic-style',
templateUrl: './dynamic-style.component.html',
styleUrls: ['./dynamic-style.component.css']
})
export class DynamicStyleComponent {
constructor(private stylesHost: ExtendedSharedStylesHost) {}

changeTheme() {
// Example: Dynamically change background color using overrideStyle method
this.stylesHost.overrideStyle('.theme-background', 'background-color', 'lightblue');
}

addCustomStyles() {
// Dynamically add a new stylesheet
this.stylesHost.injectStylesheet('assets/custom-styles.css');
}
}
```

4. **Cross-framework Compatibility and Web Component Customization**:
- Since the `ExtendedSharedStylesHost` service can be injected globally, it allows Angular components embedded as Web Components to interact with their styles dynamically.
- Developers can use this service to ensure that styles (such as CSS variables) are injected or overridden according to external needs, such as theming across multiple frameworks.

5. **Dynamic Theming Support**:
- This solution would support the ability to **dynamically inject CSS** variables or stylesheets at runtime, enabling applications to easily swap between different themes or branding options.
- This is particularly useful in environments where Angular Material is used as a Web Component and developers need to dynamically switch themes.

#### **Benefits**
1. **Improved Flexibility**: By exposing `ɵSharedStylesHost` as a public API, developers can programmatically manage styles for Angular components, particularly those used in Web Component-based environments.
2. **Dynamic Theming**: The ability to dynamically change themes, override default styles, and apply custom CSS would enhance user experience and make Angular components more adaptable.
3. **Cross-framework Integration**: Developers can now modify Angular component styles when using them as custom elements or web components within other frameworks (like React or Vue).
4. **Web Component Customization**: This solution enables deep customization of Angular components used as web components, offering a powerful mechanism for styling and theming.

#### **Considerations**
1. **Performance**: Dynamically injecting styles or modifying component styles could have a performance impact if done too frequently. Care should be taken to optimize for large applications.
2. **Backward Compatibility**: This solution should ensure that existing applications using Angular’s current style encapsulation mechanisms are not broken.
3. **Security**: The extension of `ɵSharedStylesHost` should ensure that it does not expose sensitive internal implementation details or break Angular's encapsulation model.

#### **Conclusion**
By extending the `ɵSharedStylesHost` class and exposing it as a public service through Angular's **dependency injection** system, we can provide developers with the tools to dynamically manage and override styles in Angular components. This would be particularly beneficial for **Web Component-based environments**, **cross-framework styling**, and **dynamic theming**, helping Angular remain flexible and adaptable for modern, large-scale applications.

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Commencez par localiser ɵSharedStylesHost et examiner les points d’entrée d’Angular pour l’injection de dépendances et l’encapsulation des styles. Comme l’issue ne nomme aucun fichier ni test, commencez par suivre l’implémentation actuelle et les conventions de l’API publique ; le travail est considéré comme terminé lorsqu’une conception d’API ciblée et validée pour la gestion des styles personnalisés, avec une couverture appropriée, est établie.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
angular, typescript
Domaine
frontend
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
À clarifier
Accessibilité débutants
25/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.