Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@endorphinjs/template-runtime

Package Overview
Dependencies
Maintainers
1
Versions
85
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@endorphinjs/template-runtime - npm Package Compare versions

Comparing version 0.4.5 to 0.5.0

97

dist/attribute.d.ts

@@ -1,34 +0,93 @@

import { Injector } from './injector';
import { Component } from './component';
export interface ChangeSet {
p: {
[name: string]: any;
};
c: {
[name: string]: any;
};
}
export interface AttributeChangeSet extends ChangeSet {
n?: {
[namespace: string]: ChangeSet;
};
}
/**
* Sets value of attribute `name` to `value`
* @return Update status. Always returns `0` since actual attribute value
* is defined in `finalizeAttributes()`
* Creates new attribute change set
*/
export declare function setAttribute(injector: Injector, name: string, value: any): number;
export declare function attributeSet(): AttributeChangeSet;
/**
* Sets value of attribute `name` under namespace of `nsURI` to `value`
* Create pending props change set
*/
export declare function setAttributeNS(injector: Injector, nsURI: string, name: string, value: any): void;
export declare function propsSet(elem: Component): AttributeChangeSet;
/**
* Updates `attrName` value in `elem`, if required
* @returns New attribute value
* Alias for `elem.setAttribute`
*/
export declare function updateAttribute(elem: HTMLElement, attrName: string, value: any, prevValue: any): any;
export declare function setAttribute(elem: Element, name: string, value: any): any;
/**
* Updates props in given component, if required
* @return Returns `true` if value was updated
* Alias for `elem.className`
*/
export declare function updateProps(elem: Component, data: object): boolean;
export declare function setClass(elem: Element, value: any): any;
/**
* Adds given class name as pending attribute
* Sets attribute value as expression. Unlike regular primitive attributes,
* expression values must be represented, e.g. non-primitive values must be
* converted to string representations. Also, expression resolved to `false`,
* `null` or `undefined` will remove attribute from element
*/
export declare function addClass(injector: Injector, value: string): void;
export declare function setAttributeExpression(elem: Element, name: string, value: any): any;
/**
* Applies pending attributes changes to injector’s host element
* Updates attribute value only if it’s not equal to previous value
*/
export declare function finalizeAttributes(injector: Injector): number;
export declare function updateAttributeExpression<T = any>(elem: Element, name: string, value: T, prevValue?: any): T;
/**
* Normalizes given class value: removes duplicates and trims whitespace
* Alias for `elem.setAttributeNS`
*/
export declare function normalizeClassName(str: string): string;
export declare function setAttributeNS(elem: Element, ns: string, name: string, value: any): any;
/**
* Same as `setAttributeExpression()` but for namespaced attributes
*/
export declare function setAttributeExpressionNS(elem: Element, ns: string, name: string, value: any): any;
/**
* Adds or removes (if value is `void`) attribute to given element
*/
export declare function updateAttributeExpressionNS<T = any>(elem: Element, ns: string, name: string, value: T, prevValue?: any): T;
/**
* Alias for `elem.classList.add()`
*/
export declare function addClass(elem: HTMLElement, className: string): void;
/**
* Adds class to given element if given condition is truthy
*/
export declare function addClassIf(elem: HTMLElement, className: string, condition: any): boolean;
/**
* Toggles class on given element if condition is changed
*/
export declare function toggleClassIf(elem: HTMLElement, className: string, condition: any, prevResult: boolean): boolean;
/**
* Sets pending attribute value which will be added to attribute later
*/
export declare function setPendingAttribute(data: AttributeChangeSet, name: string, value: any): void;
/**
* Sets pending namespaced attribute value which will be added to attribute later
*/
export declare function setPendingAttributeNS(data: AttributeChangeSet, ns: string, name: string, value: any): void;
/**
* Adds given class name to pending attribute set
*/
export declare function addPendingClass(data: AttributeChangeSet, className: string): void;
/**
* Adds given class name to pending attribute set if condition is truthy
*/
export declare function addPendingClassIf(data: AttributeChangeSet, className: string, condition: any): void;
/**
* Finalizes pending attributes
*/
export declare function finalizeAttributes(elem: Element, data: AttributeChangeSet): number;
/**
* Finalizes pending namespaced attributes
*/
export declare function finalizeAttributesNS(elem: Element, data: AttributeChangeSet): number;
/**
* Returns normalized list of class names from given string
*/
export declare function classNames(str: string): string[];

14

