(\n { constructor }: Object,\n method: string,\n meta: PropertyDescriptor\n ) => {\n (constructor as WebCellClass).eventDelegaters.push({\n type,\n selector,\n method\n });\n return meta as PropertyDescriptor & { value: T };\n };\n}\n","import type { Constructor } from 'web-utility';\nimport type { CustomElement } from 'web-utility';\nimport {\n WebCellProps,\n WebCellElement,\n delegate,\n Fragment,\n toHyphenCase,\n toCamelCase\n} from './utility';\nimport { ComponentMeta, DOMEventDelegater, watch } from './decorator';\nimport { VNodeChildElement, VNode, createCell, render } from './renderer';\n\nexport type WebCellFunction = (\n props?: P\n) => WebCellElement;\n\nexport interface WebCellComponent
\n extends CustomElement {\n root: DocumentFragment | Element;\n update(): void;\n props: P;\n setProps(data: Partial
): Promise;\n state: S;\n setState(data: Partial): Promise;\n defaultSlot: VNodeChildElement[];\n render(props: P, state: S): WebCellElement;\n /**\n * Called before `state` is updated\n */\n shouldUpdate?(oldState: S, newState: S): boolean;\n /**\n * Called after rendering\n */\n updatedCallback?(): void;\n emit(event: string, detail?: any, options?: EventInit): boolean;\n toString(): string;\n}\n\nexport interface WebCellClass\n extends Partial,\n Constructor> {\n attributes?: string[];\n eventDelegaters?: DOMEventDelegater[];\n}\n\nexport function mixin(\n superClass: Constructor = HTMLElement\n): WebCellClass {\n class WebCell extends superClass implements WebCellComponent
{\n static tagName: ComponentMeta['tagName'];\n static extends?: ComponentMeta['extends'];\n static renderTarget: ComponentMeta['renderTarget'] = 'shadowRoot';\n static style?: ComponentMeta['style'];\n static attributes: string[] = [];\n static eventDelegaters: DOMEventDelegater[] = [];\n\n readonly root: DocumentFragment | Element;\n private CSS?: VNode;\n private vTree: WebCellElement;\n private tick?: Promise;\n\n readonly props: P = {} as P;\n readonly state: S = {} as S;\n private cache: Partial = {} as Partial;\n\n @watch\n defaultSlot: VNodeChildElement[] = [];\n\n [key: string]: any;\n\n constructor({ mode = 'open' }: ShadowRootInit = {} as ShadowRootInit) {\n super();\n\n const { renderTarget, eventDelegaters, style } = this\n .constructor as WebCellClass;\n\n const renderChildren = renderTarget === 'children';\n\n const root = (this.root = renderChildren\n ? this\n : this.attachShadow({ mode }));\n\n for (const { type, selector, method } of eventDelegaters) {\n if (renderChildren && /^:host/.test(selector))\n console.warn(\n `[WebCell] DOM Event delegation of \"${selector}\" won't work if you don't invoke \"this.attachShadow()\" manually.`\n );\n\n root.addEventListener(\n type,\n delegate(selector, this[method]).bind(this)\n );\n }\n\n if (style)\n if (renderChildren)\n console.warn(\n '[WebCell] Global CSS should be used while \"renderTarget\" is \"children\"'\n );\n else this.CSS = ;\n }\n\n connectedCallback() {\n this.update();\n }\n\n render(props: P, state: S) {\n return (this.constructor as WebCellClass
).renderTarget !==\n 'children' ? (\n \n ) : (\n this.defaultSlot\n );\n }\n\n update() {\n if (\n !(this.CSS || this.render) ||\n !(this.shouldUpdate?.(this.state, this.cache) ?? true)\n )\n return;\n\n Object.assign(this.state, this.cache);\n this.cache = {} as Partial;\n\n this.vTree = render(\n <>\n {this.CSS}\n {this.render(this.props, this.state)}\n >,\n this.root,\n this.vTree\n );\n\n this.updatedCallback?.();\n }\n\n protected updateAsync() {\n return (this.tick =\n this.tick ||\n new Promise(resolve =>\n self.requestAnimationFrame(() => {\n this.update();\n\n this.tick = undefined;\n resolve();\n })\n ));\n }\n\n private syncPropAttr(data: Partial, list: string[]) {\n for (const key in data) {\n const name = toHyphenCase(key);\n\n if (!list.includes(name)) continue;\n\n const item = data[key];\n\n if (item != null && item !== false) {\n if (typeof item !== 'object')\n super.setAttribute(name, item === true ? name : item);\n } else this.removeAttribute(name);\n }\n }\n\n setProps(data: Partial) {\n Object.assign(this.props, data);\n\n const { attributes } = this.constructor as WebCellClass
;\n\n if (attributes)\n var attributesChanged = new Promise(resolve =>\n self.requestAnimationFrame(\n () => (this.syncPropAttr(data, attributes), resolve())\n )\n );\n\n return Promise.all([attributesChanged, this.updateAsync()]);\n }\n\n setState(data: Partial) {\n Object.assign(this.cache, data);\n\n return this.updateAsync();\n }\n\n setAttribute(name: string, value: string) {\n super.setAttribute(name, value);\n\n const { attributes } = this.constructor as WebCellClass;\n\n if (!attributes.includes(name)) return;\n\n if (typeof value === 'string')\n try {\n var data = JSON.parse(value);\n } catch (error) {\n //\n }\n this.setProps({ [toCamelCase(name)]: data ?? value } as Partial
);\n }\n\n emit(\n event: string,\n detail?: any,\n { cancelable, bubbles, composed }: EventInit = {}\n ) {\n return this.dispatchEvent(\n new CustomEvent(event, {\n detail,\n cancelable,\n bubbles,\n composed\n })\n );\n }\n\n toString() {\n return new XMLSerializer()\n .serializeToString(this.root)\n .replace(/ xmlns=\"http:\\/\\/www.w3.org\\/1999\\/xhtml\"/g, '');\n }\n }\n\n return WebCell;\n}\n","import type {} from 'element-internals-polyfill';\nimport type { ElementInternals } from 'element-internals-polyfill/dist/element-internals';\nimport type { Constructor } from 'web-utility';\nimport type { BaseFieldProps, CustomFormElement } from 'web-utility';\n\nimport { WebCellProps } from './utility';\nimport { mixin, WebCellComponent } from './WebCell';\nimport { attribute } from './decorator';\n\nexport interface WebFieldProps extends BaseFieldProps, WebCellProps {}\n\nexport interface WebFieldState {\n disabled?: boolean;\n}\n\nexport interface WebFieldComponent<\n P extends WebFieldProps = WebFieldProps,\n S = {}\n> extends CustomFormElement,\n WebCellComponent
{\n internals: ElementInternals;\n}\n\nexport type WebFieldClass<\n P extends WebFieldProps = WebFieldProps,\n S = {}\n> = Constructor>;\n\nexport function mixinForm<\n P extends WebFieldProps = WebFieldProps,\n S extends WebFieldState = WebFieldState\n>(): WebFieldClass {\n class WebField extends mixin
() implements WebFieldComponent
{\n static formAssociated = true;\n\n readonly internals = this.attachInternals();\n\n formDisabledCallback(disabled: boolean) {\n this.setState({ disabled } as Partial);\n }\n\n @attribute\n set name(name: string) {\n this.setProps({ name } as Partial
);\n }\n get name() {\n return this.props.name;\n }\n\n set value(value: string) {\n this.setProps({ value } as Partial
);\n this.internals.setFormValue(value);\n }\n get value() {\n return this.props.value;\n }\n\n @attribute\n set required(required: boolean) {\n this.setProps({ required } as Partial
);\n }\n get required() {\n return this.props.required;\n }\n\n @attribute\n set disabled(disabled: boolean) {\n this.setProps({ disabled } as Partial
);\n }\n get disabled() {\n return this.props.disabled;\n }\n\n @attribute\n set autofocus(autofocus: boolean) {\n this.setProps({ autofocus } as Partial
);\n }\n get autofocus() {\n return this.props.autofocus;\n }\n\n set defaultValue(raw: string) {\n this.setAttribute('value', raw);\n\n this.props.value ?? (this.value = raw);\n }\n\n get defaultValue() {\n return this.getAttribute('value');\n }\n\n get form() {\n return this.internals.form;\n }\n get validity() {\n return this.internals.validity;\n }\n get validationMessage() {\n return this.internals.validationMessage;\n }\n get willValidate() {\n return this.internals.willValidate;\n }\n checkValidity() {\n return this.internals.checkValidity();\n }\n reportValidity() {\n return this.internals.reportValidity();\n }\n }\n return WebField;\n}\n","export interface Defer {\n promise: Promise;\n resolve: (data?: T) => void;\n reject: (error: Error | string) => void;\n}\n\nexport function makeDefer(): Defer {\n var resolve: Defer['resolve'], reject: Defer['reject'];\n\n const promise = new Promise(\n (done, error) => ((resolve = done), (reject = error))\n );\n\n return { resolve, reject, promise };\n}\n\nexport type EventHandler = (data: any) => void;\n\nexport interface EventTrigger {\n addEventListener?(name: string, handler: EventHandler): void;\n removeEventListener?(name: string, handler: EventHandler): void;\n on?(name: string, handler: EventHandler): this;\n off?(name: string, handler: EventHandler): this;\n}\n","import { Defer, makeDefer, EventTrigger } from './utility';\n\ndeclare global {\n interface SymbolConstructor {\n observable: symbol;\n }\n}\n\nif (!Symbol.observable) Symbol.observable = Symbol('observable');\n\nexport interface Observer {\n next(value: T): void;\n error(reason: string | Error): void;\n complete(): void;\n}\n\nexport interface Subscription {\n unsubscribe(): void;\n readonly closed: boolean;\n}\n\nexport interface Subscribable {\n [Symbol.observable](): Subscribable;\n subscribe(\n onNext: Observer['next'],\n onError?: Observer['error'],\n onComplete?: Observer['complete']\n ): Subscription;\n}\n\nexport type SubscriberFunction = (\n observer: Observer\n) => (() => void) | void;\n\nexport class Observable implements Subscribable {\n private subscriber: SubscriberFunction;\n\n constructor(subscriber: SubscriberFunction) {\n this.subscriber = subscriber;\n }\n\n [Symbol.observable]() {\n return this;\n }\n\n async *[Symbol.asyncIterator]() {\n var queue: Defer[] = [makeDefer()],\n canceler: (() => void) | void,\n done = false;\n\n const observer: Observer = {\n next(value) {\n if (done) return;\n\n queue[queue.length - 1].resolve(value);\n\n queue.push(makeDefer());\n },\n error(reason) {\n if (!done)\n queue[queue.length - 1].reject(reason), (done = true);\n\n if (canceler) canceler();\n },\n complete() {\n if (!done) queue[queue.length - 1].resolve(), (done = true);\n\n if (canceler) canceler();\n }\n };\n\n canceler = this.subscriber(observer);\n\n do {\n yield queue[0].promise;\n\n queue.shift();\n } while (queue[0]);\n }\n\n static of(...items: T[]) {\n return new this(({ next, complete }) => {\n for (const item of items) next(item);\n\n complete();\n });\n }\n\n async toPromise() {\n const stack = [];\n\n for await (const item of this) {\n stack.push(item);\n\n if (stack.length > 2) stack.shift();\n }\n\n return stack[0];\n }\n\n subscribe(\n onNext: Observer['next'],\n onError?: Observer['error'],\n onComplete?: Observer['complete']\n ) {\n var stop = false;\n\n (async () => {\n try {\n for await (const item of this)\n if (!stop) onNext(item);\n else break;\n\n if (onComplete instanceof Function) onComplete();\n } catch (error) {\n if (onError instanceof Function) onError(error);\n }\n })();\n\n return {\n unsubscribe() {\n stop = true;\n },\n get closed() {\n return stop;\n }\n };\n }\n\n static from(observable: Subscribable) {\n return new this(\n ({ next, error, complete }) =>\n observable.subscribe(next, error, complete).unsubscribe\n );\n }\n\n static fromEvent(target: EventTrigger, name: string) {\n return new this(({ next, error }) => {\n if (typeof target.on === 'function')\n target.on(name, next).on('error', error);\n else {\n target.addEventListener(name, next);\n target.addEventListener('error', error);\n }\n\n return () => {\n if (typeof target.off === 'function')\n target.off(name, next).off('error', error);\n else {\n target.removeEventListener(name, next);\n target.removeEventListener('error', error);\n }\n };\n });\n }\n}\n","import { Observer, Observable } from './Observable';\nimport { makeDefer, Defer } from './utility';\n\nexport function createQueue() {\n type Data = { defer: Defer; data: D };\n\n var feedNext: Observer['next'], stop: Observer['complete'];\n\n const observable = new Observable(({ next, complete }) => {\n (feedNext = next), (stop = complete);\n });\n\n return {\n process(data: D) {\n const defer = makeDefer();\n\n if (!feedNext)\n throw Error(\"Can't process data before Queue consuming\");\n\n feedNext({ defer, data });\n\n return defer.promise;\n },\n destroy() {\n if (!stop) throw Error(\"Can't stop a Queue before Queue consuming\");\n\n stop();\n },\n observable\n };\n}\n","import { URLData } from './URL';\nimport { HTMLField } from './DOM-type';\nimport { isEmpty, parseJSON } from './data';\n\nconst sandbox = document.createElement('template'),\n fragment = document.createDocumentFragment();\n\nexport function parseDOM(HTML: string) {\n sandbox.innerHTML = HTML;\n\n return [...sandbox.content.childNodes].map(node => {\n node.remove();\n return node;\n });\n}\n\nexport function* walkDOM(\n root: Node,\n type?: Node['nodeType']\n): Generator {\n const children = [...root.childNodes];\n\n if (isEmpty(type) || type === root.nodeType) yield root as T;\n\n for (const node of children) yield* walkDOM(node, type);\n}\n\nexport function getVisibleText(root: Element) {\n var text = '';\n\n for (const { nodeType, parentElement, nodeValue } of walkDOM(root))\n if (\n nodeType === Node.TEXT_NODE &&\n parentElement.getAttribute('aria-hidden') !== 'true'\n ) {\n const { width, height } = parentElement.getBoundingClientRect();\n\n if (width && height) text += nodeValue.trim().replace(/\\s+/g, ' ');\n }\n\n return text;\n}\n\ninterface CSSOptions\n extends Pick<\n HTMLLinkElement,\n 'title' | 'media' | 'crossOrigin' | 'integrity'\n > {\n alternate?: boolean;\n}\n\nexport function importCSS(\n URI: string,\n { alternate, ...options }: CSSOptions = {} as CSSOptions\n) {\n const style = [...document.styleSheets].find(({ href }) => href === URI);\n\n if (style) return Promise.resolve(style);\n\n const link = document.createElement('link');\n\n return new Promise((resolve, reject) => {\n link.onload = () => resolve(link.sheet);\n link.onerror = (_1, _2, _3, _4, error) => reject(error);\n\n Object.assign(link, options);\n\n link.rel = (alternate ? 'alternate ' : '') + 'stylesheet';\n link.href = URI;\n\n document.head.append(link);\n });\n}\n\nexport function insertToCursor(...nodes: Node[]) {\n fragment.append(...nodes);\n\n for (const node of walkDOM(fragment))\n if (\n ![1, 3, 11].includes(node.nodeType) ||\n ['meta', 'title', 'link', 'script'].includes(\n node.nodeName.toLowerCase()\n )\n )\n (node as ChildNode).replaceWith(...node.childNodes);\n\n const selection = globalThis.getSelection();\n\n if (!selection) return;\n\n const range = selection.getRangeAt(0);\n\n range.deleteContents();\n range.insertNode(fragment);\n}\n\nexport function scrollTo(selector: string, root?: Element) {\n const [_, ID] = /^#(.+)/.exec(selector) || [];\n\n if (ID === 'top') window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });\n else\n (root || document)\n .querySelector(ID ? `[id=\"${ID}\"]` : selector)\n ?.scrollIntoView({ behavior: 'smooth' });\n}\n\ninterface ScrollEvent {\n target: HTMLHeadingElement;\n links: (HTMLAnchorElement | HTMLAreaElement)[];\n}\n\nexport function watchScroll(\n box: HTMLElement,\n handler: (event: ScrollEvent) => any,\n depth = 6\n) {\n return Array.from(\n box.querySelectorAll(\n Array.from(new Array(depth), (_, index) => `h${++index}`) + ''\n ),\n header => {\n new IntersectionObserver(([item]) => {\n if (!item.isIntersecting) return;\n\n const target = item.target as HTMLHeadingElement;\n\n handler({\n target,\n links: [\n ...target.ownerDocument.querySelectorAll<\n HTMLAnchorElement | HTMLAreaElement\n >(`[href=\"#${target.id}\"]`)\n ]\n });\n }).observe(header);\n\n if (!header.id.trim())\n header.id = header.textContent.trim().replace(/\\W+/g, '-');\n\n return {\n level: +header.tagName[1],\n id: header.id,\n text: header.textContent.trim()\n };\n }\n );\n}\n\nexport function watchVisible(\n root: Element,\n handler: (visible: boolean) => any\n) {\n var last = document.visibilityState === 'visible' ? 1 : 0;\n\n function change(state: number) {\n if (state === 3 || last === 3) handler(state === 3);\n\n last = state;\n }\n\n new IntersectionObserver(([{ isIntersecting }]) =>\n change(isIntersecting ? last | 2 : last & 1)\n ).observe(root);\n\n document.addEventListener('visibilitychange', () =>\n change(document.visibilityState === 'visible' ? last | 1 : last & 2)\n );\n}\n\nexport function formToJSON>(\n form: HTMLFormElement | HTMLFieldSetElement\n) {\n const data = {} as T;\n\n for (const field of form.elements) {\n let {\n type,\n name,\n value: v,\n checked,\n defaultValue,\n selectedOptions,\n files\n } = field as HTMLField;\n\n if (!name) continue;\n\n const box = type !== 'fieldset' && field.closest('fieldset');\n\n if (box && box !== form) continue;\n\n if (['radio', 'checkbox'].includes(type))\n if (checked) v = defaultValue || 'true';\n else continue;\n\n let value: any = parseJSON(v);\n\n switch (type) {\n case 'select-multiple':\n value = Array.from(selectedOptions, ({ value }) =>\n parseJSON(value)\n );\n break;\n case 'fieldset':\n value = formToJSON(field as HTMLFieldSetElement);\n break;\n case 'file':\n value = files && [...files];\n break;\n case 'datetime-local':\n value = new Date(value).toISOString();\n }\n\n if (name in data) data[name] = [].concat(data[name], value);\n else\n data[name] =\n !(value instanceof Array) || !isEmpty(value[1])\n ? value\n : value[0];\n }\n\n return data;\n}\n","import { parseJSON, isEmpty } from './data';\n\nconst { location, atob } = globalThis;\n\nexport function isXDomain(URI: string) {\n return new URL(URI, document.baseURI).origin !== location.origin;\n}\n\nexport type JSONValue = number | boolean | string | null;\nexport interface URLData {\n [key: string]: JSONValue | JSONValue[] | URLData | URLData[] | E;\n}\n\nexport function parseURLData(raw = window.location.search): URLData {\n const list = raw.split(/\\?|#/);\n const data = new URLSearchParams(list[1] || list[0]);\n\n return Object.fromEntries(\n [...data.keys()].map(key => {\n const list = data.getAll(key).map(parseJSON);\n\n return [key, list.length < 2 ? list[0] : list];\n })\n );\n}\n\nexport function buildURLData(map: string[][] | Record) {\n if (!(map instanceof Array)) map = Object.entries(map);\n\n return new URLSearchParams(\n (map as any[][])\n .map(\n ([key, value]) =>\n !isEmpty(value) && [key, value.toJSON?.() || value + '']\n )\n .filter(Boolean)\n );\n}\n\nconst DataURI = /^data:(.+?\\/(.+?))?(;base64)?,([\\s\\S]+)/;\n/**\n * Blob logic forked from axes's\n *\n * @see http://www.cnblogs.com/axes/p/4603984.html\n */\nexport function blobFrom(URI: string) {\n var [_, type, __, base64, data] = DataURI.exec(URI) || [];\n\n data = base64 ? atob(data) : data;\n\n const aBuffer = new ArrayBuffer(data.length);\n const uBuffer = new Uint8Array(aBuffer);\n\n for (let i = 0; data[i]; i++) uBuffer[i] = data.charCodeAt(i);\n\n return new Blob([aBuffer], { type });\n}\n","import { createQueue } from 'iterable-observer';\nimport { getVisibleText, scrollTo, formToJSON } from 'web-utility/source/DOM';\nimport { buildURLData } from 'web-utility/source/URL';\n\nexport type LinkElement = HTMLAnchorElement | HTMLAreaElement | HTMLFormElement;\n\nexport enum PathPrefix {\n hash = '#',\n path = '/'\n}\n\nexport type PathMode = keyof typeof PathPrefix;\n\nconst { location, history } = window;\n\nexport class History {\n stream = createQueue();\n paths: string[] = [];\n prefix: PathPrefix;\n\n get path() {\n return location[\n this.prefix === PathPrefix.hash ? 'hash' : 'pathname'\n ].slice(1);\n }\n\n constructor(mode: PathMode = 'hash') {\n this.prefix = PathPrefix[mode];\n }\n\n [Symbol.asyncIterator]() {\n return this.stream.observable[Symbol.asyncIterator]();\n }\n\n async set(path: string, title = document.title) {\n if (!this.paths.includes(path)) this.paths.push(path);\n\n await this.stream.process(path);\n\n document.title = title;\n }\n\n push(path: string, title = document.title) {\n history.pushState({ path, title }, title, this.prefix + path);\n\n return this.set(path, title);\n }\n\n replace(path: string, title = document.title) {\n history.replaceState({ path, title }, title, this.prefix + path);\n\n return this.set(path, title);\n }\n\n compare(last: string, next: string) {\n for (const path of this.paths)\n if (last === path) return -1;\n else if (next === path) return 1;\n\n return 0;\n }\n\n static getInnerPath(link: LinkElement) {\n const path = link.getAttribute('href') || link.getAttribute('action');\n\n if (\n (link.target || '_self') === '_self' &&\n !path.match(/^\\w+:/) &&\n (!(link instanceof HTMLFormElement) ||\n (link.getAttribute('method') || 'get').toLowerCase() === 'get')\n )\n return path;\n }\n\n static getTitle(root: HTMLElement) {\n return root.title || getVisibleText(root);\n }\n\n handleClick = (event: MouseEvent) => {\n const link = (event.target as HTMLElement).closest<\n HTMLAnchorElement | HTMLAreaElement\n >('a[href], area[href]');\n\n if (!link) return;\n\n const path = History.getInnerPath(link);\n\n if (!path) return;\n\n event.preventDefault();\n\n if (/^#.+/.test(path))\n return scrollTo(path, event.currentTarget as Element);\n\n this.push(path, History.getTitle(link));\n };\n\n handleForm = (event: Event) => {\n const form = event.target as HTMLFormElement;\n const path = History.getInnerPath(form);\n\n if (!path) return;\n\n event.preventDefault();\n\n this.push(path + '?' + buildURLData(formToJSON(form)), form.title);\n };\n\n private popping = false;\n\n listen(root: Element) {\n root.addEventListener('click', this.handleClick);\n root.addEventListener('submit', this.handleForm);\n\n if (this.prefix === PathPrefix.hash)\n window.addEventListener(\n 'hashchange',\n () => this.popping || this.set(this.path)\n );\n\n window.addEventListener('popstate', async ({ state }) => {\n const { path = this.path, title } = state || {};\n\n this.popping = true;\n\n await this.set(path, title);\n\n this.popping = false;\n });\n\n setTimeout(() => this.replace(this.path, (history.state || {}).title));\n\n return this;\n }\n}\n","import { promisify } from './event';\n\nexport interface CartesianCoordinate {\n x: number;\n y: number;\n z?: number;\n}\n\nexport class PageVector {\n from: CartesianCoordinate;\n to: CartesianCoordinate;\n\n constructor(from: CartesianCoordinate, to: CartesianCoordinate) {\n this.from = from;\n this.to = to;\n }\n\n get length() {\n const { from, to } = this;\n\n return Math.sqrt(\n Math.pow(to.x - from.x, 2) +\n Math.pow(to.y - from.y, 2) +\n (to.z != null ? Math.pow(to.z - from.z, 2) : 0)\n );\n }\n\n get direction() {\n const { from, to } = this;\n const XD = to.x - from.x,\n YD = to.y - from.y,\n ZD = to.z - from.z;\n const XL = Math.abs(XD),\n YL = Math.abs(YD),\n ZL = Math.abs(ZD);\n\n switch (isNaN(ZL) ? Math.max(XL, YL) : Math.max(XL, YL, ZL)) {\n case XL:\n return XD > 0 ? 'right' : 'left';\n case YL:\n return YD > 0 ? 'forward' : 'backward';\n case ZL:\n return ZD > 0 ? 'up' : 'down';\n }\n }\n}\n\nconst { getComputedStyle, getSelection, requestAnimationFrame } = globalThis;\n\nexport function getSwipeVector(\n from: CartesianCoordinate,\n to: CartesianCoordinate,\n threshold = parseInt(getComputedStyle(document.body).fontSize) * 6\n) {\n const vector = new PageVector(from, to);\n\n if (vector.length >= threshold && !getSelection()?.toString().trim())\n return vector;\n}\n\nexport interface AnimationEvents {\n transition: TransitionEvent;\n animation: AnimationEvent;\n}\n\nexport type AnimationType = keyof AnimationEvents;\n\nexport function durationOf(type: AnimationType, element: HTMLElement) {\n const { transitionDuration, animationDuration } = getComputedStyle(element);\n\n const duration =\n type === 'animation' ? animationDuration : transitionDuration;\n\n return parseFloat(duration) * (duration.slice(-2) === 'ms' ? 1 : 1000);\n}\n\nexport function watchMotion(\n type: T,\n element: HTMLElement\n) {\n return Promise.race([\n promisify(type, element).catch(event =>\n Promise.resolve(event)\n ),\n new Promise(resolve =>\n setTimeout(resolve, durationOf(type, element))\n )\n ]);\n}\n\nfunction fadeIn(\n type: T,\n element: HTMLElement,\n className: string,\n display: string\n) {\n element.style.display = display;\n\n const end = watchMotion(type, element);\n\n return new Promise(resolve =>\n requestAnimationFrame(() => {\n element.classList.add(className);\n\n end.then(resolve);\n })\n );\n}\n\nasync function fadeOut(\n type: T,\n element: HTMLElement,\n className: string,\n remove?: boolean\n) {\n const end = watchMotion(type, element);\n\n element.classList.remove(className);\n\n await end;\n\n if (remove) element.remove();\n else element.style.display = 'none';\n}\n\nexport function transitIn(\n element: HTMLElement,\n className: string,\n display = 'block'\n) {\n return fadeIn('transition', element, className, display);\n}\n\nexport function animateIn(\n element: HTMLElement,\n className: string,\n display = 'block'\n) {\n return fadeIn('animation', element, className, display);\n}\n\nexport function transitOut(\n element: HTMLElement,\n className: string,\n remove?: boolean\n) {\n return fadeOut('transition', element, className, remove);\n}\n\nexport function animateOut(\n element: HTMLElement,\n className: string,\n remove?: boolean\n) {\n return fadeOut('animation', element, className, remove);\n}\n","import { WebCellProps, WebCellElement } from 'web-cell';\nimport { watchMotion, durationOf } from 'web-utility/source/animation';\nimport { parseURLData } from 'web-utility/source/URL';\n\nimport { History } from './History';\n\nexport function watchStop(element: HTMLElement) {\n return watchMotion(\n durationOf('transition', element) ? 'transition' : 'animation',\n element\n );\n}\nexport interface PageProps extends WebCellProps {\n path: string;\n history?: History;\n [key: string]: any;\n}\n\nexport type PageComponent = (\n props: P\n) => WebCellElement;\n\nexport interface Route {\n paths: (string | RegExp)[];\n component: Function | (() => Promise);\n}\n\nexport function matchRoutes(list: Route[], path: string) {\n for (const { paths, ...rest } of list)\n for (const item of paths)\n if (\n typeof item === 'string'\n ? path.startsWith(item)\n : item.exec(path)\n ) {\n const data = path.split('?');\n\n return {\n ...rest,\n path: data[0],\n params: data[1] && parseURLData(data[1])\n };\n }\n}\n","import {\n WebCellProps,\n WebCellElement,\n component,\n mixin,\n watch,\n attribute,\n createCell\n} from 'web-cell';\n\nimport { Route, matchRoutes, watchStop } from './utility';\nimport { History } from './History';\n\nexport interface CellRouterProps extends WebCellProps {\n routes: Route[];\n path?: string;\n history?: History;\n pageClass?: string;\n startClass?: string;\n endClass?: string;\n onPageLoad?: (event: CustomEvent) => any;\n onPageRender?: (event: CustomEvent) => any;\n}\n\ninterface CellRouterState {\n newPath: string;\n oldPath: string;\n}\n\n@component({\n tagName: 'cell-router',\n renderTarget: 'children'\n})\nexport class CellRouter extends mixin() {\n static arrange(routes: Route[]) {\n return routes\n .reduce(\n (routes, { paths, component }) => [\n ...routes,\n ...paths.map(path => ({ paths: [path], component }))\n ],\n [] as Route[]\n )\n .sort(({ paths: [a] }, { paths: [b] }) =>\n (b + '').localeCompare(a + '')\n );\n }\n\n state = {\n newPath: '',\n oldPath: ''\n };\n\n @watch\n set routes(routes: Route[]) {\n this.setProps({ routes: CellRouter.arrange(routes) });\n }\n\n @attribute\n @watch\n set path(path: string) {\n this.setPath(path);\n }\n\n private setPath(path: string) {\n return Promise.all([\n this.setState({ oldPath: this.props.path, newPath: path }),\n this.setProps({ path })\n ]);\n }\n\n @watch\n set history(history: History) {\n this.setProps({ history }).then(async () => {\n history.listen(this.ownerDocument.body);\n\n for await (const {\n data,\n defer: { resolve }\n } of history) {\n await this.setPath(data);\n resolve();\n }\n });\n }\n\n @attribute\n @watch\n pageClass = '';\n\n @attribute\n @watch\n startClass = '';\n\n @attribute\n @watch\n endClass = '';\n\n pageOf(path: string): WebCellElement | undefined {\n const { component: Page, path: pathname, params, ...rest } =\n matchRoutes(this.routes, path) || {};\n\n if (!Page) return;\n\n const page = (\n \n );\n if (!(page instanceof Promise)) return page;\n\n this.emit('pageload', path);\n\n page.then(AsyncPage => {\n const route = this.routes.find(\n ({ component }) => component === Page\n );\n if (!route) return;\n\n route.component = AsyncPage;\n\n this.update();\n });\n }\n\n connectedCallback() {\n this.style.display = 'block';\n }\n\n updatedCallback() {\n const { newPath } = this.state;\n\n if (newPath) this.setState({ newPath: '' });\n else this.emit('pagerender', this.path);\n }\n\n watchAnimation = async (box: HTMLElement) => {\n await watchStop(box);\n\n await this.setState({ oldPath: '' });\n };\n\n render(\n { path = '', pageClass, startClass, endClass }: CellRouterProps,\n { newPath, oldPath }: CellRouterState\n ) {\n [startClass, endClass] = [endClass, startClass].sort(() =>\n this.history.compare(oldPath, newPath)\n );\n\n return (\n \n {startClass && newPath ? (\n
\n {this.pageOf(newPath)}\n
\n ) : (\n
\n {this.pageOf(path)}\n
\n )}\n {endClass && oldPath && (\n
\n {this.pageOf(oldPath)}\n
\n )}\n
\n );\n }\n}\n","export * from './History';\nexport * from './Router';\nexport * from './utility';\n","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || from);\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\ninterface MaybePolyfilledCe extends CustomElementRegistry {\n readonly polyfillWrapFlushCallback?: object;\n}\n\n/**\n * True if the custom elements polyfill is in use.\n */\nexport const isCEPolyfill = typeof window !== 'undefined' &&\n window.customElements != null &&\n (window.customElements as MaybePolyfilledCe).polyfillWrapFlushCallback !==\n undefined;\n\n/**\n * Reparents nodes, starting from `start` (inclusive) to `end` (exclusive),\n * into another container (could be the same container), before `before`. If\n * `before` is null, it appends the nodes to the container.\n */\nexport const reparentNodes =\n (container: Node,\n start: Node|null,\n end: Node|null = null,\n before: Node|null = null): void => {\n while (start !== end) {\n const n = start!.nextSibling;\n container.insertBefore(start!, before);\n start = n;\n }\n };\n\n/**\n * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from\n * `container`.\n */\nexport const removeNodes =\n (container: Node, start: Node|null, end: Node|null = null): void => {\n while (start !== end) {\n const n = start!.nextSibling;\n container.removeChild(start!);\n start = n;\n }\n };\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {TemplateResult} from './template-result.js';\n\n/**\n * An expression marker with embedded unique key to avoid collision with\n * possible text in templates.\n */\nexport const marker = `{{lit-${String(Math.random()).slice(2)}}}`;\n\n/**\n * An expression marker used text-positions, multi-binding attributes, and\n * attributes with markup-like text values.\n */\nexport const nodeMarker = ``;\n\nexport const markerRegex = new RegExp(`${marker}|${nodeMarker}`);\n\n/**\n * Suffix appended to all bound attribute names.\n */\nexport const boundAttributeSuffix = '$lit$';\n\n/**\n * An updatable Template that tracks the location of dynamic parts.\n */\nexport class Template {\n readonly parts: TemplatePart[] = [];\n readonly element: HTMLTemplateElement;\n\n constructor(result: TemplateResult, element: HTMLTemplateElement) {\n this.element = element;\n\n const nodesToRemove: Node[] = [];\n const stack: Node[] = [];\n // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\n const walker = document.createTreeWalker(\n element.content,\n 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */,\n null,\n false);\n // Keeps track of the last index associated with a part. We try to delete\n // unnecessary nodes, but we never want to associate two different parts\n // to the same index. They must have a constant node between.\n let lastPartIndex = 0;\n let index = -1;\n let partIndex = 0;\n const {strings, values: {length}} = result;\n while (partIndex < length) {\n const node = walker.nextNode() as Element | Comment | Text | null;\n if (node === null) {\n // We've exhausted the content inside a nested template element.\n // Because we still have parts (the outer for-loop), we know:\n // - There is a template in the stack\n // - The walker will find a nextNode outside the template\n walker.currentNode = stack.pop()!;\n continue;\n }\n index++;\n\n if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {\n if ((node as Element).hasAttributes()) {\n const attributes = (node as Element).attributes;\n const {length} = attributes;\n // Per\n // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap,\n // attributes are not guaranteed to be returned in document order.\n // In particular, Edge/IE can return them out of order, so we cannot\n // assume a correspondence between part index and attribute index.\n let count = 0;\n for (let i = 0; i < length; i++) {\n if (endsWith(attributes[i].name, boundAttributeSuffix)) {\n count++;\n }\n }\n while (count-- > 0) {\n // Get the template literal section leading up to the first\n // expression in this attribute\n const stringForPart = strings[partIndex];\n // Find the attribute name\n const name = lastAttributeNameRegex.exec(stringForPart)![2];\n // Find the corresponding attribute\n // All bound attributes have had a suffix added in\n // TemplateResult#getHTML to opt out of special attribute\n // handling. To look up the attribute value we also need to add\n // the suffix.\n const attributeLookupName =\n name.toLowerCase() + boundAttributeSuffix;\n const attributeValue =\n (node as Element).getAttribute(attributeLookupName)!;\n (node as Element).removeAttribute(attributeLookupName);\n const statics = attributeValue.split(markerRegex);\n this.parts.push({type: 'attribute', index, name, strings: statics});\n partIndex += statics.length - 1;\n }\n }\n if ((node as Element).tagName === 'TEMPLATE') {\n stack.push(node);\n walker.currentNode = (node as HTMLTemplateElement).content;\n }\n } else if (node.nodeType === 3 /* Node.TEXT_NODE */) {\n const data = (node as Text).data;\n if (data.indexOf(marker) >= 0) {\n const parent = node.parentNode!;\n const strings = data.split(markerRegex);\n const lastIndex = strings.length - 1;\n // Generate a new text node for each literal section\n // These nodes are also used as the markers for node parts\n for (let i = 0; i < lastIndex; i++) {\n let insert: Node;\n let s = strings[i];\n if (s === '') {\n insert = createMarker();\n } else {\n const match = lastAttributeNameRegex.exec(s);\n if (match !== null && endsWith(match[2], boundAttributeSuffix)) {\n s = s.slice(0, match.index) + match[1] +\n match[2].slice(0, -boundAttributeSuffix.length) + match[3];\n }\n insert = document.createTextNode(s);\n }\n parent.insertBefore(insert, node);\n this.parts.push({type: 'node', index: ++index});\n }\n // If there's no text, we must insert a comment to mark our place.\n // Else, we can trust it will stick around after cloning.\n if (strings[lastIndex] === '') {\n parent.insertBefore(createMarker(), node);\n nodesToRemove.push(node);\n } else {\n (node as Text).data = strings[lastIndex];\n }\n // We have a part for each match found\n partIndex += lastIndex;\n }\n } else if (node.nodeType === 8 /* Node.COMMENT_NODE */) {\n if ((node as Comment).data === marker) {\n const parent = node.parentNode!;\n // Add a new marker node to be the startNode of the Part if any of\n // the following are true:\n // * We don't have a previousSibling\n // * The previousSibling is already the start of a previous part\n if (node.previousSibling === null || index === lastPartIndex) {\n index++;\n parent.insertBefore(createMarker(), node);\n }\n lastPartIndex = index;\n this.parts.push({type: 'node', index});\n // If we don't have a nextSibling, keep this node so we have an end.\n // Else, we can remove it to save future costs.\n if (node.nextSibling === null) {\n (node as Comment).data = '';\n } else {\n nodesToRemove.push(node);\n index--;\n }\n partIndex++;\n } else {\n let i = -1;\n while ((i = (node as Comment).data.indexOf(marker, i + 1)) !== -1) {\n // Comment node has a binding marker inside, make an inactive part\n // The binding won't work, but subsequent bindings will\n // TODO (justinfagnani): consider whether it's even worth it to\n // make bindings in comments work\n this.parts.push({type: 'node', index: -1});\n partIndex++;\n }\n }\n }\n }\n\n // Remove text binding nodes after the walk to not disturb the TreeWalker\n for (const n of nodesToRemove) {\n n.parentNode!.removeChild(n);\n }\n }\n}\n\nconst endsWith = (str: string, suffix: string): boolean => {\n const index = str.length - suffix.length;\n return index >= 0 && str.slice(index) === suffix;\n};\n\n/**\n * A placeholder for a dynamic expression in an HTML template.\n *\n * There are two built-in part types: AttributePart and NodePart. NodeParts\n * always represent a single dynamic expression, while AttributeParts may\n * represent as many expressions are contained in the attribute.\n *\n * A Template's parts are mutable, so parts can be replaced or modified\n * (possibly to implement different template semantics). The contract is that\n * parts can only be replaced, not removed, added or reordered, and parts must\n * always consume the correct number of values in their `update()` method.\n *\n * TODO(justinfagnani): That requirement is a little fragile. A\n * TemplateInstance could instead be more careful about which values it gives\n * to Part.update().\n */\nexport type TemplatePart = {\n readonly type: 'node'; index: number;\n}|{\n readonly type: 'attribute';\n index: number;\n readonly name: string;\n readonly strings: ReadonlyArray;\n};\n\nexport const isTemplatePartActive = (part: TemplatePart) => part.index !== -1;\n\n// Allows `document.createComment('')` to be renamed for a\n// small manual size-savings.\nexport const createMarker = () => document.createComment('');\n\n/**\n * This regex extracts the attribute name preceding an attribute-position\n * expression. It does this by matching the syntax allowed for attributes\n * against the string literal directly preceding the expression, assuming that\n * the expression is in an attribute-value position.\n *\n * See attributes in the HTML spec:\n * https://www.w3.org/TR/html5/syntax.html#elements-attributes\n *\n * \" \\x09\\x0a\\x0c\\x0d\" are HTML space characters:\n * https://www.w3.org/TR/html5/infrastructure.html#space-characters\n *\n * \"\\0-\\x1F\\x7F-\\x9F\" are Unicode control characters, which includes every\n * space character except \" \".\n *\n * So an attribute is:\n * * The name: any character except a control character, space character, ('),\n * (\"), \">\", \"=\", or \"/\"\n * * Followed by zero or more space characters\n * * Followed by \"=\"\n * * Followed by zero or more space characters\n * * Followed by:\n * * Any character except space, ('), (\"), \"<\", \">\", \"=\", (`), or\n * * (\") then any non-(\"), or\n * * (') then any non-(')\n */\nexport const lastAttributeNameRegex =\n // eslint-disable-next-line no-control-regex\n /([ \\x09\\x0a\\x0c\\x0d])([^\\0-\\x1F\\x7F-\\x9F \"'>=/]+)([ \\x09\\x0a\\x0c\\x0d]*=[ \\x09\\x0a\\x0c\\x0d]*(?:[^ \\x09\\x0a\\x0c\\x0d\"'`<>=]*|\"[^\"]*|'[^']*))$/;\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {isTemplatePartActive, Template, TemplatePart} from './template.js';\n\nconst walkerNodeFilter = 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */;\n\n/**\n * Removes the list of nodes from a Template safely. In addition to removing\n * nodes from the Template, the Template part indices are updated to match\n * the mutated Template DOM.\n *\n * As the template is walked the removal state is tracked and\n * part indices are adjusted as needed.\n *\n * div\n * div#1 (remove) <-- start removing (removing node is div#1)\n * div\n * div#2 (remove) <-- continue removing (removing node is still div#1)\n * div\n * div <-- stop removing since previous sibling is the removing node (div#1,\n * removed 4 nodes)\n */\nexport function removeNodesFromTemplate(\n template: Template, nodesToRemove: Set) {\n const {element: {content}, parts} = template;\n const walker =\n document.createTreeWalker(content, walkerNodeFilter, null, false);\n let partIndex = nextActiveIndexInTemplateParts(parts);\n let part = parts[partIndex];\n let nodeIndex = -1;\n let removeCount = 0;\n const nodesToRemoveInTemplate = [];\n let currentRemovingNode: Node|null = null;\n while (walker.nextNode()) {\n nodeIndex++;\n const node = walker.currentNode as Element;\n // End removal if stepped past the removing node\n if (node.previousSibling === currentRemovingNode) {\n currentRemovingNode = null;\n }\n // A node to remove was found in the template\n if (nodesToRemove.has(node)) {\n nodesToRemoveInTemplate.push(node);\n // Track node we're removing\n if (currentRemovingNode === null) {\n currentRemovingNode = node;\n }\n }\n // When removing, increment count by which to adjust subsequent part indices\n if (currentRemovingNode !== null) {\n removeCount++;\n }\n while (part !== undefined && part.index === nodeIndex) {\n // If part is in a removed node deactivate it by setting index to -1 or\n // adjust the index as needed.\n part.index = currentRemovingNode !== null ? -1 : part.index - removeCount;\n // go to the next active part.\n partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\n part = parts[partIndex];\n }\n }\n nodesToRemoveInTemplate.forEach((n) => n.parentNode!.removeChild(n));\n}\n\nconst countNodes = (node: Node) => {\n let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1;\n const walker = document.createTreeWalker(node, walkerNodeFilter, null, false);\n while (walker.nextNode()) {\n count++;\n }\n return count;\n};\n\nconst nextActiveIndexInTemplateParts =\n (parts: TemplatePart[], startIndex = -1) => {\n for (let i = startIndex + 1; i < parts.length; i++) {\n const part = parts[i];\n if (isTemplatePartActive(part)) {\n return i;\n }\n }\n return -1;\n };\n\n/**\n * Inserts the given node into the Template, optionally before the given\n * refNode. In addition to inserting the node into the Template, the Template\n * part indices are updated to match the mutated Template DOM.\n */\nexport function insertNodeIntoTemplate(\n template: Template, node: Node, refNode: Node|null = null) {\n const {element: {content}, parts} = template;\n // If there's no refNode, then put node at end of template.\n // No part indices need to be shifted in this case.\n if (refNode === null || refNode === undefined) {\n content.appendChild(node);\n return;\n }\n const walker =\n document.createTreeWalker(content, walkerNodeFilter, null, false);\n let partIndex = nextActiveIndexInTemplateParts(parts);\n let insertCount = 0;\n let walkerIndex = -1;\n while (walker.nextNode()) {\n walkerIndex++;\n const walkerNode = walker.currentNode as Element;\n if (walkerNode === refNode) {\n insertCount = countNodes(node);\n refNode.parentNode!.insertBefore(node, refNode);\n }\n while (partIndex !== -1 && parts[partIndex].index === walkerIndex) {\n // If we've inserted the node, simply adjust all subsequent parts\n if (insertCount > 0) {\n while (partIndex !== -1) {\n parts[partIndex].index += insertCount;\n partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\n }\n return;\n }\n partIndex = nextActiveIndexInTemplateParts(parts, partIndex);\n }\n }\n}\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {Part} from './part.js';\n\nconst directives = new WeakMap