lit-html
Advanced tools
Comparing version 1.1.2 to 1.2.0-pre.1
@@ -13,8 +13,21 @@ # Change Log | ||
<!-- ## Unreleased --> | ||
## Unreleased | ||
<!-- ### Changed --> | ||
<!-- ### Added --> | ||
<!-- ### Fixed --> | ||
<!-- ### Removed --> | ||
<!-- ### Fixed --> | ||
## [1.2.0-pre.1] - 2020-03-16 | ||
### Added | ||
* Added `unsafeSVG` directive to bind SVG source inside SVGs. ([#304](https://github.com/Polymer/lit-html/issues/304)) | ||
* Added `templateContent()` directive for stamping out the contents of an HTML template into a text binding. ([#1058](https://github.com/Polymer/lit-html/issues/1058)) | ||
* Added the `live()` directive. Fixes #877 | ||
### Fixed | ||
* Fixed a bug where `classMap` and `styleMap` directives wouldn't render mutated objects. ([#972](https://github.com/Polymer/lit-html/issues/972)) | ||
* Fixed a bug where ifDefined() would set an attribute even when the value didn't change. ([#890](https://github.com/Polymer/lit-html/issues/890)) | ||
* Change `classMap` directive to set classes correctly on SVGs ([1070#](https://github.com/Polymer/lit-html/issues/1070)). | ||
## [1.1.2] - 2019-08-12 | ||
@@ -21,0 +34,0 @@ |
@@ -32,3 +32,3 @@ /** | ||
*/ | ||
export declare const asyncAppend: (value: AsyncIterable<unknown>, mapper?: ((v: unknown, index?: number | undefined) => unknown) | undefined) => (part: Part) => Promise<void>; | ||
export declare const asyncAppend: <T>(value: AsyncIterable<T>, mapper?: ((v: T, index?: number | undefined) => unknown) | undefined) => (part: Part) => Promise<void>; | ||
//# sourceMappingURL=async-append.d.ts.map |
@@ -33,3 +33,3 @@ /** | ||
*/ | ||
export declare const asyncReplace: (value: AsyncIterable<unknown>, mapper?: ((v: unknown, index?: number | undefined) => unknown) | undefined) => (part: Part) => Promise<void>; | ||
export declare const asyncReplace: <T>(value: AsyncIterable<T>, mapper?: ((v: T, index?: number | undefined) => unknown) | undefined) => (part: Part) => Promise<void>; | ||
//# sourceMappingURL=async-replace.d.ts.map |
@@ -22,5 +22,4 @@ /** | ||
* property in the `classInfo` argument and adds the property name to the | ||
* element's `classList` if the property value is truthy; if the property value | ||
* is falsey, the property name is removed from the element's `classList`. For | ||
* example | ||
* element's `class` if the property value is truthy; if the property value is | ||
* falsey, the property name is removed from the element's `class`. For example | ||
* `{foo: bar}` applies the class `foo` if the value of `bar` is truthy. | ||
@@ -27,0 +26,0 @@ * @param classInfo {ClassInfo} |
@@ -15,2 +15,29 @@ /** | ||
import { AttributePart, directive, PropertyPart } from '../lit-html.js'; | ||
// IE11 doesn't support classList on SVG elements, so we emulate it with a Set | ||
class ClassList { | ||
constructor(element) { | ||
this.classes = new Set(); | ||
this.changed = false; | ||
this.element = element; | ||
const classList = (element.getAttribute('class') || '').split(/\s+/); | ||
for (const cls of classList) { | ||
this.classes.add(cls); | ||
} | ||
} | ||
add(cls) { | ||
this.classes.add(cls); | ||
this.changed = true; | ||
} | ||
remove(cls) { | ||
this.classes.delete(cls); | ||
this.changed = true; | ||
} | ||
commit() { | ||
if (this.changed) { | ||
let classString = ''; | ||
this.classes.forEach((cls) => classString += cls + ' '); | ||
this.element.setAttribute('class', classString); | ||
} | ||
} | ||
} | ||
/** | ||
@@ -20,3 +47,3 @@ * Stores the ClassInfo object applied to a given AttributePart. | ||
*/ | ||
const classMapCache = new WeakMap(); | ||
const previousClassesCache = new WeakMap(); | ||
/** | ||
@@ -26,5 +53,4 @@ * A directive that applies CSS classes. This must be used in the `class` | ||
* property in the `classInfo` argument and adds the property name to the | ||
* element's `classList` if the property value is truthy; if the property value | ||
* is falsey, the property name is removed from the element's `classList`. For | ||
* example | ||
* element's `class` if the property value is truthy; if the property value is | ||
* falsey, the property name is removed from the element's `class`. For example | ||
* `{foo: bar}` applies the class `foo` if the value of `bar` is truthy. | ||
@@ -41,26 +67,39 @@ * @param classInfo {ClassInfo} | ||
const { element } = committer; | ||
// handle static classes | ||
if (!classMapCache.has(part)) { | ||
element.className = committer.strings.join(' '); | ||
let previousClasses = previousClassesCache.get(part); | ||
if (previousClasses === undefined) { | ||
// Write static classes once | ||
// Use setAttribute() because className isn't a string on SVG elements | ||
element.setAttribute('class', committer.strings.join(' ')); | ||
previousClassesCache.set(part, previousClasses = new Set()); | ||
} | ||
const { classList } = element; | ||
// remove old classes that no longer apply | ||
const oldInfo = classMapCache.get(part); | ||
for (const name in oldInfo) { | ||
const classList = (element.classList || new ClassList(element)); | ||
// Remove old classes that no longer apply | ||
// We use forEach() instead of for-of so that re don't require down-level | ||
// iteration. | ||
previousClasses.forEach((name) => { | ||
if (!(name in classInfo)) { | ||
classList.remove(name); | ||
previousClasses.delete(name); | ||
} | ||
} | ||
// add new classes | ||
}); | ||
// Add or remove classes based on their classMap value | ||
for (const name in classInfo) { | ||
const value = classInfo[name]; | ||
if (!oldInfo || value !== oldInfo[name]) { | ||
// We explicitly want a loose truthy check here because | ||
// it seems more convenient that '' and 0 are skipped. | ||
const method = value ? 'add' : 'remove'; | ||
classList[method](name); | ||
if (value != previousClasses.has(name)) { | ||
// We explicitly want a loose truthy check of `value` because it seems | ||
// more convenient that '' and 0 are skipped. | ||
if (value) { | ||
classList.add(name); | ||
previousClasses.add(name); | ||
} | ||
else { | ||
classList.remove(name); | ||
previousClasses.delete(name); | ||
} | ||
} | ||
} | ||
classMapCache.set(part, classInfo); | ||
if (typeof classList.commit === 'function') { | ||
classList.commit(); | ||
} | ||
}); | ||
//# sourceMappingURL=class-map.js.map |
@@ -15,2 +15,3 @@ /** | ||
import { AttributePart, directive } from '../lit-html.js'; | ||
const previousValues = new WeakMap(); | ||
/** | ||
@@ -23,4 +24,7 @@ * For AttributeParts, sets the attribute if the value is defined and removes | ||
export const ifDefined = directive((value) => (part) => { | ||
const previousValue = previousValues.get(part); | ||
if (value === undefined && part instanceof AttributePart) { | ||
if (value !== part.value) { | ||
// If the value is undefined, remove the attribute, but only if the value | ||
// was previously defined. | ||
if (previousValue !== undefined || !previousValues.has(part)) { | ||
const name = part.committer.name; | ||
@@ -30,6 +34,7 @@ part.committer.element.removeAttribute(name); | ||
} | ||
else { | ||
else if (value !== previousValue) { | ||
part.setValue(value); | ||
} | ||
previousValues.set(part, value); | ||
}); | ||
//# sourceMappingURL=if-defined.js.map |
@@ -27,3 +27,3 @@ /** | ||
* way to use `repeat` since it performs minimum unnecessary work for insertions | ||
* amd removals. | ||
* and removals. | ||
* | ||
@@ -30,0 +30,0 @@ * IMPORTANT: If providing a `keyFn`, keys *must* be unique for all items in a |
@@ -66,3 +66,3 @@ /** | ||
* way to use `repeat` since it performs minimum unnecessary work for insertions | ||
* amd removals. | ||
* and removals. | ||
* | ||
@@ -69,0 +69,0 @@ * IMPORTANT: If providing a `keyFn`, keys *must* be unique for all items in a |
@@ -23,3 +23,3 @@ /** | ||
* expression in the attribute. It takes the property names in the `styleInfo` | ||
* object and adds the property values as CSS propertes. Property names with | ||
* object and adds the property values as CSS properties. Property names with | ||
* dashes (`-`) are assumed to be valid CSS property names and set on the | ||
@@ -26,0 +26,0 @@ * element's style object using `setProperty()`. Names without dashes are |
@@ -19,3 +19,3 @@ /** | ||
*/ | ||
const styleMapCache = new WeakMap(); | ||
const previousStylePropertyCache = new WeakMap(); | ||
/** | ||
@@ -26,3 +26,3 @@ * A directive that applies CSS properties to an element. | ||
* expression in the attribute. It takes the property names in the `styleInfo` | ||
* object and adds the property values as CSS propertes. Property names with | ||
* object and adds the property values as CSS properties. Property names with | ||
* dashes (`-`) are assumed to be valid CSS property names and set on the | ||
@@ -47,12 +47,16 @@ * element's style object using `setProperty()`. Names without dashes are | ||
const { style } = committer.element; | ||
// Handle static styles the first time we see a Part | ||
if (!styleMapCache.has(part)) { | ||
let previousStyleProperties = previousStylePropertyCache.get(part); | ||
if (previousStyleProperties === undefined) { | ||
// Write static styles once | ||
style.cssText = committer.strings.join(' '); | ||
previousStylePropertyCache.set(part, previousStyleProperties = new Set()); | ||
} | ||
// Remove old properties that no longer exist in styleInfo | ||
const oldInfo = styleMapCache.get(part); | ||
for (const name in oldInfo) { | ||
// We use forEach() instead of for-of so that re don't require down-level | ||
// iteration. | ||
previousStyleProperties.forEach((name) => { | ||
if (!(name in styleInfo)) { | ||
previousStyleProperties.delete(name); | ||
if (name.indexOf('-') === -1) { | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
style[name] = null; | ||
@@ -64,7 +68,8 @@ } | ||
} | ||
} | ||
}); | ||
// Add or update properties | ||
for (const name in styleInfo) { | ||
previousStyleProperties.add(name); | ||
if (name.indexOf('-') === -1) { | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
style[name] = styleInfo[name]; | ||
@@ -76,4 +81,3 @@ } | ||
} | ||
styleMapCache.set(part, styleInfo); | ||
}); | ||
//# sourceMappingURL=style-map.js.map |
@@ -62,3 +62,3 @@ /** | ||
// Since a lower-priority value will never overwrite a higher-priority | ||
// synchronous value, we can stop processsing now. | ||
// synchronous value, we can stop processing now. | ||
break; | ||
@@ -65,0 +65,0 @@ } |
@@ -17,3 +17,4 @@ /** | ||
*/ | ||
export const isCEPolyfill = window.customElements !== undefined && | ||
export const isCEPolyfill = typeof window !== 'undefined' && | ||
window.customElements != null && | ||
window.customElements.polyfillWrapFlushCallback !== | ||
@@ -20,0 +21,0 @@ undefined; |
@@ -16,3 +16,3 @@ /** | ||
import { RenderOptions } from './render-options.js'; | ||
export declare type Primitive = null | undefined | boolean | number | string | Symbol | bigint; | ||
export declare type Primitive = null | undefined | boolean | number | string | symbol | bigint; | ||
export declare const isPrimitive: (value: unknown) => value is Primitive; | ||
@@ -22,3 +22,3 @@ export declare const isIterable: (value: unknown) => value is Iterable<unknown>; | ||
* Writes attribute values to the DOM for a group of AttributeParts bound to a | ||
* single attibute. The value is only set once even if there are multiple parts | ||
* single attribute. The value is only set once even if there are multiple parts | ||
* for an attribute. | ||
@@ -110,6 +110,6 @@ */ | ||
readonly name: string; | ||
readonly strings: ReadonlyArray<string>; | ||
readonly strings: readonly string[]; | ||
value: unknown; | ||
private __pendingValue; | ||
constructor(element: Element, name: string, strings: ReadonlyArray<string>); | ||
constructor(element: Element, name: string, strings: readonly string[]); | ||
setValue(value: unknown): void; | ||
@@ -116,0 +116,0 @@ commit(): void; |
@@ -29,3 +29,3 @@ /** | ||
return Array.isArray(value) || | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
!!(value && value[Symbol.iterator]); | ||
@@ -35,3 +35,3 @@ }; | ||
* Writes attribute values to the DOM for a group of AttributeParts bound to a | ||
* single attibute. The value is only set once even if there are multiple parts | ||
* single attribute. The value is only set once even if there are multiple parts | ||
* for an attribute. | ||
@@ -173,2 +173,5 @@ */ | ||
commit() { | ||
if (this.startNode.parentNode === null) { | ||
return; | ||
} | ||
while (isDirective(this.__pendingValue)) { | ||
@@ -370,3 +373,3 @@ const directive = this.__pendingValue; | ||
this.dirty = false; | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
this.element[this.name] = this._getValue(); | ||
@@ -379,20 +382,25 @@ } | ||
// Detect event listener options support. If the `capture` property is read | ||
// from the options object, then options are supported. If not, then the thrid | ||
// from the options object, then options are supported. If not, then the third | ||
// argument to add/removeEventListener is interpreted as the boolean capture | ||
// value so we should only pass the `capture` property. | ||
let eventOptionsSupported = false; | ||
try { | ||
const options = { | ||
get capture() { | ||
eventOptionsSupported = true; | ||
return false; | ||
} | ||
}; | ||
// tslint:disable-next-line:no-any | ||
window.addEventListener('test', options, options); | ||
// tslint:disable-next-line:no-any | ||
window.removeEventListener('test', options, options); | ||
} | ||
catch (_e) { | ||
} | ||
// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch | ||
// blocks right into the body of a module | ||
(() => { | ||
try { | ||
const options = { | ||
get capture() { | ||
eventOptionsSupported = true; | ||
return false; | ||
} | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
window.addEventListener('test', options, options); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
window.removeEventListener('test', options, options); | ||
} | ||
catch (_e) { | ||
// event options not supported | ||
} | ||
})(); | ||
export class EventPart { | ||
@@ -399,0 +407,0 @@ constructor(element, eventName, eventContext) { |
@@ -50,3 +50,3 @@ /** | ||
* | ||
* Safari currently has a bug which occasionally breaks this behaviour, so we | ||
* Safari currently has a bug which occasionally breaks this behavior, so we | ||
* need to cache the Template at two levels. We first cache the | ||
@@ -56,7 +56,7 @@ * TemplateStringsArray, and if that fails, we cache a key constructed by | ||
*/ | ||
export declare type templateCache = { | ||
export interface TemplateCache { | ||
readonly stringsArray: WeakMap<TemplateStringsArray, Template>; | ||
readonly keyString: Map<string, Template>; | ||
}; | ||
export declare const templateCaches: Map<string, templateCache>; | ||
} | ||
export declare const templateCaches: Map<string, TemplateCache>; | ||
//# sourceMappingURL=template-factory.d.ts.map |
@@ -27,5 +27,5 @@ /** | ||
constructor(template: Template, processor: TemplateProcessor, options: RenderOptions); | ||
update(values: ReadonlyArray<unknown>): void; | ||
update(values: readonly unknown[]): void; | ||
_clone(): DocumentFragment; | ||
} | ||
//# sourceMappingURL=template-instance.d.ts.map |
@@ -65,3 +65,3 @@ /** | ||
// | ||
// But Safari dooes not implement CustomElementRegistry#upgrade, so we | ||
// But Safari does not implement CustomElementRegistry#upgrade, so we | ||
// can not implement that order and still have upgrade-before-update and | ||
@@ -68,0 +68,0 @@ // upgrade disconnected fragments. So we instead sacrifice the |
@@ -21,6 +21,6 @@ /** | ||
readonly strings: TemplateStringsArray; | ||
readonly values: ReadonlyArray<unknown>; | ||
readonly values: readonly unknown[]; | ||
readonly type: string; | ||
readonly processor: TemplateProcessor; | ||
constructor(strings: TemplateStringsArray, values: ReadonlyArray<unknown>, type: string, processor: TemplateProcessor); | ||
constructor(strings: TemplateStringsArray, values: readonly unknown[], type: string, processor: TemplateProcessor); | ||
/** | ||
@@ -27,0 +27,0 @@ * Returns a string of HTML used to create a `<template>` element. |
@@ -43,3 +43,3 @@ /** | ||
// parser. The marker type is based on whether the expression is in an | ||
// attribute, text, or comment poisition. | ||
// attribute, text, or comment position. | ||
// * For node-position bindings we insert a comment with the marker | ||
@@ -64,3 +64,3 @@ // sentinel as its text content, like <!--{{lit-guid}}-->. | ||
s.indexOf('-->', commentOpen + 1) === -1; | ||
// Check to see if we have an attribute-like sequence preceeding the | ||
// Check to see if we have an attribute-like sequence preceding the | ||
// expression. This can match "name=value" like structures in text, | ||
@@ -71,3 +71,3 @@ // comments, and attribute values, so there can be false-positives. | ||
// We're only in this branch if we don't have a attribute-like | ||
// preceeding sequence. For comments, this guards against unusual | ||
// preceding sequence. For comments, this guards against unusual | ||
// attribute values like <div foo="<!--${'bar'}">. Cases like | ||
@@ -74,0 +74,0 @@ // <!-- foo=${'bar'}--> are handled correctly in the attribute branch |
@@ -34,3 +34,3 @@ /** | ||
/** | ||
* An updateable Template that tracks the location of dynamic parts. | ||
* An updatable Template that tracks the location of dynamic parts. | ||
*/ | ||
@@ -37,0 +37,0 @@ export declare class Template { |
@@ -30,3 +30,3 @@ /** | ||
/** | ||
* An updateable Template that tracks the location of dynamic parts. | ||
* An updatable Template that tracks the location of dynamic parts. | ||
*/ | ||
@@ -213,3 +213,5 @@ export class Template { | ||
*/ | ||
export const lastAttributeNameRegex = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; | ||
export const lastAttributeNameRegex = | ||
// eslint-disable-next-line no-control-regex | ||
/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; | ||
//# sourceMappingURL=template.js.map |
@@ -47,3 +47,6 @@ /** | ||
// TODO(justinfagnani): inject version number at build time | ||
(window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.2'); | ||
if (typeof window !== 'undefined') { | ||
(window['litHtmlVersions'] || (window['litHtmlVersions'] = [])) | ||
.push('1.2.0-pre.1'); | ||
} | ||
/** | ||
@@ -50,0 +53,0 @@ * Interprets a template literal as an HTML template that can efficiently |
{ | ||
"name": "lit-html", | ||
"version": "1.1.2", | ||
"version": "1.2.0-pre.1", | ||
"description": "HTML template literals in JavaScript", | ||
@@ -10,2 +10,3 @@ "license": "BSD-3-Clause", | ||
"module": "lit-html.js", | ||
"typings": "lit-html.d.ts", | ||
"directories": { | ||
@@ -31,3 +32,4 @@ "test": "test" | ||
"format": "clang-format --version; find src test | grep '\\.js$\\|\\.ts$' | xargs clang-format --style=file -i", | ||
"lint": "tslint --project ./", | ||
"lint": "npm run lint:eslint", | ||
"lint:eslint": "eslint 'src/**/*.{js,ts}'", | ||
"prepublishOnly": "node check-version-tracker.js && npm run lint && npm test", | ||
@@ -38,16 +40,21 @@ "prepare": "npm run build", | ||
"author": "The Polymer Authors", | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"@types/chai": "^4.1.0", | ||
"@types/mocha": "^5.2.0", | ||
"@types/mocha": "^7.0.1", | ||
"@typescript-eslint/eslint-plugin": "^2.10.0", | ||
"@typescript-eslint/parser": "^2.10.0", | ||
"@webcomponents/shadycss": "^1.8.0", | ||
"@webcomponents/webcomponentsjs": "^2.0.4", | ||
"@webcomponents/webcomponentsjs": "^2.4.2", | ||
"chai": "^4.1.2", | ||
"clang-format": "^1.2.4", | ||
"clang-format": "~1.2.4", | ||
"eslint": "^6.7.0", | ||
"husky": "^3.1.0", | ||
"lint-staged": "^9.5.0", | ||
"lit-html-benchmarks": "^0.2.1", | ||
"mocha": "^5.2.0", | ||
"rollup": "^0.64.1", | ||
"rollup-plugin-filesize": "^4.0.1", | ||
"rollup-plugin-terser": "^1.0.1", | ||
"tachometer": "^0.4.1", | ||
"tslint": "^5.11.0", | ||
"mocha": "^7.0.1", | ||
"rollup": "^1.19.0", | ||
"rollup-plugin-filesize": "^6.2.0", | ||
"rollup-plugin-terser": "^5.2.0", | ||
"tachometer": "^0.4.15", | ||
"typescript": "^3.4.1", | ||
@@ -58,4 +65,13 @@ "uglify-es": "^3.3.5", | ||
}, | ||
"typings": "lit-html.d.ts", | ||
"dependencies": {} | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"src/**/*.{js,ts}": [ | ||
"eslint --fix", | ||
"git add" | ||
] | ||
} | ||
} |
@@ -20,3 +20,3 @@ /** | ||
* do NOT work with this polyfill. | ||
* If it can not fullfill your requirement, please consider using the full | ||
* If it can not fulfill your requirement, please consider using the full | ||
* polyfill: https://github.com/webcomponents/template | ||
@@ -23,0 +23,0 @@ */ |
@@ -21,3 +21,3 @@ /** | ||
* do NOT work with this polyfill. | ||
* If it can not fullfill your requirement, please consider using the full | ||
* If it can not fulfill your requirement, please consider using the full | ||
* polyfill: https://github.com/webcomponents/template | ||
@@ -42,6 +42,6 @@ */ | ||
Object.defineProperties(template, { | ||
content: Object.assign({}, descriptor, { get() { | ||
content: Object.assign(Object.assign({}, descriptor), { get() { | ||
return content; | ||
} }), | ||
innerHTML: Object.assign({}, descriptor, { set: function (text) { | ||
innerHTML: Object.assign(Object.assign({}, descriptor), { set: function (text) { | ||
body.innerHTML = text; | ||
@@ -48,0 +48,0 @@ removeNodes(content, content.firstChild); |
@@ -6,2 +6,3 @@ # lit-html | ||
[![Published on npm](https://img.shields.io/npm/v/lit-html.svg)](https://www.npmjs.com/package/lit-html) | ||
[![Join our Slack](https://img.shields.io/badge/slack-join%20chat-4a154b.svg)](https://www.polymer-project.org/slack-invite) | ||
[![Mentioned in Awesome lit-html](https://awesome.re/mentioned-badge.svg)](https://github.com/web-padawan/awesome-lit-html) | ||
@@ -8,0 +9,0 @@ |
@@ -19,6 +19,6 @@ /** | ||
type CachedTemplate = { | ||
readonly instance: TemplateInstance, | ||
readonly nodes: DocumentFragment | ||
}; | ||
interface CachedTemplate { | ||
readonly instance: TemplateInstance; | ||
readonly nodes: DocumentFragment; | ||
} | ||
const templateCaches = | ||
@@ -25,0 +25,0 @@ new WeakMap<NodePart, WeakMap<Template, CachedTemplate>>(); |
@@ -17,3 +17,34 @@ /** | ||
// IE11 doesn't support classList on SVG elements, so we emulate it with a Set | ||
class ClassList { | ||
element: Element; | ||
classes: Set<string> = new Set(); | ||
changed = false; | ||
constructor(element: Element) { | ||
this.element = element; | ||
const classList = (element.getAttribute('class') || '').split(/\s+/); | ||
for (const cls of classList) { | ||
this.classes.add(cls); | ||
} | ||
} | ||
add(cls: string) { | ||
this.classes.add(cls); | ||
this.changed = true; | ||
} | ||
remove(cls: string) { | ||
this.classes.delete(cls); | ||
this.changed = true; | ||
} | ||
commit() { | ||
if (this.changed) { | ||
let classString = ''; | ||
this.classes.forEach((cls) => classString += cls + ' '); | ||
this.element.setAttribute('class', classString); | ||
} | ||
} | ||
} | ||
export interface ClassInfo { | ||
@@ -27,3 +58,3 @@ readonly [name: string]: string|boolean|number; | ||
*/ | ||
const classMapCache = new WeakMap(); | ||
const previousClassesCache = new WeakMap<Part, Set<string>>(); | ||
@@ -34,5 +65,4 @@ /** | ||
* property in the `classInfo` argument and adds the property name to the | ||
* element's `classList` if the property value is truthy; if the property value | ||
* is falsey, the property name is removed from the element's `classList`. For | ||
* example | ||
* element's `class` if the property value is truthy; if the property value is | ||
* falsey, the property name is removed from the element's `class`. For example | ||
* `{foo: bar}` applies the class `foo` if the value of `bar` is truthy. | ||
@@ -52,28 +82,41 @@ * @param classInfo {ClassInfo} | ||
// handle static classes | ||
if (!classMapCache.has(part)) { | ||
element.className = committer.strings.join(' '); | ||
let previousClasses = previousClassesCache.get(part); | ||
if (previousClasses === undefined) { | ||
// Write static classes once | ||
// Use setAttribute() because className isn't a string on SVG elements | ||
element.setAttribute('class', committer.strings.join(' ')); | ||
previousClassesCache.set(part, previousClasses = new Set()); | ||
} | ||
const {classList} = element; | ||
const classList = | ||
(element.classList || new ClassList(element)) as DOMTokenList | ClassList; | ||
// remove old classes that no longer apply | ||
const oldInfo = classMapCache.get(part); | ||
for (const name in oldInfo) { | ||
// Remove old classes that no longer apply | ||
// We use forEach() instead of for-of so that re don't require down-level | ||
// iteration. | ||
previousClasses.forEach((name) => { | ||
if (!(name in classInfo)) { | ||
classList.remove(name); | ||
previousClasses!.delete(name); | ||
} | ||
} | ||
}); | ||
// add new classes | ||
// Add or remove classes based on their classMap value | ||
for (const name in classInfo) { | ||
const value = classInfo[name]; | ||
if (!oldInfo || value !== oldInfo[name]) { | ||
// We explicitly want a loose truthy check here because | ||
// it seems more convenient that '' and 0 are skipped. | ||
const method = value ? 'add' : 'remove'; | ||
classList[method](name); | ||
if (value != previousClasses.has(name)) { | ||
// We explicitly want a loose truthy check of `value` because it seems | ||
// more convenient that '' and 0 are skipped. | ||
if (value) { | ||
classList.add(name); | ||
previousClasses.add(name); | ||
} else { | ||
classList.remove(name); | ||
previousClasses.delete(name); | ||
} | ||
} | ||
} | ||
classMapCache.set(part, classInfo); | ||
if (typeof (classList as ClassList).commit === 'function') { | ||
(classList as ClassList).commit(); | ||
} | ||
}); |
@@ -17,2 +17,4 @@ /** | ||
const previousValues = new WeakMap<Part, unknown>(); | ||
/** | ||
@@ -25,10 +27,16 @@ * For AttributeParts, sets the attribute if the value is defined and removes | ||
export const ifDefined = directive((value: unknown) => (part: Part) => { | ||
const previousValue = previousValues.get(part); | ||
if (value === undefined && part instanceof AttributePart) { | ||
if (value !== part.value) { | ||
// If the value is undefined, remove the attribute, but only if the value | ||
// was previously defined. | ||
if (previousValue !== undefined || !previousValues.has(part)) { | ||
const name = part.committer.name; | ||
part.committer.element.removeAttribute(name); | ||
} | ||
} else { | ||
} else if (value !== previousValue) { | ||
part.setValue(value); | ||
} | ||
previousValues.set(part, value); | ||
}); |
@@ -81,3 +81,3 @@ /** | ||
* way to use `repeat` since it performs minimum unnecessary work for insertions | ||
* amd removals. | ||
* and removals. | ||
* | ||
@@ -84,0 +84,0 @@ * IMPORTANT: If providing a `keyFn`, keys *must* be unique for all items in a |
@@ -25,3 +25,3 @@ /** | ||
*/ | ||
const styleMapCache = new WeakMap<AttributePart, StyleInfo>(); | ||
const previousStylePropertyCache = new WeakMap<AttributePart, Set<string>>(); | ||
@@ -33,3 +33,3 @@ /** | ||
* expression in the attribute. It takes the property names in the `styleInfo` | ||
* object and adds the property values as CSS propertes. Property names with | ||
* object and adds the property values as CSS properties. Property names with | ||
* dashes (`-`) are assumed to be valid CSS property names and set on the | ||
@@ -57,13 +57,18 @@ * element's style object using `setProperty()`. Names without dashes are | ||
// Handle static styles the first time we see a Part | ||
if (!styleMapCache.has(part)) { | ||
let previousStyleProperties = previousStylePropertyCache.get(part); | ||
if (previousStyleProperties === undefined) { | ||
// Write static styles once | ||
style.cssText = committer.strings.join(' '); | ||
previousStylePropertyCache.set(part, previousStyleProperties = new Set()); | ||
} | ||
// Remove old properties that no longer exist in styleInfo | ||
const oldInfo = styleMapCache.get(part); | ||
for (const name in oldInfo) { | ||
// We use forEach() instead of for-of so that re don't require down-level | ||
// iteration. | ||
previousStyleProperties.forEach((name) => { | ||
if (!(name in styleInfo)) { | ||
previousStyleProperties!.delete(name); | ||
if (name.indexOf('-') === -1) { | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(style as any)[name] = null; | ||
@@ -74,8 +79,9 @@ } else { | ||
} | ||
} | ||
}); | ||
// Add or update properties | ||
for (const name in styleInfo) { | ||
previousStyleProperties.add(name); | ||
if (name.indexOf('-') === -1) { | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(style as any)[name] = styleInfo[name]; | ||
@@ -86,3 +92,2 @@ } else { | ||
} | ||
styleMapCache.set(part, styleInfo); | ||
}); |
@@ -78,3 +78,3 @@ /** | ||
// Since a lower-priority value will never overwrite a higher-priority | ||
// synchronous value, we can stop processsing now. | ||
// synchronous value, we can stop processing now. | ||
break; | ||
@@ -81,0 +81,0 @@ } |
@@ -9,4 +9,3 @@ interface ShadyCSS { | ||
ScopingShim: undefined|{ | ||
prepareAdoptedCssText( | ||
cssTextArray: Array<string>, elementName: string): void; | ||
prepareAdoptedCssText(cssTextArray: string[], elementName: string): void; | ||
}; | ||
@@ -13,0 +12,0 @@ } |
@@ -23,3 +23,3 @@ /** | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type DirectiveFactory = (...args: any[]) => object; | ||
@@ -26,0 +26,0 @@ |
@@ -26,3 +26,4 @@ /** | ||
*/ | ||
export const isCEPolyfill = window.customElements !== undefined && | ||
export const isCEPolyfill = typeof window !== 'undefined' && | ||
window.customElements != null && | ||
(window.customElements as MaybePolyfilledCe).polyfillWrapFlushCallback !== | ||
@@ -29,0 +30,0 @@ undefined; |
@@ -91,3 +91,3 @@ /** | ||
const nextActiveIndexInTemplateParts = | ||
(parts: TemplatePart[], startIndex: number = -1) => { | ||
(parts: TemplatePart[], startIndex = -1) => { | ||
for (let i = startIndex + 1; i < parts.length; i++) { | ||
@@ -94,0 +94,0 @@ const part = parts[i]; |
@@ -28,3 +28,3 @@ /** | ||
// https://tc39.github.io/ecma262/#sec-typeof-operator | ||
export type Primitive = null|undefined|boolean|number|string|Symbol|bigint; | ||
export type Primitive = null|undefined|boolean|number|string|symbol|bigint; | ||
export const isPrimitive = (value: unknown): value is Primitive => { | ||
@@ -37,3 +37,3 @@ return ( | ||
return Array.isArray(value) || | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
!!(value && (value as any)[Symbol.iterator]); | ||
@@ -44,3 +44,3 @@ }; | ||
* Writes attribute values to the DOM for a group of AttributeParts bound to a | ||
* single attibute. The value is only set once even if there are multiple parts | ||
* single attribute. The value is only set once even if there are multiple parts | ||
* for an attribute. | ||
@@ -207,2 +207,5 @@ */ | ||
commit() { | ||
if (this.startNode.parentNode === null) { | ||
return; | ||
} | ||
while (isDirective(this.__pendingValue)) { | ||
@@ -351,7 +354,7 @@ const directive = this.__pendingValue; | ||
readonly name: string; | ||
readonly strings: ReadonlyArray<string>; | ||
readonly strings: readonly string[]; | ||
value: unknown = undefined; | ||
private __pendingValue: unknown = undefined; | ||
constructor(element: Element, name: string, strings: ReadonlyArray<string>) { | ||
constructor(element: Element, name: string, strings: readonly string[]) { | ||
if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') { | ||
@@ -424,3 +427,3 @@ throw new Error( | ||
this.dirty = false; | ||
// tslint:disable-next-line:no-any | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
(this.element as any)[this.name] = this._getValue(); | ||
@@ -434,3 +437,3 @@ } | ||
// Detect event listener options support. If the `capture` property is read | ||
// from the options object, then options are supported. If not, then the thrid | ||
// from the options object, then options are supported. If not, then the third | ||
// argument to add/removeEventListener is interpreted as the boolean capture | ||
@@ -440,17 +443,21 @@ // value so we should only pass the `capture` property. | ||
try { | ||
const options = { | ||
get capture() { | ||
eventOptionsSupported = true; | ||
return false; | ||
} | ||
}; | ||
// tslint:disable-next-line:no-any | ||
window.addEventListener('test', options as any, options); | ||
// tslint:disable-next-line:no-any | ||
window.removeEventListener('test', options as any, options); | ||
} catch (_e) { | ||
} | ||
// Wrap into an IIFE because MS Edge <= v41 does not support having try/catch | ||
// blocks right into the body of a module | ||
(() => { | ||
try { | ||
const options = { | ||
get capture() { | ||
eventOptionsSupported = true; | ||
return false; | ||
} | ||
}; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
window.addEventListener('test', options as any, options); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
window.removeEventListener('test', options as any, options); | ||
} catch (_e) { | ||
// event options not supported | ||
} | ||
})(); | ||
type EventHandlerWithOptions = | ||
@@ -457,0 +464,0 @@ EventListenerOrEventListenerObject&Partial<AddEventListenerOptions>; |
@@ -86,3 +86,3 @@ /** | ||
* | ||
* Safari currently has a bug which occasionally breaks this behaviour, so we | ||
* Safari currently has a bug which occasionally breaks this behavior, so we | ||
* need to cache the Template at two levels. We first cache the | ||
@@ -92,7 +92,7 @@ * TemplateStringsArray, and if that fails, we cache a key constructed by | ||
*/ | ||
export type templateCache = { | ||
readonly stringsArray: WeakMap<TemplateStringsArray, Template>; // | ||
export interface TemplateCache { | ||
readonly stringsArray: WeakMap<TemplateStringsArray, Template>; | ||
readonly keyString: Map<string, Template>; | ||
}; | ||
} | ||
export const templateCaches = new Map<string, templateCache>(); | ||
export const templateCaches = new Map<string, TemplateCache>(); |
@@ -43,3 +43,3 @@ /** | ||
update(values: ReadonlyArray<unknown>) { | ||
update(values: readonly unknown[]) { | ||
let i = 0; | ||
@@ -80,3 +80,3 @@ for (const part of this.__parts) { | ||
// | ||
// But Safari dooes not implement CustomElementRegistry#upgrade, so we | ||
// But Safari does not implement CustomElementRegistry#upgrade, so we | ||
// can not implement that order and still have upgrade-before-update and | ||
@@ -83,0 +83,0 @@ // upgrade disconnected fragments. So we instead sacrifice the |
@@ -31,3 +31,3 @@ /** | ||
readonly strings: TemplateStringsArray; | ||
readonly values: ReadonlyArray<unknown>; | ||
readonly values: readonly unknown[]; | ||
readonly type: string; | ||
@@ -37,4 +37,4 @@ readonly processor: TemplateProcessor; | ||
constructor( | ||
strings: TemplateStringsArray, values: ReadonlyArray<unknown>, | ||
type: string, processor: TemplateProcessor) { | ||
strings: TemplateStringsArray, values: readonly unknown[], type: string, | ||
processor: TemplateProcessor) { | ||
this.strings = strings; | ||
@@ -59,3 +59,3 @@ this.values = values; | ||
// parser. The marker type is based on whether the expression is in an | ||
// attribute, text, or comment poisition. | ||
// attribute, text, or comment position. | ||
// * For node-position bindings we insert a comment with the marker | ||
@@ -80,3 +80,3 @@ // sentinel as its text content, like <!--{{lit-guid}}-->. | ||
s.indexOf('-->', commentOpen + 1) === -1; | ||
// Check to see if we have an attribute-like sequence preceeding the | ||
// Check to see if we have an attribute-like sequence preceding the | ||
// expression. This can match "name=value" like structures in text, | ||
@@ -87,3 +87,3 @@ // comments, and attribute values, so there can be false-positives. | ||
// We're only in this branch if we don't have a attribute-like | ||
// preceeding sequence. For comments, this guards against unusual | ||
// preceding sequence. For comments, this guards against unusual | ||
// attribute values like <div foo="<!--${'bar'}">. Cases like | ||
@@ -90,0 +90,0 @@ // <!-- foo=${'bar'}--> are handled correctly in the attribute branch |
@@ -41,3 +41,3 @@ /** | ||
/** | ||
* An updateable Template that tracks the location of dynamic parts. | ||
* An updatable Template that tracks the location of dynamic parts. | ||
*/ | ||
@@ -218,5 +218,9 @@ export class Template { | ||
export type TemplatePart = { | ||
readonly type: 'node', | ||
index: number | ||
}|{readonly type: 'attribute', index: number, readonly name: string, readonly strings: ReadonlyArray<string>}; | ||
readonly type: 'node'; index: number; | ||
}|{ | ||
readonly type: 'attribute'; | ||
index: number; | ||
readonly name: string; | ||
readonly strings: ReadonlyArray<string>; | ||
}; | ||
@@ -256,2 +260,3 @@ export const isTemplatePartActive = (part: TemplatePart) => part.index !== -1; | ||
export const lastAttributeNameRegex = | ||
// eslint-disable-next-line no-control-regex | ||
/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/; |
@@ -59,3 +59,6 @@ /** | ||
// TODO(justinfagnani): inject version number at build time | ||
(window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.2'); | ||
if (typeof window !== 'undefined') { | ||
(window['litHtmlVersions'] || (window['litHtmlVersions'] = [])) | ||
.push('1.2.0-pre.1'); | ||
} | ||
@@ -62,0 +65,0 @@ /** |
@@ -23,3 +23,3 @@ /** | ||
* do NOT work with this polyfill. | ||
* If it can not fullfill your requirement, please consider using the full | ||
* If it can not fulfill your requirement, please consider using the full | ||
* polyfill: https://github.com/webcomponents/template | ||
@@ -26,0 +26,0 @@ */ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
572941
158
7593
48
0
21
1