{"version":3,"file":"polyfill-support.js","sources":["src/polyfill-support.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * lit-html patch to support browsers without native web components.\n *\n * This module should be used in addition to loading the web components\n * polyfills via @webcomponents/webcomponentjs. When using those polyfills\n * support for polyfilled Shadow DOM is automatic via the ShadyDOM polyfill.\n * Scoping classes are added to DOM nodes to facilitate CSS scoping that\n * simulates the style scoping Shadow DOM provides. ShadyDOM does this scoping\n * to all elements added to the DOM. This module provides an important\n * optimization for this process by pre-scoping lit-html template\n * DOM. This means ShadyDOM does not have to scope each instance of the\n * template DOM. Instead, each template is scoped only once.\n *\n * Creating scoped CSS is not covered by this module. It is, however, integrated\n * into the lit-element and @lit/reactive-element packages. See the ShadyCSS docs\n * for how to apply scoping to CSS:\n * https://github.com/webcomponents/polyfills/tree/master/packages/shadycss#usage.\n *\n * @packageDocumentation\n */\n\nexport {};\n\ninterface RenderOptions {\n readonly renderBefore?: ChildNode | null;\n scope?: string;\n}\n\ninterface ShadyTemplateResult {\n strings: TemplateStringsArray;\n // This property needs to remain unminified.\n ['_$litType$']?: string;\n}\n\n// Note, this is a dummy type as the full type here is big.\ninterface Directive {\n __directive?: Directive;\n}\n\ninterface DirectiveParent {\n _$parent?: DirectiveParent;\n __directive?: Directive;\n __directives?: Array;\n}\n\ninterface PatchableChildPartConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-misused-new\n new (...args: any[]): PatchableChildPart;\n}\n\ninterface PatchableChildPart {\n __directive?: Directive;\n _$committedValue: unknown;\n _$startNode: ChildNode;\n _$endNode: ChildNode | null;\n options: RenderOptions;\n _$setValue(value: unknown, directiveParent: DirectiveParent): void;\n _$getTemplate(result: ShadyTemplateResult): HTMLTemplateElement;\n}\n\ninterface PatchableTemplate {\n el: HTMLTemplateElement;\n}\n\ninterface PatchableTemplateConstructor {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-misused-new\n new (...args: any[]): PatchableTemplate;\n createElement(html: string, options?: RenderOptions): HTMLTemplateElement;\n}\n\ninterface PatchableTemplateInstance {\n _$template: PatchableTemplate;\n}\n\n// Scopes that have had styling prepared. Note, must only be done once per\n// scope.\nconst styledScopes: Set = new Set();\n// Map of css per scope. This is collected during first scope render, used when\n// styling is prepared, and then discarded.\nconst scopeCssStore: Map = new Map();\n\nconst ENABLE_SHADYDOM_NOPATCH = true;\n\n// Note, explicitly use `var` here so that this can be re-defined when\n// bundled.\n// eslint-disable-next-line no-var\nvar DEV_MODE = true;\n\n/**\n * lit-html patches. These properties cannot be renamed.\n * * ChildPart.prototype._$getTemplate\n * * ChildPart.prototype._$setValue\n */\nconst polyfillSupport: NonNullable = (\n Template: PatchableTemplateConstructor,\n ChildPart: PatchableChildPartConstructor\n) => {\n // polyfill-support is only needed if ShadyCSS or the ApplyShim is in use\n // We test at the point of patching, which makes it safe to load\n // webcomponentsjs and polyfill-support in either order\n if (\n window.ShadyCSS === undefined ||\n (window.ShadyCSS.nativeShadow && !window.ShadyCSS.ApplyShim)\n ) {\n return;\n }\n\n // console.log(\n // '%c Making lit-html compatible with ShadyDOM/CSS.',\n // 'color: lightgreen; font-style: italic'\n // );\n\n const wrap =\n ENABLE_SHADYDOM_NOPATCH &&\n window.ShadyDOM?.inUse &&\n window.ShadyDOM?.noPatch === true\n ? window.ShadyDOM!.wrap\n : (node: Node) => node;\n\n const needsPrepareStyles = (name: string | undefined) =>\n name !== undefined && !styledScopes.has(name);\n\n const cssForScope = (name: string) => {\n let scopeCss = scopeCssStore.get(name);\n if (scopeCss === undefined) {\n scopeCssStore.set(name, (scopeCss = []));\n }\n return scopeCss;\n };\n\n const prepareStyles = (name: string, template: HTMLTemplateElement) => {\n // Get styles\n const scopeCss = cssForScope(name);\n const hasScopeCss = scopeCss.length !== 0;\n if (hasScopeCss) {\n const style = document.createElement('style');\n style.textContent = scopeCss.join('\\n');\n // Note, it's important to add the style to the *end* of the template so\n // it doesn't mess up part indices.\n template.content.appendChild(style);\n }\n // Mark this scope as styled.\n styledScopes.add(name);\n // Remove stored data since it's no longer needed.\n scopeCssStore.delete(name);\n // ShadyCSS removes scopes and removes the style under ShadyDOM and leaves\n // it under native Shadow DOM\n window.ShadyCSS!.prepareTemplateStyles(template, name);\n // Note, under native Shadow DOM, the style is added to the beginning of the\n // template. It must be moved to the *end* of the template so it doesn't\n // mess up part indices.\n if (hasScopeCss && window.ShadyCSS!.nativeShadow) {\n // If there were styles but the CSS text was empty, ShadyCSS will\n // eliminate the style altogether, so the style here could be null\n const style = template.content.querySelector('style');\n if (style !== null) {\n template.content.appendChild(style);\n }\n }\n };\n\n const scopedTemplateCache = new Map<\n string | undefined,\n Map\n >();\n\n /**\n * Override to extract style elements from the template\n * and store all style.textContent in the shady scope data.\n * Note, it's ok to patch Template since it's only used via ChildPart.\n */\n const originalCreateElement = Template.createElement;\n Template.createElement = function (html: string, options?: RenderOptions) {\n const element = originalCreateElement.call(Template, html, options);\n const scope = options?.scope;\n if (scope !== undefined) {\n if (!window.ShadyCSS!.nativeShadow) {\n window.ShadyCSS!.prepareTemplateDom(element, scope);\n }\n // Process styles only if this scope is being prepared. Otherwise,\n // leave styles as is for back compat with Lit1.\n if (needsPrepareStyles(scope)) {\n const scopeCss = cssForScope(scope);\n // Remove styles and store textContent.\n const styles = element.content.querySelectorAll(\n 'style'\n ) as NodeListOf;\n // Store the css in this template in the scope css and remove the