Socket
Socket
Sign inDemoInstall

lit-html

Package Overview
Dependencies
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.4.0 to 0.5.0

api.md

12

package.json
{
"name": "lit-html",
"version": "0.4.0",
"version": "0.5.0",
"description": "HTML template literals in JavaScript",
"license": "BSD-3-Clause",
"repository": "PolymerLabs/lit-html",
"main": "lib/lit-html.js",
"module": "lib/lit-html.js",
"main": "lit-html.js",
"module": "lit-html.js",
"directories": {

@@ -19,2 +19,3 @@ "test": "test"

"@types/chai": "^4.0.1",
"@types/mocha": "^2.2.41",
"chai": "^4.0.2",

@@ -24,6 +25,3 @@ "mocha": "^3.4.2",

},
"dependencies": {
"@types/mocha": "^2.2.41"
},
"typings": "./lib/lit-html.d.ts"
"typings": "lit-html.d.ts"
}
# lit-html
HTML template literals in JavaScript
HTML templates, via JavaScript template literals
`lit-html` lets you describe HTML templates with JavaScript template literals, and efficiently render and re-render those templates to DOM.
## Overview
## Example
`lit-html` lets you write [HTML templates](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) with JavaScript [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), and efficiently render and _re-render_ those templates to DOM.
```javascript
const sayHello = (name) => html`<div>Hello ${name}!</div>`;
`lit-html` provides two main exports:
const container = document.querySelector('#container');
render(sayHello('Steve'), container);
// renders <div>Hello Steve!</div> to container
* `html`: A JavaScript [template tag](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals) used to produce a `TemplateResult`, which is a container for a template, and the values that should populate the template.
* `render()`: A function that renders a `TemplateResult` to a DOM container, such as an element or shadow root.
render(sayHello('Kevin'), container);
// updates to <div>Hello Kevin!</div>, but only updates the ${name} part
```
### Examples
## Why
`lit-html` can be used standalone and directly to help manage some DOM:
```javascript
const helloTemplate = (name) => html`<div>Hello ${name}!</div>`;
`lit-html` has four main goals:
// renders <div>Hello Steve!</div> to the document body
render(helloTemplate('Steve'), document.body);
1. Efficient updates of previously rendered DOM.
2. Easy access the JavaScript state that needs to be injected into DOM.
3. Standard syntax without required build steps, understandable by standards-compliant tools.
4. Very small size.
Goal 1 motivate `lit-html`'s method of creating HTML `<template>`s with markers for dynamic sections, rather than the final DOM tree.
For real-world template use-cases, updating existing DOM is just as important as creating the initial DOM. Using JavaScript template literals without a helper like `lit-html` makes it easy to create the initial DOM, but offers no help in efficiently updating it. Developer must either manually find dynamic nodes and update them, or re-render the entire tree by setting `innerHTML`.
Even previous HTML-in-JS proposals like E4X were only concerned with creating a static DOM tree with expression values already interpolated into the contents. That's again, good for initial rendering and not so good for updates.
`lit-html` is able to preserve the static vs dynamic content distinction that JavaScript template literal syntax makes clear, so it can only update the dynamic parts of a template, completely skipping the static parts on re-renders.
This should offer a performance advantage even against VDOM approaches, as most VDOM libraries do not make a distinction between static and dynamic context. The VDOM trees represent the final desired state and then the whole tree is reconciled against a previous state.
Goal 2 drives `lit-html` to HTML-in-JS rather than expressions-in-HTML. Any JavaScript expression can be used in a template, from any scope available where the template is defined.
Goal 3 makes tempalte literals an obvious choice over non-standard syntax like JSX.
Goal 4 is partially acheived by leveraging the built in JavaScript and HTML parsers and not doing anything that would impede using them.
## Status
`lit-html` is very new, under initial development, and not production-ready.
* It uses JavaScript modules, and there's no build set up yet, so out-of-the-box it only runs in Safari 10.1 and Chrome Canary (with the Experimental Web Platform features flag on).
* It has a growing test suite, but it has only been run manually on Chrome Canary, Safari 10.1 and Firefox 54 with modules enabled.
* Much more test coverage is needed for complex templates, especially template composition and Function and Iterable values.
* It has not been benchmarked thouroughly yet.
* The API is likely to change.
Even without a build configuration, `lit-html` minified with `babili` and gzipped measures in at less than 1.5k. We will strive to keep the size extremely small.
## How it Works
`html` does not return DOM nodes, unlike many other HTML with tagged template literal examples, but returns a `TemplateResult` - an object that contains a template and the values from expressions in the template - which can then be used to create or update DOM.
The template is created only the first time `html` is called on a particular template literal. On every subsequent call of `html` on the same template literal the exact same template is returned, only the values change.
To call `html` multiple times on the same template literal, it'll usually be placed in a function:
```javascript
let count = 1;
const countTemplate = () => html`count: ${count++}`;
// updates to <div>Hello Kevin!</div>, but only updates the ${name} part
render(helloTemplate('Kevin'), document.body);
```
The template object is based on an actual HTML `<template>` element and created by setting it's `innerHTML`, utilizing the browser's HTML parser. The HTML is not created by concatenating the string literals expression values, but by joining the literal parts with special markers. The template object finds and remembers the locations of the markers (called "parts"). This makes the system safer from XSS attacks: a value bound to an attribute can't close the attribute, text content is automatically escaped, etc.
But may also be common to use `lit-html` with a component system that calls `render()` for you, similar to React components:
When a template is rendered it is cloned along with the part metadata. Values are set via `setAttribute()` and `textContent`. Some state is stored on the container to indicate that a template was already rendered there. Subsequent renders use that state to update only the dynamic parts, not the entire template instance.
### Rough Algorithm Outline
#### `html`:
1. `html` is invoked with `strings` and `values`.
`strings` are the string literal parts as a `TemplateStringsArray`. The same instance is returned for every evaluation of a particular template literal.
2. Look up a cached template keyed by `strings`, otherwise...
3. Create a new template:
1. Join `strings` with a special marker, `{{}}`. This creates a template string that looks like a Polymer template with empty expressions.
2. Create a new `<template>` element and set its `innerHTML` to the generated template string.
3. Crawl the `<template>` contents, looking for markers and remember their location by index in `Part` objects. Text-content expressions create new empty text nodes which are used as placeholders.
4. Return a `TemplateResult` with the template and the values.
#### `render(result, container)`:
1. Look for an existing `TemplateInstance` on `container`
2. If an instance exists, check that it's from the same `Template` as this `TemplateResult`
3. If the instance is not from the same `Template`, remove its content from `container`.
4. If an instance doesn't exist for the node, create one from the `Template`:
1. Clone the `Template`'s `<template>` contents.
2. Iterate through the cloned nodes and create new "instance parts" for nodes that have `Part`s. An "instance part" is just a {part, node} record.
5. Update. For every `Part`:
1. If it's an `AttributePart`, build up an attibute value then set the attribute.
2. If it's a `NodePart`, get the value (trampoline thunks, render nested templates, etc), then either append a document fragment or set the `textContent`.
6. If this is the first render, append the result DOM to `container`.
## Use in Components
HTML templates could easily be the basis for component rendering, similar to JSX in React. A component base class can call an instance method that returns a `TemplateResult` and then apply it to the shadow root:
_(this example uses JS Class Fields, an upcoming specification)_
```javascript
class MyElement extends CoolBaseElement {
class MyElement extends CoolLitMixin(HTMLElement) {
static get observedProperties() {
return ['message', 'name'];
}
static observedProperties = ['message', 'name'];

@@ -129,69 +37,73 @@ title = `About lit-html`;

render() { return html`
<h1>${this.title}</h1>
<p>${this.body}</p>
`;}
// Called by the base-class when properties change, result is passed
// to lit-html's render() function.
render() {
return html`
<h1>${this.title}</h1>
<p>${this.body}</p>
`;
}
}
```
## Benefits over HTML templates
## Motivation
`lit-html` has basically all of the benefits of HTML-in-JS systems like JSX, like:
`lit-html` has four main goals:
### Lighter weight
1. Efficient updates of previously rendered DOM.
2. Expressiveness and easy access the JavaScript state that needs to be injected into DOM.
3. Standard JavaScript without required build steps, understandable by standards-compliant tools.
4. Very small size.
There's no need to load an expression parser and evaluator.
## How it Works
### Seamless access to data
`lit-html` utilizes some unique properties of HTML `<template>` elements and JavaScript tmplate literals. So it's helpful to understand them first.
Since template literals are evaluated in JavaScript, their expressions have access to every variable in that scope, including globals, module and block scopes, and `this` inside methods.
### Tagged Template Literals
If the main use of templates is to inject values into HTML, this breaks down a major barrier between templates and values.
A JavaScript template literal is a string literal that can have other JavaScript expressions embedded in it:
### Faster expression evaluation
```javascript
`My name is ${name}.`
```
They're just JavaScript expressions.
A _tagged_ template literal is preceded by a special template tag function:
### IDE support by default
```javascript
let name = 'Monica';
tag`My name is ${name}.`
```
In a type-checking environment like TypeScript, expressions are checked because they are just regular script. Hover-over docs and code-completion just work as well.
Tags are functions of the form: `tag(strings, ...values)`, where `strings` is an immutable array of the literal parts, and values are the results of the embedded expressions.
### Case-sensitive parsing
In the preceding example, `strings` would be `['My name is ', '.']`, and `values` would be `['Monica']`.
Template literals preserve case, even though the HTML parser doesn't for attribute names. `lit-html` extracts the raw attribute names, which is useful for template syntaxes that use attribute syntax to set properties on elements.
### HTML `<template>` Elements
## Benefits over JSX
A `<template>` element is an inert tree of DOM (script don't run, images don't load, custom elements aren't upgraded, etc) that can be efficiently cloned. It's usually used to tell the HTML parser that a section of the document must not be instantiated when parsed, but by code at a later time, but it can also be created imperatively with `createElement` and `innerHTML`.
### Native syntax
### Template Creation
No tooling required. Understood by all JS editors and tools.
The first time `html` is called on a particular template literal it does one-time setup work to create the template. It joins all the string parts with a special placeholder, `"{{}}"`, then creates a `<template>` and sets its `innherHTML` to the result. The it walks the template's DOM and extracts the placeholder and remembers their location.
### No VDOM overhead
Every call to `html` returns a `TemplateResult` which contains the template created on the first call, and the expression values for the current call.
`lit-html` only re-renders the dynamic parts of a template, so it doesn't produce a VDOM tree of the entire template contents, it just produces new values for each expression. By completely skipping static template parts, it saves work.
### Template Rendering
### Scoped
`render()` takes a `TemplateResult` and renders it to a DOM container. On the initial render it clones the template, then walks it using the remembered placeholder positions, to create `Part`s.
JSX requires that the compiler be configured with the function to compile tags to. You can't mix two different JSX configurations in the same file.
A `Part` is a "hole" in the DOM where values can be injected. `lit-html` includes two type of parts by default: `NodePart` and `AttributePart`, which let you set text content and attribute values respectively. The `Part`s, container, and template they were created from are grouped together in an object called a `TemplateInstance`.
The `html` template tag is just a variable, probably an imported function. You can have any number of similar functions in the same JS scope, or set `html` to different implementations.
Rendering can be customized by providing alternate `render()` implementations whcih create different kinds of `TemplateInstances` and `Part`s, like `PropertyPart` and `EventPart` included in `lib/lit-extended.ts` which let templates set properties and event handlers on elements.
### Templates are values
## Performance
JSX translates to function calls, and can't be manipulated on a per-template basis at runtime. `lit-html` produces a template object at runtime, which can be further processed by libraries like ShadyCSS.
`lit-html` is designed to be lightweight and fast (though performance benchmarking is just starting).
### CSS-compatible syntax
* It utilizies the built-in JS and HTML parsers - it doesn't include any expression or markup parser of it's own.
* It only updates the dynamic parts of templates - static parts are untouched, not even walked for diffing, after the initial render.
* It uses cloning for initial render.
Because template literals use `${}` as the expression delimiter, CSS's use of `{}` isn't interpreted as an expression. You can include style tags in your templates as you would expect:
This should make the approach generally fast and small. Actual science and optimization and still TODOs at this time.
```javascript
html`
<style>
:host {
background: burlywood;
}
</style>
`
```
## Features

@@ -217,2 +129,4 @@

_TODO: Add sanitization hooks to disallow inline event handlers, etc._
### Case-sensitive Attribute Names

@@ -227,13 +141,2 @@

### Functions/Thunks
A function value is called with no arguments, in a try/catch block to be safe from exceptions:
```javascript
let data;
const render = () => html`foo = ${_=>data.foo}`;
```
Here, `data.foo` throws because `data` is undefined, but the rest of the template renders.
### Arrays/Iterables

@@ -265,10 +168,72 @@

These features compose so you can include iterables of thunks that return arrays of nested templates, etc...
### Function Values / Directives
A function valued expression can be used for error handling and stateful rendering.
If an expression returns a function, the function is called with the `Part` its populating, inside a try/catch block.
This makes it safe from exceptions:
```javascript
let data;
const render = () => html`foo = ${_=>data.foo}`;
```
Here, `data.foo` throws because `data` is undefined, but the rest of the template renders.
And is a useful extension point:
const render = () => html`<div>${(part) => part.setValue((part.previousValue + 1) || 0)}</div>`;
lit-html includes a few directives:
#### `repeat(items, keyfn, template)`
A loop that supports efficient re-ordering by using item keys.
Example:
```javascript
const render = () => html`
<ul>
${repeat(items, (i) => i.id, (i, index) => html`
<li>${index}: ${i.name}</li>`)}
</ul>
`;
```
#### `until(promise, defaultContent)`
Renders `defaultContent` until `promise` resolves, then it renders the resolved value of `promise`.
Example:
```javascript
const render = () => html`
<p>
${until(
fetch('content.txt').then((r) => r.text()),
html`<span>Loading...</span>`)}
</p>
`;
```
### Promises
Promises are rendered when they resolve, leaving the previous value in place until they do. Races are handled, so that if an unresolved Promise is overwritten, it won't update the template when it finally resolves.
```javascript
const render = () => html`
The response is ${fetch('sample.txt').then((r) => r.text())}.
`;
```
### Composability
These features compose so you can render iterables of functions that return arrays of nested templates, etc...
### Extensibility
`lit-html` is designed to be extended by more opinionated flavors of template syntaxes. For instance, `lit-html` doesn't support declarative event handlers or property setting out-of-the-box. A layer on top can add that while exposing the same API, by wrapping the `html` tag in a new tag and modifying the result.
`lit-html` is designed to be extended by more opinionated flavors of template syntaxes. For instance, `lit-html` doesn't support declarative event handlers or property setting out-of-the-box. A layer on top can add that while exposing the same API, by implementing a custom `render()` function.
This is accomplished by allowing the `TemplatePart`s of a template, which are responsible for setting new values into the DOM, to be replaced with new implementations.
Some examples of possible extensions:

@@ -280,54 +245,80 @@

### Small Size
## Status
`lit-html` is less than 1.5k minified and gzipped.
`lit-html` is very new, under initial development, and not production-ready.
## API
* It uses JavaScript modules, and there's no build set up yet, so out-of-the-box it only runs in Safari 10.1, Chrome Canary (coming in 61), and Firefox 54 (behind a flag).
* It has a growing test suite, but it has only been run manually on Chrome Canary, Safari 10.1 and Firefox 54.
* Much more test coverage is needed for complex templates, especially template composition and Function and Iterable values.
* It has not been benchmarked thouroughly yet.
* The API may change.
### Function `html`
Even without a build configuration, `lit-html` minified with `babili` and gzipped measures in at less than 1.7k. We will strive to keep the size extremely small.
`html(callSite: TemplateStringsArray, ...expressions: any[]): TemplateResult`
## Benefits over HTML templates
`html` is a template tag for [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), which parses the literal as HTML and returns a `TemplateResult`.
`lit-html` has basically all of the benefits of HTML-in-JS systems like JSX, like:
### Class `TemplateResult`
### Lighter weight
`TemplateResult` is a class that holds a `Template` object parsed from a template literal and the values from its expressions.
There's no need to load an expression parser and evaluator.
* Property `template: Template`
### Seamless access to data
A reference to the parsed `Template` object.
Since template literals are evaluated in JavaScript, their expressions have access to every variable in that scope, including globals, module and block scopes, and `this` inside methods.
* Property `values: any[]`
If the main use of templates is to inject values into HTML, this breaks down a major barrier between templates and values.
The values returned by the template literal's expressions.
### Faster expression evaluation
### Function `render(result: TemplateResult, container: Element): void`
They're just JavaScript expressions.
Renders a `TemplateResult`'s template to an element using the result's values. For re-renders, only the dynamic parts are updated.
### IDE support by default
### Class `Template`
In a type-checking environment like TypeScript, expressions are checked because they are just regular script. Hover-over docs and code-completion just work as well.
* Property `element: HTMLTemplateElement`
### Case-sensitive parsing
* Property `parts: Part[]`
Template literals preserve case, even though the HTML parser doesn't for attribute names. `lit-html` extracts the raw attribute names, which is useful for template syntaxes that use attribute syntax to set properties on elements.
### Abstract Class `Part`
## Benefits over JSX
A `Part` is a dynamic section of a `TemplateInstance`. It's value can be set to update the section.
### Native syntax
Specially support value types are `Node`, `Function`, and `TemplateResult`.
No tooling required. Understood by all JS editors and tools.
* Method `setValue(value: any): void`
### No VDOM overhead
## Future Work
`lit-html` only re-renders the dynamic parts of a template, so it doesn't produce a VDOM tree of the entire template contents, it just produces new values for each expression. By completely skipping static template parts, it saves work.
### Stateful Values
### Scoped
In order to support stateful repeat/if like `dom-repeat` and `dom-if` a value should be able to control it's rendering somewhat. TBD.
JSX requires that the compiler be configured with the function to compile tags to. You can't mix two different JSX configurations in the same file.
### Async Support
The `html` template tag is just a variable, probably an imported function. You can have any number of similar functions in the same JS scope, or set `html` to different implementations.
Promises and Async Iterables should be supported natively.
### Templates are values
JSX translates to function calls, and can't be manipulated on a per-template basis at runtime. `lit-html` produces a template object at runtime, which can be further processed by libraries like ShadyCSS.
### CSS-compatible syntax
Because template literals use `${}` as the expression delimiter, CSS's use of `{}` isn't interpreted as an expression. You can include style tags in your templates as you would expect:
```javascript
html`
<style>
:host {
background: burlywood;
}
</style>
`
```
## Future Work
### Async Iterables Support
Async Iterables should be supported natively.
### Higher-Order Templates examples

@@ -349,19 +340,2 @@

#### `repeat(items, keyfn, template)`
A loop that supports efficient re-ordering by using item keys.
Example:
```javascript
const render = () => html`
<ul>
${repeat(items, (i) => i.id, (i, index) => html`
<li>${index}: ${i.name}</li>`)}
</ul>
`;
```
Note, initial version is in `lib/labs/repeat.ts`: https://github.com/PolymerLabs/lit-html/blob/master/src/labs/repeat.ts
#### `guard(guardExpr, template)`

@@ -368,0 +342,0 @@

@@ -269,88 +269,113 @@ /**

setValue(value: any): void {
let node: Node|undefined = undefined;
value = this._getValue(value);
if (value instanceof Node) {
this.clear();
node = value;
this._previousValue = this._setNodeValue(value);
} else if (value instanceof TemplateResult) {
let instance: TemplateInstance;
if (this._previousValue && this._previousValue._template === value.template) {
instance = this._previousValue;
} else {
this.clear();
instance = this.instance._createInstance(value.template);
node = instance._clone();
}
instance.update(value.values);
this._previousValue = instance;
this._previousValue = this._setTemplateResultValue(value);
} else if (value && value.then !== undefined) {
value.then((v: any) => {
if (this._previousValue === value) {
this.setValue(v);
}
});
this._previousValue = value;
} else if (value && typeof value !== 'string' && value[Symbol.iterator]) {
// For an Iterable, we create a new InstancePart per item, then set its
// value to the item. This is a little bit of overhead for every item in
// an Iterable, but it lets us recurse easily and update Arrays of
// TemplateResults that will be commonly returned from expressions like:
// array.map((i) => html`${i}`)
this._previousValue = this._setIterableValue(value);
} else if (this.startNode.nextSibling! === this.endNode.previousSibling! &&
this.startNode.nextSibling!.nodeType === Node.TEXT_NODE) {
this.startNode.nextSibling!.textContent = value;
this._previousValue = value;
} else {
this._previousValue = this._setTextValue(value);
}
}
// We reuse this parts startNode as the first part's startNode, and this
// parts endNode as the last part's endNode.
private _insertNodeBeforeEndNode(node: Node) {
this.endNode.parentNode!.insertBefore(node, this.endNode);
}
let itemStart = this.startNode;
let itemEnd;
const values = value[Symbol.iterator]() as Iterator<any>;
private _setNodeValue(value: Node): Node {
this.clear();
this._insertNodeBeforeEndNode(value);
const previousParts: NodePart[]|undefined = Array.isArray(this._previousValue) ? this._previousValue : undefined;
let previousPartsIndex = 0;
const itemParts = [];
let current = values.next();
let next = values.next();
return value;
}
if (current.done) {
// Empty iterable, just clear
this.clear();
}
while (!current.done) {
// Reuse a previous part if we can, otherwise create a new one
let itemPart: NodePart;
if (previousParts !== undefined && previousPartsIndex < previousParts.length) {
itemPart = previousParts[previousPartsIndex++];
if (next.done && itemPart.endNode !== this.endNode) {
// Since this is the last part we'll use, set it's endNode to the
// container's endNode. Setting the value of this part will clean
// up any residual nodes from a previously longer iterable.
private _setTextValue(value: string): Node {
return this._setNodeValue(new Text(value));
}
// Remove previousSibling, since we want itemPart.endNode to be
// removed as part of the clear operation.
this.clear(itemPart.endNode.previousSibling!);
itemPart.endNode = this.endNode;
}
itemEnd = itemPart.endNode;
private _setTemplateResultValue(value: TemplateResult): TemplateInstance {
let instance: TemplateInstance;
if (this._previousValue && this._previousValue._template === value.template) {
instance = this._previousValue;
} else {
instance = this.instance._createInstance(value.template);
this._setNodeValue(instance._clone());
}
instance.update(value.values);
return instance;
}
private _setIterableValue(value: any): NodePart[] {
// For an Iterable, we create a new InstancePart per item, then set its
// value to the item. This is a little bit of overhead for every item in
// an Iterable, but it lets us recurse easily and update Arrays of
// TemplateResults that will be commonly returned from expressions like:
// array.map((i) => html`${i}`)
// We reuse this parts startNode as the first part's startNode, and this
// parts endNode as the last part's endNode.
let itemStart = this.startNode;
let itemEnd;
const values = value[Symbol.iterator]() as Iterator<any>;
const previousParts: NodePart[]|undefined = Array.isArray(this._previousValue) ?
this._previousValue : undefined;
let previousPartsIndex = 0;
const itemParts = [];
let current = values.next();
let next = values.next();
if (current.done) {
// Empty iterable, just clear
this.clear();
}
while (!current.done) {
// Reuse a previous part if we can, otherwise create a new one
let itemPart: NodePart;
if (previousParts !== undefined && previousPartsIndex < previousParts.length) {
itemPart = previousParts[previousPartsIndex++];
if (next.done && itemPart.endNode !== this.endNode) {
// Since this is the last part we'll use, set it's endNode to the
// container's endNode. Setting the value of this part will clean
// up any residual nodes from a previously longer iterable.
// Remove previousSibling, since we want itemPart.endNode to be
// removed as part of the clear operation.
this.clear(itemPart.endNode.previousSibling!);
itemPart.endNode = this.endNode;
}
itemEnd = itemPart.endNode;
} else {
if (next.done) {
// on the last item, reuse this part's endNode
itemEnd = this.endNode;
} else {
if (next.done) {
// on the last item, reuse this part's endNode
itemEnd = this.endNode;
} else {
itemEnd = new Text();
this.endNode.parentNode!.insertBefore(itemEnd, this.endNode);
}
itemPart = new NodePart(this.instance, itemStart, itemEnd);
itemEnd = new Text();
this._insertNodeBeforeEndNode(itemEnd);
}
itemPart = new NodePart(this.instance, itemStart, itemEnd);
}
itemPart.setValue(current.value);
itemParts.push(itemPart);
itemPart.setValue(current.value);
itemParts.push(itemPart);
current = next;
next = values.next();
itemStart = itemEnd;
}
this._previousValue = itemParts;
} else if (this.startNode.nextSibling! === this.endNode.previousSibling! &&
this.startNode.nextSibling!.nodeType === Node.TEXT_NODE) {
this.startNode.nextSibling!.textContent = value;
} else {
this.clear();
node = new Text(value);
current = next;
next = values.next();
itemStart = itemEnd;
}
if (node !== undefined) {
this.endNode.parentNode!.insertBefore(node, this.endNode);
}
return itemParts;
}

@@ -357,0 +382,0 @@

@@ -223,2 +223,44 @@ /**

test('renders a Promise', async () => {
const container = document.createElement('div');
let resolve: (v: any) => void;
const promise = new Promise((res, _) => {resolve = res;});
render(html`<div>${promise}</div>`, container);
assert.equal(container.innerHTML, '<div></div>');
resolve!('foo');
await promise;
assert.equal(container.innerHTML, '<div>foo</div>');
});
test('renders racing Promises correctly', async () => {
const container = document.createElement('div');
let resolve1: (v: any) => void;
const promise1 = new Promise((res, _) => {resolve1 = res;});
let resolve2: (v: any) => void;
const promise2 = new Promise((res, _) => {resolve2 = res;});
let promise = promise1;
const t = () => html`<div>${promise}</div>`;
// First render, first Promise, no value
render(t(), container);
assert.equal(container.innerHTML, '<div></div>');
promise = promise2;
// Second render, second Promise, still no value
render(t(), container);
assert.equal(container.innerHTML, '<div></div>');
// Resolve the first Promise, should not update the container
resolve1!('foo');
await promise1;
assert.equal(container.innerHTML, '<div></div>');
// Resolve the second Promise, should update the container
resolve2!('bar');
await promise1;
assert.equal(container.innerHTML, '<div>bar</div>');
});
test('renders a combination of stuff', () => {

@@ -225,0 +267,0 @@ const container = document.createElement('div');

{
"compilerOptions": {
/* Basic Options */
"target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
"module": "es2015", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'. */
"lib": ["es2017", "dom"], /* Specify library files to be included in the compilation: */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
"declaration": true, /* Generates corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./lib", /* Redirect output structure to the directory. */
"target": "es2017",
"module": "es2015",
"lib": ["es2017", "dom"],
"declaration": true,
"sourceMap": true,
"outDir": "./",
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
/* Source Map Options */
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"src/**/*.ts"
]
],
"exclude": []
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc