UNPKG

chrome-devtools-frontend

Version:
83 lines (74 loc) 3.28 kB
/** * @license * Copyright (c) 2017 The Polymer Project Authors. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt * The complete set of authors may be found at * http://polymer.github.io/AUTHORS.txt * The complete set of contributors may be found at * http://polymer.github.io/CONTRIBUTORS.txt * Code distributed by Google as part of the polymer project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ import {directive, NodePart, Part} from '../lit-html.js'; /** * A directive that renders the items of an async iterable[1], replacing * previous values with new values, so that only one value is ever rendered * at a time. * * Async iterables are objects with a [Symbol.asyncIterator] method, which * returns an iterator who's `next()` method returns a Promise. When a new * value is available, the Promise resolves and the value is rendered to the * Part controlled by the directive. If another value other than this * directive has been set on the Part, the iterable will no longer be listened * to and new values won't be written to the Part. * * [1]: https://github.com/tc39/proposal-async-iteration * * @param value An async iterable * @param mapper An optional function that maps from (value, index) to another * value. Useful for generating templates for each item in the iterable. */ export const asyncReplace = directive( <T>(value: AsyncIterable<T>, mapper?: (v: T, index?: number) => unknown) => async (part: Part) => { if (!(part instanceof NodePart)) { throw new Error('asyncReplace can only be used in text bindings'); } // If we've already set up this particular iterable, we don't need // to do anything. if (value === part.value) { return; } // We nest a new part to keep track of previous item values separately // of the iterable as a value itself. const itemPart = new NodePart(part.options); part.value = value; let i = 0; for await (let v of value) { // Check to make sure that value is the still the current value of // the part, and if not bail because a new value owns this part if (part.value !== value) { break; } // When we get the first value, clear the part. This let's the // previous value display until we can replace it. if (i === 0) { part.clear(); itemPart.appendIntoPart(part); } // As a convenience, because functional-programming-style // transforms of iterables and async iterables requires a library, // we accept a mapper function. This is especially convenient for // rendering a template for each item. if (mapper !== undefined) { // This is safe because T must otherwise be treated as unknown by // the rest of the system. v = mapper(v, i) as T; } itemPart.setValue(v); itemPart.commit(); i++; } });