dist/component.d.ts
import { Injector } from './injector';
import { Changes, Data, UpdateTemplate, ChangeSet, MountTemplate } from './types';
import { Changes, Data, UpdateTemplate, MountTemplate } from './types';
import { Store } from './store';
interface RefMap {
[key: string]: Element;
export interface RefMap {
[key: string]: Element | null;
}

@@ -52,4 +52,2 @@ export declare type ComponentEventHandler = (component: Component, event: Event, target: HTMLElement) => void;

input: Injector;
/** Change set for component refs */
refs: ChangeSet;
/** Runtime variables */

@@ -70,4 +68,2 @@ vars: object;

rendering: boolean;
/** Indicates that component is currently in finalization state (calling `did*` hooks) */
finalizing: boolean;
/** Default props values */

@@ -158,7 +154,7 @@ defaultProps: object;

*/
export declare function mountComponent(component: Component, initialProps?: object): void;
export declare function mountComponent(component: Component, props?: object): void;
/**
* Updates given mounted component
*/
export declare function updateComponent(component: Component): number;
export declare function updateComponent(component: Component, props?: object): number;
/**

@@ -165,0 +161,0 @@ * Destroys given component: removes static event listeners and cleans things up

@@ -5,2 +5,6 @@ declare type TextNode = Text & {

/**
* Shorthand for `elem.appendChild()` for better minification
*/
export declare function appendChild(element: Element, node: Node): Node;
/**
* Creates element with given tag name

@@ -7,0 +11,0 @@ * @param cssScope Scope for CSS isolation

import { Scope, EventBinding } from './types';
import { Injector } from './injector';
import { Component } from './component';
interface PendingEvents {
target: Element;
host: Component;
events: {
[type: string]: EventBinding | void;
};
}
/**

@@ -8,15 +14,15 @@ * Registers given event listener on `target` element and returns event binding

*/
export declare function addStaticEvent(target: Element, type: string, handleEvent: EventListener, host: Component, scope: Scope): EventBinding;
export declare function addEvent(target: Element, type: string, listener: EventListener, host: Component, scope: Scope): EventBinding;
/**
* Unregister given event binding
*/
export declare function removeStaticEvent(binding: EventBinding): void;
export declare function removeEvent(type: string, binding: EventBinding): void;
/**
* Adds pending event `name` handler
* Creates structure for collecting pending events
*/
export declare function addEvent(injector: Injector, type: string, handleEvent: EventListener, host: Component, scope: Scope): void;
/**
* Finalizes events of given injector
*/
export declare function finalizeEvents(injector: Injector): number;
export declare function pendingEvents(host: Component, target: Element): PendingEvents;
export declare function setPendingEvent(pending: PendingEvents, type: string, listener: EventListener, scope: Scope): void;
export declare function finalizePendingEvents(pending: PendingEvents): void;
export declare function detachPendingEvents(pending: PendingEvents): void;
export declare function safeEventListener(host: Component, handler: EventListener): EventListener;
export {};
import { LinkedList, LinkedListItem } from './linked-list';
import { ChangeSet, EventBinding, Scope, MountBlock, UpdateBlock } from './types';
import { Scope, MountBlock, UpdateBlock } from './types';
import { Component } from './component';

@@ -12,16 +12,6 @@ import { SlotContext } from './slot';

ptr: LinkedListItem | null;
/**
* Slots container
*/
slots?: {
/** Slots container */
slots: {
[name: string]: SlotContext;
} | null;
/** Pending attributes updates */
attributes: ChangeSet;
/** Pending namespace updates */
attributesNS?: {
[uri: string]: ChangeSet;
};
/** Current event handlers */
events: ChangeSet<EventBinding>;
}

@@ -28,0 +18,0 @@ export interface Block {

@@ -12,2 +12,6 @@ import { Injector, Block } from './injector';

}
interface PartialsMap {
[name: string]: PartialDefinition;
}
export declare function getPartial(host: Component, name: string, componentPartials: PartialsMap): PartialDefinition | undefined;
/**

@@ -14,0 +18,0 @@ * Mounts given partial into injector context

@@ -1,16 +0,11 @@

import { Component } from './component';
import { Component, RefMap } from './component';
/**
* Sets runtime ref (e.g. ref which will be changed over time) to given host
* @returns Update status. Refs must be explicitly finalized, thus
* we always return `0` as nothing was changed
* Adds given element as a named ref
*/
export declare function setRef(host: Component, name: string, elem: HTMLElement): number;
export declare function setRef(host: Component, key: string, elem: Element): void;
/**
* Sets static ref (e.g. ref which won’t be changed over time) to given host
* Removes ref for given key
*/
export declare function setStaticRef(host: Component, name: string, value: Element): void;
/**
* Finalizes refs on given scope
* @returns Update status
*/
export declare function finalizeRefs(host: Component): number;
export declare function removeRef(host: Component, key: string): void;
export declare function setPendingRef(pending: RefMap, key: string | void, elem: Element | null): void;
export declare function finalizePendingRefs(host: Component, pending: RefMap): void;

@@ -6,2 +6,8 @@ 'use strict';

/**
* Shorthand for `elem.appendChild()` for better minification
*/
function appendChild(element, node) {
return element.appendChild(node);
}
/**
* Creates element with given tag name

@@ -104,4 +110,2 @@ * @param cssScope Scope for CSS isolation

* Check if given value id defined, e.g. not `null`, `undefined` or `NaN`
* @param {*} value
* @returns {boolean}
*/

@@ -112,29 +116,2 @@ function isDefined(value) {

/**
* Finalizes updated items, defined in `items.prev` and `items.cur`
* @param {object} items
* @param {function} change
* @param {*} [ctx]
* @returns {number} Returns `1` if data was updated, `0` otherwise
*/
function finalizeItems(items, change, ctx) {
let updated = 0;
const { cur, prev } = items;
for (const name in cur) {
const curValue = cur[name];
const prevValue = prev[name];
if (curValue !== prevValue) {
updated = 1;
change(name, prevValue, prev[name] = curValue, ctx);
}
cur[name] = null;
}
return updated;
}
/**
* Creates object for storing change sets, e.g. current and previous values
*/
function changeSet() {
return { prev: obj(), cur: obj() };
}
/**
* Returns properties from `next` which were changed since `prev` state.

@@ -228,7 +205,12 @@ * Returns `null` if there are no changes

function runtimeError(host, error) {
host.dispatchEvent(new CustomEvent('runtime-error', {
bubbles: true,
cancelable: true,
detail: { error, host }
}));
if (typeof CustomEvent !== 'undefined') {
host.dispatchEvent(new CustomEvent('runtime-error', {
bubbles: true,
cancelable: true,
detail: { error, host }
}));
}
else {
throw error;
}
}

@@ -240,5 +222,4 @@

*/
function addStaticEvent(target, type, handleEvent, host, scope) {
handleEvent = safeEventListener(host, handleEvent);
return registerBinding({ host, scope, type, handleEvent, target });
function addEvent(target, type, listener, host, scope) {
return registerBinding(type, { host, scope, target, listener, handleEvent });
}

@@ -248,29 +229,55 @@ /**

*/
function removeStaticEvent(binding) {
binding.target.removeEventListener(binding.type, binding);
function removeEvent(type, binding) {
binding.target.removeEventListener(type, binding);
}
/**
* Adds pending event `name` handler
* Creates structure for collecting pending events
*/
function addEvent(injector, type, handleEvent, host, scope) {
// We’ll use `ChangeSet` to bind and unbind events only: once binding is registered,
// we will mutate binding props
const { prev, cur } = injector.events;
const binding = cur[type] || prev[type];
handleEvent = safeEventListener(host, handleEvent);
function pendingEvents(host, target) {
return { host, target, events: obj() };
}
function setPendingEvent(pending, type, listener, scope) {
let binding = pending.events[type];
if (binding) {
binding.listener = listener;
binding.scope = scope;
binding.handleEvent = handleEvent;
cur[type] = binding;
}
else {
cur[type] = { host, scope, type, handleEvent, target: injector.parentNode };
binding = pending.events[type] = addEvent(pending.target, type, listener, pending.host, scope);
}
binding.pending = listener;
}
/**
* Finalizes events of given injector
*/
function finalizeEvents(injector) {
return finalizeItems(injector.events, changeEvent, injector.parentNode);
function finalizePendingEvents(pending) {
// For event listeners, we should only bind or unbind events, depending
// on current listener value
const { events } = pending;
for (const type in events) {
const binding = events[type];
if (binding) {
if (!binding.pending) {
events[type] = removeEvent(type, binding);
}
binding.pending = void 0;
}
}
}
function detachPendingEvents(pending) {
const { events } = pending;
for (const type in events) {
const binding = events[type];
if (binding) {
removeEvent(type, binding);
}
}
}
function handleEvent(event) {
try {
this.listener && this.listener(event);
}
catch (error) {
runtimeError(this.host, error);
// tslint:disable-next-line:no-console
console.error(error);
}
}
function safeEventListener(host, handler) {

@@ -289,97 +296,157 @@ // tslint:disable-next-line:only-arrow-functions

}
function registerBinding(binding) {
binding.target.addEventListener(binding.type, binding);
function registerBinding(type, binding) {
binding.target.addEventListener(type, binding);
return binding;
}
/**
* Invoked when event handler was changed
* Creates new attribute change set
*/
function changeEvent(name, prevValue, newValue) {
if (!prevValue && newValue) {
// Should register new binding
registerBinding(newValue);
}
else if (prevValue && !newValue) {
removeStaticEvent(prevValue);
}
function attributeSet() {
return { c: obj(), p: obj() };
}
/**
* Sets value of attribute `name` to `value`
* @return Update status. Always returns `0` since actual attribute value
* is defined in `finalizeAttributes()`
* Create pending props change set
*/
function setAttribute(injector, name, value) {
injector.attributes.cur[name] = value;
return 0;
function propsSet(elem) {
const props = assign(obj(), elem.componentModel.defaultProps);
// NB in components, pending `c` props are tested against actual `.props`,
// the `p` property is not used. To keep up with the same hidden JS class,
// create `p` property as well and point it to `c` to reduce object allocations
return { c: props, p: props };
}
/**
* Sets value of attribute `name` under namespace of `nsURI` to `value`
* Alias for `elem.setAttribute`
*/
function setAttributeNS(injector, nsURI, name, value) {
if (!injector.attributesNS) {
injector.attributesNS = obj();
}
const { attributesNS } = injector;
if (!attributesNS[nsURI]) {
attributesNS[nsURI] = changeSet();
}
attributesNS[nsURI].cur[name] = value;
function setAttribute(elem, name, value) {
elem.setAttribute(name, value);
return value;
}
/**
* Updates `attrName` value in `elem`, if required
* @returns New attribute value
* Alias for `elem.className`
*/
function updateAttribute(elem, attrName, value, prevValue) {
if (value !== prevValue) {
changeAttribute(attrName, prevValue, value, elem);
return value;
function setClass(elem, value) {
elem.className = value;
return value;
}
/**
* Sets attribute value as expression. Unlike regular primitive attributes,
* expression values must be represented, e.g. non-primitive values must be
* converted to string representations. Also, expression resolved to `false`,
* `null` or `undefined` will remove attribute from element
*/
function setAttributeExpression(elem, name, value) {
const primitive = representedValue(value);
primitive === null
? elem.removeAttribute(name)
: setAttribute(elem, name, primitive);
return value;
}
/**
* Updates attribute value only if it’s not equal to previous value
*/
function updateAttributeExpression(elem, name, value, prevValue) {
return prevValue !== value
? setAttributeExpression(elem, name, value)
: value;
}
/**
* Alias for `elem.setAttributeNS`
*/
function setAttributeNS(elem, ns, name, value) {
elem.setAttributeNS(ns, name, value);
return value;
}
/**
* Same as `setAttributeExpression()` but for namespaced attributes
*/
function setAttributeExpressionNS(elem, ns, name, value) {
const primitive = representedValue(value);
primitive === null
? elem.removeAttributeNS(ns, name)
: setAttributeNS(elem, ns, name, primitive);
return value;
}
/**
* Adds or removes (if value is `void`) attribute to given element
*/
function updateAttributeExpressionNS(elem, ns, name, value, prevValue) {
return prevValue !== value
? setAttributeExpressionNS(elem, ns, name, value)
: value;
}
/**
* Alias for `elem.classList.add()`
*/
function addClass(elem, className) {
elem.classList.add(className);
}
/**
* Adds class to given element if given condition is truthy
*/
function addClassIf(elem, className, condition) {
condition && addClass(elem, className);
return condition;
}
/**
* Toggles class on given element if condition is changed
*/
function toggleClassIf(elem, className, condition, prevResult) {
if (prevResult !== condition) {
condition ? addClass(elem, className) : elem.classList.remove(className);
}
return prevValue;
return condition;
}
/**
* Updates props in given component, if required
* @return Returns `true` if value was updated
* Sets pending attribute value which will be added to attribute later
*/
function updateProps(elem, data) {
const { props } = elem;
let updated;
for (const p in data) {
if (data.hasOwnProperty(p) && props[p] !== data[p]) {
if (!updated) {
updated = obj();
}
updated[p] = data[p];
}
function setPendingAttribute(data, name, value) {
data.c[name] = value;
}
/**
* Sets pending namespaced attribute value which will be added to attribute later
*/
function setPendingAttributeNS(data, ns, name, value) {
if (!data.n) {
data.n = obj();
}
if (updated) {
elem.setProps(data);
return true;
if (!data.n[ns]) {
data.n[ns] = attributeSet();
}
return false;
data.n[ns].c[name] = value;
}
/**
* Adds given class name as pending attribute
* Adds given class name to pending attribute set
*/
function addClass(injector, value) {
if (isDefined(value)) {
const className = injector.attributes.cur.class;
setAttribute(injector, 'class', isDefined(className) ? className + ' ' + value : value);
function addPendingClass(data, className) {
if (className != null) {
const prev = data.c.class;
data.c.class = prev ? prev + ' ' + className : String(className);
}
}
/**
* Applies pending attributes changes to injector’s host element
* Adds given class name to pending attribute set if condition is truthy
*/
function finalizeAttributes(injector) {
const { attributes, attributesNS } = injector;
if (isDefined(attributes.cur.class)) {
attributes.cur.class = normalizeClassName(attributes.cur.class);
}
let updated = finalizeItems(attributes, changeAttribute, injector.parentNode);
if (attributesNS) {
const ctx = { node: injector.parentNode, ns: null };
for (const ns in attributesNS) {
ctx.ns = ns;
updated |= finalizeItems(attributesNS[ns], changeAttributeNS, ctx);
function addPendingClassIf(data, className, condition) {
condition && addPendingClass(data, className);
}
/**
* Finalizes pending attributes
*/
function finalizeAttributes(elem, data) {
let updated = 0;
const { c, p } = data;
for (const name in c) {
const curValue = c[name];
if (curValue !== p[name]) {
updated = 1;
if (name === 'class') {
elem.className = classNames(curValue).join(' ');
}
else {
setAttributeExpression(elem, name, curValue);
}
p[name] = curValue;
}
c[name] = null;
}

@@ -389,41 +456,62 @@ return updated;

/**
* Normalizes given class value: removes duplicates and trims whitespace
* Finalizes pending namespaced attributes
*/
function normalizeClassName(str) {
const out = [];
const parts = String(str).split(/\s+/);
for (let i = 0, cl; i < parts.length; i++) {
cl = parts[i];
if (cl && out.indexOf(cl) === -1) {
out.push(cl);
function finalizeAttributesNS(elem, data) {
// NB use it as a separate function to use explicitly inside generated content.
// It there’s no pending namespace attributes, this method will not be included
// into final bundle
if (!data.n) {
return 0;
}
let updated = 0;
for (const ns in data.n) {
const { c, p } = data.n[ns];
for (const name in c) {
const curValue = c[name];
if (curValue !== p[name]) {
updated = 1;
setAttributeExpressionNS(elem, ns, name, curValue);
p[name] = curValue;
}
c[name] = null;
}
}
return out.join(' ');
return updated;
}
/**
* Callback for changing attribute value
* Returns normalized list of class names from given string
*/
function changeAttribute(name, prevValue, newValue, elem) {
if (isDefined(newValue)) {
if (name === 'class') {
elem.className = normalizeClassName(newValue);
function classNames(str) {
const out = [];
if (isDefined(str)) {
const parts = String(str).split(/\s+/);
for (let i = 0, cl; i < parts.length; i++) {
cl = parts[i];
if (cl && out.indexOf(cl) === -1) {
out.push(cl);
}
}
else {
representAttributeValue(elem, name, newValue);
}
}
else if (isDefined(prevValue)) {
elem.removeAttribute(name);
}
return out;
}
/**
* Callback for changing attribute value
* Returns represented attribute value for given data
*/
function changeAttributeNS(name, prevValue, newValue, ctx) {
if (isDefined(newValue)) {
ctx.node.setAttributeNS(ctx.ns, name, newValue);
function representedValue(value) {
if (value === false || !isDefined(value)) {
return null;
}
else if (isDefined(prevValue)) {
ctx.node.removeAttributeNS(ctx.ns, name);
if (value === true) {
return '';
}
if (Array.isArray(value)) {
return '[]';
}
if (typeof value === 'function') {
return '𝑓';
}
if (typeof value === 'object') {
return '{}';
}
return value;
}

@@ -513,6 +601,3 @@

// to reduce runtime checks and keep functions in monomorphic state
slots: null,
attributes: changeSet(),
attributesNS: void 0,
events: changeSet()
slots: null
};

@@ -804,3 +889,3 @@ }

if (block.update) {
block.update(block.host, block.injector, block.scope);
block.update(block.host, block.scope);
}

@@ -871,4 +956,4 @@ }

const { props, state, extend, events } = prepare(element, definition);
element.refs = {};
element.props = obj(props);
element.refs = obj();
element.props = obj();
element.state = state;

@@ -894,6 +979,4 @@ element.componentView = element; // XXX Should point to Shadow Root in Web Components

vars: obj(),
refs: changeSet(),
mounted: false,
rendering: false,
finalizing: false,
update: void 0,

@@ -910,15 +993,7 @@ queued: false,

*/
function mountComponent(component, initialProps) {
function mountComponent(component, props) {
const { componentModel } = component;
const { input, definition, defaultProps } = componentModel;
let changes = setPropsInternal(component, obj(), assign(obj(defaultProps), initialProps));
const runtimeChanges = setPropsInternal(component, input.attributes.prev, input.attributes.cur);
if (changes && runtimeChanges) {
assign(changes, runtimeChanges);
}
else if (runtimeChanges) {
changes = runtimeChanges;
}
const { input, definition } = componentModel;
const changes = setPropsInternal(component, props || componentModel.defaultProps);
const arg = changes || {};
finalizeEvents(input);
componentModel.rendering = true;

@@ -937,6 +1012,4 @@ // Notify slot status

componentModel.rendering = false;
componentModel.finalizing = true;
runHook(component, 'didRender', arg);
runHook(component, 'didMount', arg);
componentModel.finalizing = false;
}

@@ -946,6 +1019,4 @@ /**

*/
function updateComponent(component) {
const { input } = component.componentModel;
const changes = setPropsInternal(component, input.attributes.prev, input.attributes.cur);
finalizeEvents(input);
function updateComponent(component, props) {
const changes = props && setPropsInternal(component, props);
if (changes || component.componentModel.queued) {

@@ -964,3 +1035,2 @@ renderNext(component, changes);

const { definition, events } = componentModel;
const scope = getScope(component);
runHook(component, 'willUnmount');

@@ -975,3 +1045,3 @@ componentModel.mounted = false;

const dispose = definition.default && definition.default.dispose;
captureError(component, dispose, scope);
captureError(component, dispose, getScope(component));
runHook(component, 'didUnmount');

@@ -1031,6 +1101,4 @@ // @ts-ignore: Nulling disposed object

componentModel.rendering = false;
componentModel.finalizing = true;
runHook(component, 'didRender', arg);
runHook(component, 'didUpdate', arg);
componentModel.finalizing = false;
}

@@ -1049,19 +1117,20 @@ /**

}
function setPropsInternal(component, prevProps, nextProps) {
const changes = {};
let didChanged = false;
function setPropsInternal(component, nextProps) {
let changes;
const { props } = component;
const { defaultProps } = component.componentModel;
for (const p in nextProps) {
const prev = prevProps[p];
const prev = props[p];
let current = nextProps[p];
if (current == null) {
current = defaultProps[p];
nextProps[p] = current = defaultProps[p];
}
if (p === 'class' && current != null) {
current = normalizeClassName(current);
current = classNames(current).join(' ');
}
if (current !== prev) {
didChanged = true;
props[p] = prevProps[p] = current;
if (!changes) {
changes = obj();
}
props[p] = current;
changes[p] = { current, prev };

@@ -1072,5 +1141,4 @@ if (!/^partial:/.test(p)) {

}
nextProps[p] = null;
}
return didChanged ? changes : null;
return changes;
}

@@ -1155,4 +1223,5 @@ /**

if (value != null && componentModel && componentModel.mounted) {
const changes = setPropsInternal(element, element.props, obj(value));
const changes = setPropsInternal(element, assign(obj(), value));
changes && renderNext(element, changes);
return changes;
}

@@ -1223,3 +1292,3 @@ };

// Update rendered result
updated = block.update(host, injector, scope) ? 1 : 0;
updated = block.update(host, scope) ? 1 : 0;
}

@@ -1299,3 +1368,3 @@ block.injector.ptr = block.end;

setScope(host, scope);
if (rendered.update(host, injector, scope)) {
if (rendered.update(host, scope)) {
this.updated = 1;

@@ -1362,3 +1431,3 @@ }

const prevScope = getScope(host);
collection.forEach(iterator$1, block);
collection.forEach(keyIterator, block);
setScope(host, prevScope);

@@ -1384,3 +1453,3 @@ }

}
function iterator$1(value, key) {
function keyIterator(value, key) {
const { injector, index, rendered } = this;

@@ -1422,6 +1491,6 @@ const id = this.keyExpr(value, prepareScope(this.scope, index, key, value));

if (entry.update) {
const { host, injector } = entry;
const { host } = entry;
const scope = prepareScope(entry.scope, index, key, value);
setScope(host, scope);
if (entry.update(host, injector, scope)) {
if (entry.update(host, scope)) {
return 1;

@@ -1476,30 +1545,33 @@ }

/**
* Sets runtime ref (e.g. ref which will be changed over time) to given host
* @returns Update status. Refs must be explicitly finalized, thus
* we always return `0` as nothing was changed
* Adds given element as a named ref
*/
function setRef(host, name, elem) {
host.componentModel.refs.cur[name] = elem;
return 0;
function setRef(host, key, elem) {
elem.setAttribute(getRefAttr(key, host), '');
host.refs[key] = elem;
}
/**
* Sets static ref (e.g. ref which won’t be changed over time) to given host
* Removes ref for given key
*/
function setStaticRef(host, name, value) {
value && value.setAttribute(getRefAttr(name, host), '');
host.refs[name] = value;
function removeRef(host, key) {
const elem = host.refs[key];
if (elem) {
elem.removeAttribute(getRefAttr(key, host));
host.refs[key] = null;
}
}
/**
* Finalizes refs on given scope
* @returns Update status
*/
function finalizeRefs(host) {
return finalizeItems(host.componentModel.refs, changeRef, host);
function setPendingRef(pending, key, elem) {
if (key && elem) {
pending[key] = elem;
}
}
/**
* Invoked when element reference was changed
*/
function changeRef(name, prevValue, newValue, host) {
prevValue && prevValue.removeAttribute(getRefAttr(name, host));
setStaticRef(host, name, newValue);
function finalizePendingRefs(host, pending) {
for (const key in pending) {
const prev = host.refs[key];
const next = pending[key];
if (prev !== next) {
prev && removeRef(host, key);
next && setRef(host, key, next);
}
pending[key] = null;
}
}

@@ -1581,2 +1653,5 @@ /**

function getPartial(host, name, componentPartials) {
return host.props['partial:' + name] || componentPartials[name];
}
/**

@@ -1624,3 +1699,3 @@ * Mounts given partial into injector context

const scope = setScope(host, assign(block.scope, args));
if (block.update(host, injector, scope)) {
if (block.update(host, scope)) {
updated = 1;

@@ -1786,2 +1861,13 @@ }

elem.style.animation = animation;
// In case if callback is provided, we have to ensure that animation is actually applied.
// In some testing environments, animations could be disabled via
// `* { animation: none !important; }`. In this case, we should complete animation ASAP.
if (callback) {
nextTick(() => {
const style = window.getComputedStyle(elem, null);
if (!style.animationName || style.animationName === 'none') {
stopAnimation(elem);
}
});
}
}

@@ -1918,4 +2004,2 @@ /**

* Concatenates two strings with optional separator
* @param {string} name
* @param {string} suffix
*/

@@ -1926,2 +2010,10 @@ function concat(name, suffix) {

}
function nextTick(fn) {
if (typeof Promise !== 'undefined') {
Promise.resolve().then(fn);
}
else {
requestAnimationFrame(fn);
}
}

@@ -2014,7 +2106,12 @@ /**

exports.addClass = addClass;
exports.addClassIf = addClassIf;
exports.addEvent = addEvent;
exports.addStaticEvent = addStaticEvent;
exports.addPendingClass = addPendingClass;
exports.addPendingClassIf = addPendingClassIf;
exports.animate = animate;
exports.appendChild = appendChild;
exports.assign = assign;
exports.attributeSet = attributeSet;
exports.call = call;
exports.classNames = classNames;
exports.composeTween = composeTween;

@@ -2028,2 +2125,3 @@ exports.createAnimation = createAnimation;

exports.default = endorphin;
exports.detachPendingEvents = detachPendingEvents;
exports.disposeBlock = disposeBlock;

@@ -2041,6 +2139,8 @@ exports.domInsert = domInsert;

exports.finalizeAttributes = finalizeAttributes;
exports.finalizeEvents = finalizeEvents;
exports.finalizeRefs = finalizeRefs;
exports.finalizeAttributesNS = finalizeAttributesNS;
exports.finalizePendingEvents = finalizePendingEvents;
exports.finalizePendingRefs = finalizePendingRefs;
exports.find = find;
exports.get = get;
exports.getPartial = getPartial;
exports.getProp = getProp;

@@ -2062,6 +2162,9 @@ exports.getScope = getScope;

exports.move = move;
exports.normalizeClassName = normalizeClassName;
exports.notifySlotUpdate = notifySlotUpdate;
exports.obj = obj;
exports.pendingEvents = pendingEvents;
exports.prepareScope = prepareScope;
exports.removeStaticEvent = removeStaticEvent;
exports.propsSet = propsSet;
exports.removeEvent = removeEvent;
exports.removeRef = removeRef;
exports.renderComponent = renderComponent;

@@ -2071,6 +2174,12 @@ exports.safeEventListener = safeEventListener;

exports.setAttribute = setAttribute;
exports.setAttributeExpression = setAttributeExpression;
exports.setAttributeExpressionNS = setAttributeExpressionNS;
exports.setAttributeNS = setAttributeNS;
exports.setClass = setClass;
exports.setPendingAttribute = setPendingAttribute;
exports.setPendingAttributeNS = setPendingAttributeNS;
exports.setPendingEvent = setPendingEvent;
exports.setPendingRef = setPendingRef;
exports.setRef = setRef;
exports.setScope = setScope;
exports.setStaticRef = setStaticRef;
exports.setVar = setVar;

@@ -2080,2 +2189,3 @@ exports.stopAnimation = stopAnimation;

exports.text = text;
exports.toggleClassIf = toggleClassIf;
exports.tweenAnimate = tweenAnimate;

@@ -2089,3 +2199,4 @@ exports.unmountBlock = unmountBlock;

exports.unmountSlot = unmountSlot;
exports.updateAttribute = updateAttribute;
exports.updateAttributeExpression = updateAttributeExpression;
exports.updateAttributeExpressionNS = updateAttributeExpressionNS;
exports.updateBlock = updateBlock;

@@ -2099,4 +2210,3 @@ exports.updateComponent = updateComponent;

exports.updatePartial = updatePartial;
exports.updateProps = updateProps;
exports.updateText = updateText;
//# sourceMappingURL=runtime.cjs.js.map

@@ -18,3 +18,3 @@ import { Component, ComponentDefinition } from './component';

export * from './animation';
export { assign } from './utils';
export { assign, obj } from './utils';
declare type FilterCallback<T> = (value: T, key: string | number) => boolean;

@@ -21,0 +21,0 @@ interface ComponentOptions {

/**
* Shorthand for `elem.appendChild()` for better minification
*/
function appendChild(element, node) {
return element.appendChild(node);
}
/**
* Creates element with given tag name

@@ -99,4 +105,2 @@ * @param cssScope Scope for CSS isolation

* Check if given value id defined, e.g. not `null`, `undefined` or `NaN`
* @param {*} value
* @returns {boolean}
*/

@@ -107,29 +111,2 @@ function isDefined(value) {

/**
* Finalizes updated items, defined in `items.prev` and `items.cur`
* @param {object} items
* @param {function} change
* @param {*} [ctx]
* @returns {number} Returns `1` if data was updated, `0` otherwise
*/
function finalizeItems(items, change, ctx) {
let updated = 0;
const { cur, prev } = items;
for (const name in cur) {
const curValue = cur[name];
const prevValue = prev[name];
if (curValue !== prevValue) {
updated = 1;
change(name, prevValue, prev[name] = curValue, ctx);
}
cur[name] = null;
}
return updated;
}
/**
* Creates object for storing change sets, e.g. current and previous values
*/
function changeSet() {
return { prev: obj(), cur: obj() };
}
/**
* Returns properties from `next` which were changed since `prev` state.

@@ -223,7 +200,12 @@ * Returns `null` if there are no changes

function runtimeError(host, error) {
host.dispatchEvent(new CustomEvent('runtime-error', {
bubbles: true,
cancelable: true,
detail: { error, host }
}));
if (typeof CustomEvent !== 'undefined') {
host.dispatchEvent(new CustomEvent('runtime-error', {
bubbles: true,
cancelable: true,
detail: { error, host }
}));
}
else {
throw error;
}
}

@@ -235,5 +217,4 @@

*/
function addStaticEvent(target, type, handleEvent, host, scope) {
handleEvent = safeEventListener(host, handleEvent);
return registerBinding({ host, scope, type, handleEvent, target });
function addEvent(target, type, listener, host, scope) {
return registerBinding(type, { host, scope, target, listener, handleEvent });
}

@@ -243,29 +224,55 @@ /**

*/
function removeStaticEvent(binding) {
binding.target.removeEventListener(binding.type, binding);
function removeEvent(type, binding) {
binding.target.removeEventListener(type, binding);
}
/**
* Adds pending event `name` handler
* Creates structure for collecting pending events
*/
function addEvent(injector, type, handleEvent, host, scope) {
// We’ll use `ChangeSet` to bind and unbind events only: once binding is registered,
// we will mutate binding props
const { prev, cur } = injector.events;
const binding = cur[type] || prev[type];
handleEvent = safeEventListener(host, handleEvent);
function pendingEvents(host, target) {
return { host, target, events: obj() };
}
function setPendingEvent(pending, type, listener, scope) {
let binding = pending.events[type];
if (binding) {
binding.listener = listener;
binding.scope = scope;
binding.handleEvent = handleEvent;
cur[type] = binding;
}
else {
cur[type] = { host, scope, type, handleEvent, target: injector.parentNode };
binding = pending.events[type] = addEvent(pending.target, type, listener, pending.host, scope);
}
binding.pending = listener;
}
/**
* Finalizes events of given injector
*/
function finalizeEvents(injector) {
return finalizeItems(injector.events, changeEvent, injector.parentNode);
function finalizePendingEvents(pending) {
// For event listeners, we should only bind or unbind events, depending
// on current listener value
const { events } = pending;
for (const type in events) {
const binding = events[type];
if (binding) {
if (!binding.pending) {
events[type] = removeEvent(type, binding);
}
binding.pending = void 0;
}
}
}
function detachPendingEvents(pending) {
const { events } = pending;
for (const type in events) {
const binding = events[type];
if (binding) {
removeEvent(type, binding);
}
}
}
function handleEvent(event) {
try {
this.listener && this.listener(event);
}
catch (error) {
runtimeError(this.host, error);
// tslint:disable-next-line:no-console
console.error(error);
}
}
function safeEventListener(host, handler) {

@@ -284,97 +291,157 @@ // tslint:disable-next-line:only-arrow-functions

}
function registerBinding(binding) {
binding.target.addEventListener(binding.type, binding);
function registerBinding(type, binding) {
binding.target.addEventListener(type, binding);
return binding;
}
/**
* Invoked when event handler was changed
* Creates new attribute change set
*/
function changeEvent(name, prevValue, newValue) {
if (!prevValue && newValue) {
// Should register new binding
registerBinding(newValue);
}
else if (prevValue && !newValue) {
removeStaticEvent(prevValue);
}
function attributeSet() {
return { c: obj(), p: obj() };
}
/**
* Sets value of attribute `name` to `value`
* @return Update status. Always returns `0` since actual attribute value
* is defined in `finalizeAttributes()`
* Create pending props change set
*/
function setAttribute(injector, name, value) {
injector.attributes.cur[name] = value;
return 0;
function propsSet(elem) {
const props = assign(obj(), elem.componentModel.defaultProps);
// NB in components, pending `c` props are tested against actual `.props`,
// the `p` property is not used. To keep up with the same hidden JS class,
// create `p` property as well and point it to `c` to reduce object allocations
return { c: props, p: props };
}
/**
* Sets value of attribute `name` under namespace of `nsURI` to `value`
* Alias for `elem.setAttribute`
*/
function setAttributeNS(injector, nsURI, name, value) {
if (!injector.attributesNS) {
injector.attributesNS = obj();
}
const { attributesNS } = injector;
if (!attributesNS[nsURI]) {
attributesNS[nsURI] = changeSet();
}
attributesNS[nsURI].cur[name] = value;
function setAttribute(elem, name, value) {
elem.setAttribute(name, value);
return value;
}
/**
* Updates `attrName` value in `elem`, if required
* @returns New attribute value
* Alias for `elem.className`
*/
function updateAttribute(elem, attrName, value, prevValue) {
if (value !== prevValue) {
changeAttribute(attrName, prevValue, value, elem);
return value;
function setClass(elem, value) {
elem.className = value;
return value;
}
/**
* Sets attribute value as expression. Unlike regular primitive attributes,
* expression values must be represented, e.g. non-primitive values must be
* converted to string representations. Also, expression resolved to `false`,
* `null` or `undefined` will remove attribute from element
*/
function setAttributeExpression(elem, name, value) {
const primitive = representedValue(value);
primitive === null
? elem.removeAttribute(name)
: setAttribute(elem, name, primitive);
return value;
}
/**
* Updates attribute value only if it’s not equal to previous value
*/
function updateAttributeExpression(elem, name, value, prevValue) {
return prevValue !== value
? setAttributeExpression(elem, name, value)
: value;
}
/**
* Alias for `elem.setAttributeNS`
*/
function setAttributeNS(elem, ns, name, value) {
elem.setAttributeNS(ns, name, value);
return value;
}
/**
* Same as `setAttributeExpression()` but for namespaced attributes
*/
function setAttributeExpressionNS(elem, ns, name, value) {
const primitive = representedValue(value);
primitive === null
? elem.removeAttributeNS(ns, name)
: setAttributeNS(elem, ns, name, primitive);
return value;
}
/**
* Adds or removes (if value is `void`) attribute to given element
*/
function updateAttributeExpressionNS(elem, ns, name, value, prevValue) {
return prevValue !== value
? setAttributeExpressionNS(elem, ns, name, value)
: value;
}
/**
* Alias for `elem.classList.add()`
*/
function addClass(elem, className) {
elem.classList.add(className);
}
/**
* Adds class to given element if given condition is truthy
*/
function addClassIf(elem, className, condition) {
condition && addClass(elem, className);
return condition;
}
/**
* Toggles class on given element if condition is changed
*/
function toggleClassIf(elem, className, condition, prevResult) {
if (prevResult !== condition) {
condition ? addClass(elem, className) : elem.classList.remove(className);
}
return prevValue;
return condition;
}
/**
* Updates props in given component, if required
* @return Returns `true` if value was updated
* Sets pending attribute value which will be added to attribute later
*/
function updateProps(elem, data) {
const { props } = elem;
let updated;
for (const p in data) {
if (data.hasOwnProperty(p) && props[p] !== data[p]) {
if (!updated) {
updated = obj();
}
updated[p] = data[p];
}
function setPendingAttribute(data, name, value) {
data.c[name] = value;
}
/**
* Sets pending namespaced attribute value which will be added to attribute later
*/
function setPendingAttributeNS(data, ns, name, value) {
if (!data.n) {
data.n = obj();
}
if (updated) {
elem.setProps(data);
return true;
if (!data.n[ns]) {
data.n[ns] = attributeSet();
}
return false;
data.n[ns].c[name] = value;
}
/**
* Adds given class name as pending attribute
* Adds given class name to pending attribute set
*/
function addClass(injector, value) {
if (isDefined(value)) {
const className = injector.attributes.cur.class;
setAttribute(injector, 'class', isDefined(className) ? className + ' ' + value : value);
function addPendingClass(data, className) {
if (className != null) {
const prev = data.c.class;
data.c.class = prev ? prev + ' ' + className : String(className);
}
}
/**
* Applies pending attributes changes to injector’s host element
* Adds given class name to pending attribute set if condition is truthy
*/
function finalizeAttributes(injector) {
const { attributes, attributesNS } = injector;
if (isDefined(attributes.cur.class)) {
attributes.cur.class = normalizeClassName(attributes.cur.class);
}
let updated = finalizeItems(attributes, changeAttribute, injector.parentNode);
if (attributesNS) {
const ctx = { node: injector.parentNode, ns: null };
for (const ns in attributesNS) {
ctx.ns = ns;
updated |= finalizeItems(attributesNS[ns], changeAttributeNS, ctx);
function addPendingClassIf(data, className, condition) {
condition && addPendingClass(data, className);
}
/**
* Finalizes pending attributes
*/
function finalizeAttributes(elem, data) {
let updated = 0;
const { c, p } = data;
for (const name in c) {
const curValue = c[name];
if (curValue !== p[name]) {
updated = 1;
if (name === 'class') {
elem.className = classNames(curValue).join(' ');
}
else {
setAttributeExpression(elem, name, curValue);
}
p[name] = curValue;
}
c[name] = null;
}

@@ -384,41 +451,62 @@ return updated;

/**
* Normalizes given class value: removes duplicates and trims whitespace
* Finalizes pending namespaced attributes
*/
function normalizeClassName(str) {
const out = [];
const parts = String(str).split(/\s+/);
for (let i = 0, cl; i < parts.length; i++) {
cl = parts[i];
if (cl && out.indexOf(cl) === -1) {
out.push(cl);
function finalizeAttributesNS(elem, data) {
// NB use it as a separate function to use explicitly inside generated content.
// It there’s no pending namespace attributes, this method will not be included
// into final bundle
if (!data.n) {
return 0;
}
let updated = 0;
for (const ns in data.n) {
const { c, p } = data.n[ns];
for (const name in c) {
const curValue = c[name];
if (curValue !== p[name]) {
updated = 1;
setAttributeExpressionNS(elem, ns, name, curValue);
p[name] = curValue;
}
c[name] = null;
}
}
return out.join(' ');
return updated;
}
/**
* Callback for changing attribute value
* Returns normalized list of class names from given string
*/
function changeAttribute(name, prevValue, newValue, elem) {
if (isDefined(newValue)) {
if (name === 'class') {
elem.className = normalizeClassName(newValue);
function classNames(str) {
const out = [];
if (isDefined(str)) {
const parts = String(str).split(/\s+/);
for (let i = 0, cl; i < parts.length; i++) {
cl = parts[i];
if (cl && out.indexOf(cl) === -1) {
out.push(cl);
}
}
else {
representAttributeValue(elem, name, newValue);
}
}
else if (isDefined(prevValue)) {
elem.removeAttribute(name);
}
return out;
}
/**
* Callback for changing attribute value
* Returns represented attribute value for given data
*/
function changeAttributeNS(name, prevValue, newValue, ctx) {
if (isDefined(newValue)) {
ctx.node.setAttributeNS(ctx.ns, name, newValue);
function representedValue(value) {
if (value === false || !isDefined(value)) {
return null;
}
else if (isDefined(prevValue)) {
ctx.node.removeAttributeNS(ctx.ns, name);
if (value === true) {
return '';
}
if (Array.isArray(value)) {
return '[]';
}
if (typeof value === 'function') {
return '𝑓';
}
if (typeof value === 'object') {
return '{}';
}
return value;
}

@@ -508,6 +596,3 @@

// to reduce runtime checks and keep functions in monomorphic state
slots: null,
attributes: changeSet(),
attributesNS: void 0,
events: changeSet()
slots: null
};

@@ -799,3 +884,3 @@ }

if (block.update) {
block.update(block.host, block.injector, block.scope);
block.update(block.host, block.scope);
}

@@ -866,4 +951,4 @@ }

const { props, state, extend, events } = prepare(element, definition);
element.refs = {};
element.props = obj(props);
element.refs = obj();
element.props = obj();
element.state = state;

@@ -889,6 +974,4 @@ element.componentView = element; // XXX Should point to Shadow Root in Web Components

vars: obj(),
refs: changeSet(),
mounted: false,
rendering: false,
finalizing: false,
update: void 0,

@@ -905,15 +988,7 @@ queued: false,

*/
function mountComponent(component, initialProps) {
function mountComponent(component, props) {
const { componentModel } = component;
const { input, definition, defaultProps } = componentModel;
let changes = setPropsInternal(component, obj(), assign(obj(defaultProps), initialProps));
const runtimeChanges = setPropsInternal(component, input.attributes.prev, input.attributes.cur);
if (changes && runtimeChanges) {
assign(changes, runtimeChanges);
}
else if (runtimeChanges) {
changes = runtimeChanges;
}
const { input, definition } = componentModel;
const changes = setPropsInternal(component, props || componentModel.defaultProps);
const arg = changes || {};
finalizeEvents(input);
componentModel.rendering = true;

@@ -932,6 +1007,4 @@ // Notify slot status

componentModel.rendering = false;
componentModel.finalizing = true;
runHook(component, 'didRender', arg);
runHook(component, 'didMount', arg);
componentModel.finalizing = false;
}

@@ -941,6 +1014,4 @@ /**

*/
function updateComponent(component) {
const { input } = component.componentModel;
const changes = setPropsInternal(component, input.attributes.prev, input.attributes.cur);
finalizeEvents(input);
function updateComponent(component, props) {
const changes = props && setPropsInternal(component, props);
if (changes || component.componentModel.queued) {

@@ -959,3 +1030,2 @@ renderNext(component, changes);

const { definition, events } = componentModel;
const scope = getScope(component);
runHook(component, 'willUnmount');

@@ -970,3 +1040,3 @@ componentModel.mounted = false;

const dispose = definition.default && definition.default.dispose;
captureError(component, dispose, scope);
captureError(component, dispose, getScope(component));
runHook(component, 'didUnmount');

@@ -1026,6 +1096,4 @@ // @ts-ignore: Nulling disposed object

componentModel.rendering = false;
componentModel.finalizing = true;
runHook(component, 'didRender', arg);
runHook(component, 'didUpdate', arg);
componentModel.finalizing = false;
}

@@ -1044,19 +1112,20 @@ /**

}
function setPropsInternal(component, prevProps, nextProps) {
const changes = {};
let didChanged = false;
function setPropsInternal(component, nextProps) {
let changes;
const { props } = component;
const { defaultProps } = component.componentModel;
for (const p in nextProps) {
const prev = prevProps[p];
const prev = props[p];
let current = nextProps[p];
if (current == null) {
current = defaultProps[p];
nextProps[p] = current = defaultProps[p];
}
if (p === 'class' && current != null) {
current = normalizeClassName(current);
current = classNames(current).join(' ');
}
if (current !== prev) {
didChanged = true;
props[p] = prevProps[p] = current;
if (!changes) {
changes = obj();
}
props[p] = current;
changes[p] = { current, prev };

@@ -1067,5 +1136,4 @@ if (!/^partial:/.test(p)) {

}
nextProps[p] = null;
}
return didChanged ? changes : null;
return changes;
}

@@ -1150,4 +1218,5 @@ /**

if (value != null && componentModel && componentModel.mounted) {
const changes = setPropsInternal(element, element.props, obj(value));
const changes = setPropsInternal(element, assign(obj(), value));
changes && renderNext(element, changes);
return changes;
}

@@ -1218,3 +1287,3 @@ };

// Update rendered result
updated = block.update(host, injector, scope) ? 1 : 0;
updated = block.update(host, scope) ? 1 : 0;
}

@@ -1294,3 +1363,3 @@ block.injector.ptr = block.end;

setScope(host, scope);
if (rendered.update(host, injector, scope)) {
if (rendered.update(host, scope)) {
this.updated = 1;

@@ -1357,3 +1426,3 @@ }

const prevScope = getScope(host);
collection.forEach(iterator$1, block);
collection.forEach(keyIterator, block);
setScope(host, prevScope);

@@ -1379,3 +1448,3 @@ }

}
function iterator$1(value, key) {
function keyIterator(value, key) {
const { injector, index, rendered } = this;

@@ -1417,6 +1486,6 @@ const id = this.keyExpr(value, prepareScope(this.scope, index, key, value));

if (entry.update) {
const { host, injector } = entry;
const { host } = entry;
const scope = prepareScope(entry.scope, index, key, value);
setScope(host, scope);
if (entry.update(host, injector, scope)) {
if (entry.update(host, scope)) {
return 1;

@@ -1471,30 +1540,33 @@ }

/**
* Sets runtime ref (e.g. ref which will be changed over time) to given host
* @returns Update status. Refs must be explicitly finalized, thus
* we always return `0` as nothing was changed
* Adds given element as a named ref
*/
function setRef(host, name, elem) {
host.componentModel.refs.cur[name] = elem;
return 0;
function setRef(host, key, elem) {
elem.setAttribute(getRefAttr(key, host), '');
host.refs[key] = elem;
}
/**
* Sets static ref (e.g. ref which won’t be changed over time) to given host
* Removes ref for given key
*/
function setStaticRef(host, name, value) {
value && value.setAttribute(getRefAttr(name, host), '');
host.refs[name] = value;
function removeRef(host, key) {
const elem = host.refs[key];
if (elem) {
elem.removeAttribute(getRefAttr(key, host));
host.refs[key] = null;
}
}
/**
* Finalizes refs on given scope
* @returns Update status
*/
function finalizeRefs(host) {
return finalizeItems(host.componentModel.refs, changeRef, host);
function setPendingRef(pending, key, elem) {
if (key && elem) {
pending[key] = elem;
}
}
/**
* Invoked when element reference was changed
*/
function changeRef(name, prevValue, newValue, host) {
prevValue && prevValue.removeAttribute(getRefAttr(name, host));
setStaticRef(host, name, newValue);
function finalizePendingRefs(host, pending) {
for (const key in pending) {
const prev = host.refs[key];
const next = pending[key];
if (prev !== next) {
prev && removeRef(host, key);
next && setRef(host, key, next);
}
pending[key] = null;
}
}

@@ -1576,2 +1648,5 @@ /**

function getPartial(host, name, componentPartials) {
return host.props['partial:' + name] || componentPartials[name];
}
/**

@@ -1619,3 +1694,3 @@ * Mounts given partial into injector context

const scope = setScope(host, assign(block.scope, args));
if (block.update(host, injector, scope)) {
if (block.update(host, scope)) {
updated = 1;

@@ -1781,2 +1856,13 @@ }

elem.style.animation = animation;
// In case if callback is provided, we have to ensure that animation is actually applied.
// In some testing environments, animations could be disabled via
// `* { animation: none !important; }`. In this case, we should complete animation ASAP.
if (callback) {
nextTick(() => {
const style = window.getComputedStyle(elem, null);
if (!style.animationName || style.animationName === 'none') {
stopAnimation(elem);
}
});
}
}

@@ -1913,4 +1999,2 @@ /**

* Concatenates two strings with optional separator
* @param {string} name
* @param {string} suffix
*/

@@ -1921,2 +2005,10 @@ function concat(name, suffix) {

}
function nextTick(fn) {
if (typeof Promise !== 'undefined') {
Promise.resolve().then(fn);
}
else {
requestAnimationFrame(fn);
}
}

@@ -2008,3 +2100,3 @@ /**

export default endorphin;
export { Store, addClass, addEvent, addStaticEvent, animate, assign, call, composeTween, createAnimation, createComponent, createInjector, createScope, createSlot, cssAnimate, disposeBlock, domInsert, domRemove, elem, elemNS, elemNSWithText, elemWithText, emptyBlockContent, enterScope, exitScope, filter, finalizeAttributes, finalizeEvents, finalizeRefs, find, get, getProp, getScope, getSlotContext, getState, getVar, injectBlock, insert, isolateElement, mountBlock, mountComponent, mountInnerHTML, mountIterator, mountKeyIterator, mountPartial, mountSlot, move, normalizeClassName, notifySlotUpdate, prepareScope, removeStaticEvent, renderComponent, safeEventListener, scheduleRender, setAttribute, setAttributeNS, setRef, setScope, setStaticRef, setVar, stopAnimation, subscribeStore, text, tweenAnimate, unmountBlock, unmountComponent, unmountInnerHTML, unmountIterator, unmountKeyIterator, unmountPartial, unmountSlot, updateAttribute, updateBlock, updateComponent, updateDefaultSlot, updateIncomingSlot, updateInnerHTML, updateIterator, updateKeyIterator, updatePartial, updateProps, updateText };
export { Store, addClass, addClassIf, addEvent, addPendingClass, addPendingClassIf, animate, appendChild, assign, attributeSet, call, classNames, composeTween, createAnimation, createComponent, createInjector, createScope, createSlot, cssAnimate, detachPendingEvents, disposeBlock, domInsert, domRemove, elem, elemNS, elemNSWithText, elemWithText, emptyBlockContent, enterScope, exitScope, filter, finalizeAttributes, finalizeAttributesNS, finalizePendingEvents, finalizePendingRefs, find, get, getPartial, getProp, getScope, getSlotContext, getState, getVar, injectBlock, insert, isolateElement, mountBlock, mountComponent, mountInnerHTML, mountIterator, mountKeyIterator, mountPartial, mountSlot, move, notifySlotUpdate, obj, pendingEvents, prepareScope, propsSet, removeEvent, removeRef, renderComponent, safeEventListener, scheduleRender, setAttribute, setAttributeExpression, setAttributeExpressionNS, setAttributeNS, setClass, setPendingAttribute, setPendingAttributeNS, setPendingEvent, setPendingRef, setRef, setScope, setVar, stopAnimation, subscribeStore, text, toggleClassIf, tweenAnimate, unmountBlock, unmountComponent, unmountInnerHTML, unmountIterator, unmountKeyIterator, unmountPartial, unmountSlot, updateAttributeExpression, updateAttributeExpressionNS, updateBlock, updateComponent, updateDefaultSlot, updateIncomingSlot, updateInnerHTML, updateIterator, updateKeyIterator, updatePartial, updateText };
//# sourceMappingURL=runtime.es.js.map

@@ -13,3 +13,3 @@ import { Component } from './component';

}
export declare type UpdateBlock<D = Scope> = (host: Component, injector: Injector, data: D) => number | void;
export declare type UpdateBlock<D = Scope> = (host: Component, data: D) => number | void;
export declare type UnmountBlock = (scope: Scope, host: Component) => void;

@@ -39,4 +39,5 @@ export interface Scope {

scope: Scope;
type: string;
target: Element;
listener?: EventListener;
pending?: EventListener;
}
import { Changes, ChangeSet } from './types';
import { Component } from './component';
export declare const animatingKey = "$$animating";
declare type ChangeCallback = (name: string, prev: any, next: any, ctx?: any) => void;
/**

@@ -11,15 +10,5 @@ * Creates fast object

* Check if given value id defined, e.g. not `null`, `undefined` or `NaN`
* @param {*} value
* @returns {boolean}
*/
export declare function isDefined(value: any): boolean;
/**
* Finalizes updated items, defined in `items.prev` and `items.cur`
* @param {object} items
* @param {function} change
* @param {*} [ctx]
* @returns {number} Returns `1` if data was updated, `0` otherwise
*/
export declare function finalizeItems(items: ChangeSet, change: ChangeCallback, ctx: any): number;
/**
* Creates object for storing change sets, e.g. current and previous values

@@ -26,0 +15,0 @@ */

{
"name": "@endorphinjs/template-runtime",
"version": "0.4.5",
"version": "0.5.0",
"description": "EndorphinJS template runtime, embedded with template bundles",

@@ -26,3 +26,3 @@ "main": "./dist/runtime.cjs.js",

"devDependencies": {
"@endorphinjs/template-compiler": "^0.4.5",
"@endorphinjs/template-compiler": "^0.5.0",
"@types/mocha": "^5.2.6",

@@ -53,3 +53,3 @@ "@types/node": "^11.13.10",

},
"gitHead": "1e768e8d1b61a919ab64123831d73b738a336d07"
"gitHead": "26809b00768921270e0b6ee4b0d6383e411644e7"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc