-
-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(runtime): initial runtime support for styles
- Loading branch information
1 parent
b4cdd38
commit 6aafcca
Showing
6 changed files
with
183 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { IContainer } from '@aurelia/kernel'; | ||
import { bindable, customAttribute } from '@aurelia/runtime'; | ||
|
||
export class CSSModulesRegistry { | ||
public register(container: IContainer, ...params: (Record<string, string>)[]) { | ||
const classLookup = Object.assign({}, ...params) as Record<string, string>; | ||
|
||
@customAttribute('class') | ||
class ClassCustomAttribute { | ||
@bindable public value!: string; | ||
|
||
constructor(private element: HTMLElement) {} | ||
|
||
public binding() { | ||
this.valueChanged(); | ||
} | ||
|
||
public valueChanged() { | ||
if (!this.value) { | ||
this.element.className = ''; | ||
return; | ||
} | ||
|
||
this.element.className = this.value.split(' ') | ||
.map(x => classLookup[x] || x) | ||
.join(' '); | ||
} | ||
} | ||
|
||
container.register(ClassCustomAttribute); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { IContainer, Registration } from '@aurelia/kernel'; | ||
import { | ||
AdoptedStyleSheetsStyleManager, | ||
IShadowDOMStyleManager, | ||
StyleElementStyleManager | ||
} from './shadow-dom-styles'; | ||
|
||
export function adoptedStyleSheetsSupported(): boolean { | ||
return 'adoptedStyleSheets' in ShadowRoot.prototype; | ||
} | ||
|
||
export class ShadowDOMRegistry { | ||
private useAdoptedStyleSheets: boolean; | ||
|
||
constructor(private parent: IShadowDOMStyleManager) { | ||
this.useAdoptedStyleSheets = adoptedStyleSheetsSupported(); | ||
} | ||
|
||
public register(container: IContainer, ...params: any[]) { | ||
container.register( | ||
Registration.instance( | ||
IShadowDOMStyleManager, | ||
this.useAdoptedStyleSheets | ||
? new AdoptedStyleSheetsStyleManager(params, this.parent) | ||
: new StyleElementStyleManager(params, this.parent) | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { DI, PLATFORM } from '@aurelia/kernel'; | ||
|
||
type HasAdoptedStyleSheets = ShadowRoot & { | ||
adoptedStyleSheets: CSSStyleSheet[]; | ||
}; | ||
|
||
export const IShadowDOMStyleManager = | ||
DI.createInterface<IShadowDOMStyleManager>('IShadowDOMStyleManager') | ||
.withDefault(x => x.instance({ applyTo: PLATFORM.noop })); | ||
|
||
export interface IShadowDOMStyleManager { | ||
applyTo(shadowRoot: ShadowRoot): void; | ||
} | ||
|
||
export class AdoptedStyleSheetsStyleManager implements IShadowDOMStyleManager { | ||
private readonly styleSheets: CSSStyleSheet[]; | ||
|
||
constructor(styles: string[], private parent: IShadowDOMStyleManager | null = null) { | ||
this.styleSheets = styles.map(x => { | ||
const sheet = new CSSStyleSheet(); | ||
(sheet as any).replaceSync(x); | ||
return sheet; | ||
}); | ||
} | ||
|
||
public applyTo(shadowRoot: HasAdoptedStyleSheets) { | ||
if (this.parent !== null) { | ||
this.parent.applyTo(shadowRoot); | ||
} | ||
|
||
// https://wicg.github.io/construct-stylesheets/ | ||
// https://developers.google.com/web/updates/2019/02/constructable-stylesheets | ||
shadowRoot.adoptedStyleSheets = [ | ||
...shadowRoot.adoptedStyleSheets, | ||
...this.styleSheets | ||
]; | ||
} | ||
} | ||
|
||
export class StyleElementStyleManager implements IShadowDOMStyleManager { | ||
constructor(private styles: string[], private parent: IShadowDOMStyleManager | null = null) {} | ||
|
||
public applyTo(shadowRoot: ShadowRoot) { | ||
const styles = this.styles; | ||
|
||
for (let i = styles.length - 1; i > -1; --i) { | ||
const element = document.createElement('style'); | ||
element.innerHTML = styles[i]; | ||
shadowRoot.prepend(element); | ||
} | ||
|
||
if (this.parent !== null) { | ||
this.parent.applyTo(shadowRoot); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { IContainer, IRegistry, Registration } from '@aurelia/kernel'; | ||
import { CSSModulesRegistry } from './css-modules-registry'; | ||
import { adoptedStyleSheetsSupported, ShadowDOMRegistry } from './shadow-dom-registry'; | ||
import { | ||
AdoptedStyleSheetsStyleManager, | ||
IShadowDOMStyleManager, | ||
StyleElementStyleManager | ||
} from './shadow-dom-styles'; | ||
|
||
const ext = '.css'; | ||
|
||
export interface IShadowDOMConfiguration { | ||
sharedStyles?: string[]; | ||
} | ||
|
||
export function styles(...styles: any[]) { | ||
return Registration.defer(ext, ...styles); | ||
} | ||
|
||
export const StyleConfiguration = { | ||
cssModules(): IRegistry { | ||
return { | ||
register(container: IContainer) { | ||
container.register( | ||
Registration.singleton(ext, CSSModulesRegistry) | ||
); | ||
} | ||
}; | ||
}, | ||
|
||
shadowDOM(config?: IShadowDOMConfiguration): IRegistry { | ||
return { | ||
register(container: IContainer) { | ||
if (config && config.sharedStyles) { | ||
container.register( | ||
Registration.instance( | ||
IShadowDOMStyleManager, | ||
adoptedStyleSheetsSupported() | ||
? new AdoptedStyleSheetsStyleManager(config.sharedStyles, null) | ||
: new StyleElementStyleManager(config.sharedStyles, null) | ||
) | ||
); | ||
} | ||
|
||
container.register( | ||
Registration.singleton(ext, ShadowDOMRegistry) | ||
); | ||
} | ||
}; | ||
} | ||
}; |