Skip to content

Commit

Permalink
feat(styles): rename shadycss path to styles, add Polymer style modul…
Browse files Browse the repository at this point in the history
…e support

Closes #70
  • Loading branch information
asyncLiz committed Aug 24, 2018
1 parent 85c99d4 commit 96f15a2
Show file tree
Hide file tree
Showing 21 changed files with 406 additions and 14 deletions.
29 changes: 26 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Angular + Polymer
[Angular and custom elements are BFFs](https://custom-elements-everywhere.com/). With Polymer, there are a few gaps that Origami fills. The library is divided into several modules that can be imported individually to address these gaps.

- [Angular Form Support](forms/README.md)
- [ShadyCSS Support](shadycss/README.md)
- [ShadyCSS Support](styles/README.md#shadycss)
- [Style Modules](styles/README.md#style-modules)
- [Polymer `<template>` Stamping](templates/README.md)
- [Polyfill Utilities](polyfills/README.md)

Expand Down Expand Up @@ -131,9 +132,9 @@ export class AppComponent {
}
```

### [ShadyCSS Support](shadycss/README.md)
### [ShadyCSS Support](styles/README.md#shadycss)

Enables the use of CSS custom properties in Angular styles on browsers that do not support them via [ShadyCSS](https://github.com/webcomponents/shadycss), with some [limitations](shadycss/README.md#limitations).
Enables the use of CSS custom properties in Angular styles on browsers that do not support them via [ShadyCSS](https://github.com/webcomponents/shadycss), with some [limitations](styles/README.md#limitations).

```ts
import { Component } from '@angular/core';
Expand All @@ -155,6 +156,28 @@ import '@polymer/paper-button/paper-button';
export class AppComponent {}
```

### [Style Modules](styles/README.md#style-modules)

Allows for [style modules](https://www.polymer-project.org/3.0/docs/devguide/style-shadow-dom#style-modules) defined in Polymer to be injected into Angular components.

```ts
import { Component } from '@angular/core';
import { IncludeStyles } from '@codebakery/origami/styles';
import '@polymer/iron-flex-layout/iron-flex-layout-classes';

@IncludeStyles('iron-flex')
@Component({
selector: 'app-component',
template: `
<div class="layout horizontal">
<div class="flex">Column 1</div>
<div class="flex">Column 2</div>
</div>
`
})
export class AppComponent {}
```

### [Polymer `<template>` Stamping](templates/README.md)

Call `polymerHost()` and add it to the providers for a component that uses Polymer's data binding syntax in `<template>` elements. Add `ngNonBindable` to all `<template>` elements.
Expand Down
5 changes: 4 additions & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ Additionally, Origami has been split into several modules. `OrigamiModule` will
import { OrigamiModule } from '@codebakery/origami';
// or
import { OrigamiFormsModule } from '@codebakery/origami/forms';
import { ShadyCSSModule } from '@codebakery/origami/shadycss';
import {
IncludeStylesModule,
ShadyCSSModule
} from '@codebakery/origami/styles';
import { TemplateModule } from '@codebakery/origami/templates';
import { WebComponentsReadyModule } from '@codebakery/origami/polyfills';
```
Expand Down
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module.exports = config => {
frameworks: ['jasmine', 'karma-typescript'],
files: [
'init.spec.ts',
'{forms,polyfills,shadycss,src,templates,util}/**/*.ts'
'{forms,polyfills,styles,src,templates,util}/**/*.ts'
],
preprocessors: {
'**/*.ts': 'karma-typescript'
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"peerDependencies": {
"@angular/core": "^5.0.0-rc.0 || ^5.0.0 || ^6.0.0-rc.0 || ^6.0.0",
"@angular/forms": "^5.0.0-rc.0 || ^5.0.0 || ^6.0.0-rc.0 || ^6.0.0",
"@angular/router": "^5.0.0-rc.0 || ^5.0.0 || ^6.0.0-rc.0 || ^6.0.0",
"@polymer/polymer": "^3.0.5",
"@webcomponents/webcomponentsjs": "^2.0.4",
"tslib": "^1.7.0",
Expand All @@ -76,6 +77,7 @@
"@angular/forms": "^6.1.0",
"@angular/platform-browser": "^6.1.0",
"@angular/platform-browser-dynamic": "^6.1.0",
"@angular/router": "^6.1.0",
"@polymer/polymer": "^3.0.5",
"@types/glob": "^5.0.35",
"@types/jasmine": "^2.8.8",
Expand Down
4 changes: 0 additions & 4 deletions shadycss/public_api.ts

This file was deleted.

7 changes: 6 additions & 1 deletion src/origami.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { NgModule } from '@angular/core';
import { OrigamiFormsModule } from '@codebakery/origami/forms';
import { ShadyCSSModule } from '@codebakery/origami/shadycss';
import {
IncludeStylesModule,
ShadyCSSModule
} from '@codebakery/origami/styles';
import { TemplateModule } from '@codebakery/origami/templates';
import { WebComponentsReadyModule } from '@codebakery/origami/polyfills';

Expand All @@ -10,12 +13,14 @@ import { WebComponentsReadyModule } from '@codebakery/origami/polyfills';
@NgModule({
imports: [
OrigamiFormsModule,
IncludeStylesModule,
ShadyCSSModule,
TemplateModule,
WebComponentsReadyModule
],
exports: [
OrigamiFormsModule,
IncludeStylesModule,
ShadyCSSModule,
TemplateModule,
WebComponentsReadyModule
Expand Down
52 changes: 50 additions & 2 deletions shadycss/README.md → styles/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,51 @@
# Modules

- [Include Styles](#include-styles)
- [ShadyCSS](#shadycss)

# Include Styles

Allows for [style modules](https://www.polymer-project.org/3.0/docs/devguide/style-shadow-dom#style-modules) defined in Polymer to be injected into Angular components.

## Usage

Import the `IncludeStylesModule` into the app's root `@NgModule`.

```ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IncludeStylesModule } from '@codebakery/origami/styles';
import { AppComponent } from './app.component';

@NgModule({
imports: [BrowserModule, IncludeStylesModule],
declarations: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
bootstrap: [AppComponent]
})
export class AppModule {}
```

Use the `@IncludeStyles()` decorater to inject one or more style modules into the component.

```ts
import { Component } from '@angular/core';
import { IncludeStyles } from '@codebakery/origami/styles';
import '@polymer/iron-flex-layout/iron-flex-layout-classes';

@IncludeStyles('iron-flex')
@Component({
selector: 'app-component',
template: `
<div class="layout horizontal">
<div class="flex">Column 1</div>
<div class="flex">Column 2</div>
</div>
`
})
export class AppComponent {}
```

# ShadyCSS

Adds [ShadyCSS](https://github.com/webcomponents/shadycss) support to Angular styles. This allows the usage of CSS custom properties in browsers that do not support them.
Expand All @@ -9,7 +57,7 @@ Import the `ShadyCSSModule` in any `@NgModule` you wish to use ShadyCSS with. Fo
```ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ShadyCSSModule } from '@codebakery/origami/shadycss';
import { ShadyCSSModule } from '@codebakery/origami/styles';
import { AppComponent } from './app.component';

@NgModule({
Expand Down Expand Up @@ -60,7 +108,7 @@ If using the deprecated `@apply` mixin proposal, import `ShadyCSSModule.usingApp
```ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ShadyCSSModule } from '@codebakery/origami/shadycss';
import { ShadyCSSModule } from '@codebakery/origami/styles';
import { AppComponent } from './app.component';

@NgModule({
Expand Down
2 changes: 1 addition & 1 deletion shadycss/package.json → styles/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"dest": "../",
"lib": {
"entryFile": "public_api.ts",
"flatModuleFile": "origami-shadycss"
"flatModuleFile": "origami-styles"
}
}
}
10 changes: 10 additions & 0 deletions styles/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export * from './src/modules/import-style-module';
export * from './src/modules/include-styles.module';
export * from './src/modules/include-styles';
export * from './src/modules/inject-styles';
export * from './src/modules/style-to-emulated-encapsulation';
export * from './src/modules/type-selectors';
export * from './src/shadycss/models';
export * from './src/shadycss/process-stylesheets';
export * from './src/shadycss/shadycss.module';
export * from './src/shadycss/shared-styles-host';
24 changes: 24 additions & 0 deletions styles/src/modules/import-style-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DomModule } from '@polymer/polymer/lib/elements/dom-module';

const CACHED_STYLE_MODULES = new Map<string, string | undefined>();

export function importStyleModule(styleModule: string): string | undefined {
if (!CACHED_STYLE_MODULES.has(styleModule)) {
const styleTemplate = <HTMLTemplateElement | undefined>(
DomModule.import(styleModule, 'template')
);
if (styleTemplate) {
const styles = styleTemplate.content.querySelectorAll('style');
CACHED_STYLE_MODULES.set(
styleModule,
Array.from(styles)
.map(style => style.innerText)
.join('\n')
);
} else {
CACHED_STYLE_MODULES.set(styleModule, undefined);
}
}

return CACHED_STYLE_MODULES.get(styleModule);
}
20 changes: 20 additions & 0 deletions styles/src/modules/include-styles.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
APP_INITIALIZER,
ModuleWithProviders,
NgModule,
NgModuleRef,
Provider
} from '@angular/core';
import { injectIncludeStyles } from './inject-styles';

export const INJECT_STYLES_PROVIDER: Provider = {
provide: APP_INITIALIZER,
multi: true,
useFactory: injectIncludeStyles,
deps: [NgModuleRef]
};

@NgModule({
providers: [INJECT_STYLES_PROVIDER]
})
export class IncludeStylesModule {}
33 changes: 33 additions & 0 deletions styles/src/modules/include-styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Type } from '@angular/core';

const TYPE_STYLE_MODULES = new Map<Type<any>, string[]>();

function IncludeStylesDecorator(...styleModules: string[]): ClassDecorator {
return (target: any) => {
TYPE_STYLE_MODULES.set(target, styleModules);
return target;
};
}

function getRegisteredTypes(): Array<Type<any>> {
return Array.from(TYPE_STYLE_MODULES.keys());
}

function getStyleModulesFor(type: Type<any>): string[] {
return TYPE_STYLE_MODULES.get(type) || [];
}

export type IncludeStyles = ((
styleModule: string,
...styleModules: string[]
) => ClassDecorator) &
IncludeStylesStatic;

export interface IncludeStylesStatic {
getRegisteredTypes(): Array<Type<any>>;
getStyleModulesFor(type?: Type<any>): string[];
}

export const IncludeStyles = <IncludeStyles>IncludeStylesDecorator;
IncludeStyles.getRegisteredTypes = getRegisteredTypes;
IncludeStyles.getStyleModulesFor = getStyleModulesFor;
66 changes: 66 additions & 0 deletions styles/src/modules/inject-styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
ComponentFactoryResolver,
NgModuleRef,
RendererFactory2,
Type,
ViewEncapsulation
} from '@angular/core';
import { Router } from '@angular/router';
import { whenSet } from '@codebakery/origami/util';
import { importStyleModule } from './import-style-module';
import { IncludeStyles } from './include-styles';
import { styleToEmulatedEncapsulation } from './style-to-emulated-encapsulation';
import { getTypeFor, scanComponentFactoryResolver } from './type-selectors';

export function injectIncludeStyles(ngModule: NgModuleRef<any>): () => void {
return () => {
patchRendererFactory(ngModule.injector.get(RendererFactory2));
scanComponentFactoryResolver(
ngModule.injector.get(ComponentFactoryResolver)
);
const router = <Router>ngModule.injector.get(Router);
router.events.subscribe(e => {
if ('route' in e && !(<any>e.route)._loadedConfig) {
whenSet(<any>e.route, '_loadedConfig', undefined, config => {
scanComponentFactoryResolver(
config.module.injector.get(ComponentFactoryResolver)
);
});
}
});
};
}

const INJECTED_SELECTORS: string[] = [];

export function patchRendererFactory(factory: RendererFactory2) {
const $createRenderer = factory.createRenderer;
factory.createRenderer = function(element, type) {
const selector = element && element.localName;
if (selector && type && INJECTED_SELECTORS.indexOf(selector) === -1) {
const styleModules = IncludeStyles.getStyleModulesFor(
getTypeFor(selector)
);
let styles = styleModules.map(
styleModule => importStyleModule(styleModule) || ''
);
switch (type.encapsulation) {
case ViewEncapsulation.Emulated:
default:
styles = styles.map(style =>
styleToEmulatedEncapsulation(style, type.id)
);
break;
case ViewEncapsulation.Native:
case ViewEncapsulation.None:
case ViewEncapsulation.ShadowDom:
break;
}

type.styles.push(...styles);
INJECTED_SELECTORS.push(selector);
}

return $createRenderer.apply(this, arguments);
};
}
Loading

0 comments on commit 96f15a2

Please sign in to comment.