lion/packages/ui/components/core/ScopedStylesController.js
2022-10-31 16:55:07 +01:00

53 lines
1.6 KiB
JavaScript

import { unsafeCSS, css } from 'lit';
/**
* @typedef {import('lit').ReactiveControllerHost} ReactiveControllerHost
* @typedef {import('lit').ReactiveController} ReactiveController
* @implements {ReactiveController}
*/
export class ScopedStylesController {
/**
* @param {import('lit').CSSResult} scope
* @return {import('lit').CSSResultGroup}
*/
// eslint-disable-next-line no-unused-vars
static scopedStyles(scope) {
return css``;
}
/**
* @param {ReactiveControllerHost & import('lit').LitElement} host
*/
constructor(host) {
(this.host = host).addController(this);
// Perhaps use constructable stylesheets instead once Safari supports replace(Sync) methods
this.__styleTag = document.createElement('style');
this.scopedClass = `${this.host.localName}-${Math.floor(Math.random() * 10000)}`;
}
hostConnected() {
this.host.classList.add(this.scopedClass);
this.__setupStyleTag();
}
hostDisconnected() {
this.__teardownStyleTag();
}
__setupStyleTag() {
// Make it win from other elements on the page.
// TODO: consider adding an id here to always win, since we are simulating shadow dom
// behavior here.
const highSpecifictyScope = `${this.scopedClass}.${this.scopedClass}`;
this.__styleTag.textContent = /** @type {typeof ScopedStylesController} */ (
this.host.constructor
)
.scopedStyles(unsafeCSS(highSpecifictyScope))
.toString();
this.host.insertBefore(this.__styleTag, this.host.childNodes[0]);
}
__teardownStyleTag() {
this.host.removeChild(this.__styleTag);
}
}