diff --git a/shadycss/README.md b/shadycss/README.md index c09ce80..6e04141 100644 --- a/shadycss/README.md +++ b/shadycss/README.md @@ -53,47 +53,40 @@ import '@polymer/paper-button/paper-button'; export class AppComponent {} ``` -## IE11 Issue +## `@apply` mixins -Initial CSS custom properties must be defined on an `html` selector in a `ViewEncapsulation.None` component. - -## Limitations - -### External Stylesheets - -This module cannot provide polyfill support for external stylesheets or any styles defined in the `angular.json` or `.angular-cli.json` `"styles"` array. A recommended workaround is to use `ViewEncapsulation.None` on the app's root component and use its component styles as "global" styles. +If using the deprecated `@apply` mixin proposal, import `ShadyCSSModule.usingApply()` instead. ```ts -import { Component, ViewEncapsulation } from '@angular/core'; +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { ShadyCSSModule } from '@codebakery/origami/shadycss'; +import { AppComponent } from './app.component'; -@Component({ - selector: 'app-root', - templateUrl: './app-root.component.html', - // global.css may use CSS custom properties that will affect all children of - // the root element. - styleUrls: ['./global.css'], - encapsulation: ViewEncapsulation.None +@NgModule({ + imports: [BrowserModule, ShadyCSSModule.usingApply()], + declarations: [AppComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + bootstrap: [AppComponent] }) -export class AppRootComponent {} +export class AppModule {} ``` -### IE11 New Properties +## Limitations + +### Defining CSS Custom Properties -Properties that are defined in a Shadow DOM template (such as those provided by custom elements) will work with ShadyCSS in IE11. However, _newly_ defined properties in an Angular template must be defined with an `html` selector in a `ViewEncapsulation.None` component. +_Newly_ defined CSS custom properties must be defined in a root `html` or `:root` selector. It is recommended to define new properties in global CSS instead of component styles. ```ts -import { Component, ViewEncapsulation } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'app-component', styles: [ ` - html { - /* - --my-color is not defined by an external element, it is our own - CSS property. To work with ShadyCSS, it must be defined on an html - root selector. - */ + /* This does not work */ + :host { --my-color: blue; } @@ -103,18 +96,19 @@ import { Component, ViewEncapsulation } from '@angular/core'; ` ], template: ` -
I'm blue!
- `, - /* - In order for the above html selector to work, the component must have - ViewEncapsulation.None, since Angular cannot encapsulate the root html - element. - */ - encapsulation: ViewEncapsulation.None +
I'm not blue :(
+ ` }) export class AppComponent {} ``` -See [this issue](https://github.com/webcomponents/shadycss/issues/75) for more information. +The example `--my-color` property should be defined in a global CSS stylesheet. -Like the above limitation, it is recommended that all custom CSS properties an app defines should be declared in a root component that does not have view encapsulation. +```css +html { + /* AppComponent's
will now be blue */ + --my-color: blue; +} +``` + +See [this issue](https://github.com/webcomponents/shadycss/issues/75) for more information. diff --git a/shadycss/public_api.ts b/shadycss/public_api.ts index 4c3a168..69403ca 100644 --- a/shadycss/public_api.ts +++ b/shadycss/public_api.ts @@ -1,3 +1,4 @@ export * from './src/models'; +export * from './src/process-stylesheets'; export * from './src/shadycss.module'; export * from './src/shared-styles-host'; diff --git a/shadycss/src/models.ts b/shadycss/src/models.ts index 9157452..0f6de66 100644 --- a/shadycss/src/models.ts +++ b/shadycss/src/models.ts @@ -5,6 +5,8 @@ export namespace ShadyCSS { } export interface ShadyCSS { + nativeCss: boolean; + nativeShadow: boolean; CustomStyleInterface?: ShadyCSS.CustomStyleInterface; } diff --git a/shadycss/src/process-stylesheets.ts b/shadycss/src/process-stylesheets.ts new file mode 100644 index 0000000..e09ff1a --- /dev/null +++ b/shadycss/src/process-stylesheets.ts @@ -0,0 +1,55 @@ +import { InjectionToken } from '@angular/core'; + +/** + * By default, Origami will not parse or register styles with ShadyCSS if the + * platform supports native CSS custom properties. However, ShadyCSS also + * supports the deprecated `@apply` mixin proposal. If a project is using + * `@apply` in CSS, this token should be provided with a true value. + */ +export const USING_APPLY = new InjectionToken('usingApply'); + +/** + * Processes all current document stylesheets added by Angular and registers + * them with ShadyCSS. + * + * This function will also parse external `` stylesheets if native + * CSS custom properties are not supported, or if `usingApply` is set to true. + * + * @param usingApply if true, parse stylesheets regardless of native support, + * since no browser supports `@apply` natively + */ +export function processStylesheets(usingApply?: boolean) { + const CustomStyleInterface = + window.ShadyCSS && window.ShadyCSS.CustomStyleInterface; + if (CustomStyleInterface && (!window.ShadyCSS.nativeCss || usingApply)) { + Array.from(document.styleSheets).forEach(stylesheet => { + const node = stylesheet.ownerNode; + if (isStyleNode(node) && !node.hasAttribute('scope')) { + CustomStyleInterface.addCustomStyle(node); + } else if (stylesheet.href && !(stylesheet)._fetching) { + (stylesheet)._fetching = true; + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => { + const style = document.createElement('style'); + style.innerHTML = xhr.responseText; + node.parentNode!.insertBefore(style, node); + node.parentNode!.removeChild(node); + CustomStyleInterface.addCustomStyle(style); + }); + + xhr.open('GET', stylesheet.href); + xhr.send(); + } + }); + } +} + +/** + * Returns true if the provided node is a `