/** * @license * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview We should consider dropping support for this API: * * 1. we need to try avoid using `innerHTML` for xss concerns * 2. we have css variables which are more recommended way to custom styling */ /** * // import { useShadow } from '@polymer/polymer/lib/utils/settings'; * TODO(TS): polymer/lib/utils/settings.d.ts is not exporting useShadow * while the js is, to avoid the error, re-define it here */ const useShadow = !window.ShadyDOM || !window.ShadyDOM.inUse; let styleObjectCount = 0; interface PgElement extends Element { __pg_js_api_style_tags: { [className: string]: boolean; }; } export class GrStyleObject { private className = ''; constructor(private readonly rulesStr: string) { this.className = `__pg_js_api_class_${styleObjectCount}`; styleObjectCount++; } /** * Creates a new unique CSS class and injects it in a root node of the element * if it hasn't been added yet. A root node is an document or is the * associated shadowRoot. This class can be added to any element with the same * root node. * */ getClassName(element: Element) { let rootNodeEl = useShadow ? element.getRootNode() : document.body; if (rootNodeEl === document) { rootNodeEl = document.head; } // TODO(TS): type casting to have correct interface // maybe move this __pg_xxx to attribute const rootNode: PgElement = rootNodeEl as PgElement; if (!rootNode.__pg_js_api_style_tags) { rootNode.__pg_js_api_style_tags = {}; } if (!rootNode.__pg_js_api_style_tags[this.className]) { const styleTag = document.createElement('style'); styleTag.innerHTML = `.${this.className} { ${this.rulesStr} }`; rootNode.appendChild(styleTag); rootNode.__pg_js_api_style_tags[this.className] = true; } return this.className; } /** * Apply shared style to the element. * */ apply(element: Element) { element.classList.add(this.getClassName(element)); } } /** * TODO(TS): move to util */ export class GrStylesApi { /** * Creates a new GrStyleObject with specified style properties. */ css(ruleStr: string) { return new GrStyleObject(ruleStr); } }