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

@bikeshaving/crank

Package Overview
Dependencies
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bikeshaving/crank - npm Package Compare versions

Comparing version 0.3.6 to 0.3.7

9

CHANGELOG.md
# Changelog
## [0.3.7] - 2020-11-16
Mostly some changes when trying to get Crank to play nicely with contenteditables
### Fixed
- Fixed TypeScript sourcemaps not being generated in builds (#165).
- Fixed empty arrays or otherwise non-empty element children not clearing out non-Crank DOM mutations (#167).
- Fixed rerenderings updating DOM Text nodes even when the contents have not changed (#169).
## [0.3.6] - 2020-10-13
### Fixed
- Changed the algorithm of patch slightly so that `setAttribute` is never used with object/function values.
## [0.3.5] - 2020-09-17

@@ -3,0 +12,0 @@ ### Fixed

17

cjs/crank.d.ts

@@ -7,3 +7,3 @@ /**

* elements, and their behavior is determined by the renderer, while elements
* whose tags are components are called “component” elements, and their
* whose tags are functions are called “component” elements, and their
* behavior is determined by the execution of the component.

@@ -30,3 +30,3 @@ */

*
* The tag is just the empty string, and you can use the empty string in
* This tag is just the empty string, and you can use the empty string in
* createElement calls or transpiler options to avoid having to reference this

@@ -133,3 +133,3 @@ * export directly.

* An object containing the “properties” of an element. These correspond to
* the “attributes” of an element when using JSX syntax.
* the attribute syntax from JSX.
*/

@@ -139,7 +139,6 @@ props: TagProps<TTag>;

* A value which uniquely identifies an element from its siblings so that it
* can be added/updated/moved/removed by the identity of the key rather than
* its position within the parent.
* can be added/updated/moved/removed by key rather than position.
*
* @remarks
* Passed to the element as the prop "crank-key".
* Passed in createElement() as the prop "crank-key".
*/

@@ -151,3 +150,3 @@ key: Key;

* @remarks
* Passed to the element as the prop "crank-ref".
* Passed in createElement() as the prop "crank-ref".
*/

@@ -184,4 +183,4 @@ ref: ((value: unknown) => unknown) | undefined;

* Until an element commits for the first time, we show any previously
* rendered values in its place. This is mainly important when the nearest
* host is rearranged concurrently.
* rendered values in its place. This allows the nearest host to be
* rearranged concurrently.
*/

@@ -188,0 +187,0 @@ _fb: NarrowedChild;

@@ -5,3 +5,2 @@ 'use strict';

/*** UTILITIES ***/
const NOOP = () => { };

@@ -12,11 +11,21 @@ function wrap(value) {

function unwrap(arr) {
return arr.length > 1 ? arr : arr[0];
return arr.length === 0 ? undefined : arr.length === 1 ? arr[0] : arr;
}
/**
* Ensures a value is an array.
*
* @remarks
* This function pretty much does the same thing as wrap above except it
* handles nulls and iterables, and shallowly clones arrays, so it is
* appropriate for wrapping user-provided children from el.props.
*/
function arrayify(value) {
return value == null
? []
: typeof value !== "string" &&
typeof value[Symbol.iterator] === "function"
? Array.from(value)
: [value];
: Array.isArray(value)
? value.slice()
: typeof value === "string" ||
typeof value[Symbol.iterator] !== "function"
? [value]
: [...value];
}

@@ -41,3 +50,3 @@ function isIteratorLike(value) {

*
* The tag is just the empty string, and you can use the empty string in
* This tag is just the empty string, and you can use the empty string in
* createElement calls or transpiler options to avoid having to reference this

@@ -82,3 +91,3 @@ * export directly.

/**
* A flag which is set when the component has been mounted. Used mainly to
* A flag which is set when the element has been mounted. Used mainly to
* detect whether an element is being reused so that we clone it.

@@ -88,3 +97,3 @@ */

/**
* A flag which is set when the component has committed at least once.
* A flag which is set when the element has committed at least once.
*/

@@ -96,4 +105,3 @@ const IsCommitted = 1 << 1;

// NOTE: to maximize compatibility between Crank versions, starting with 0.2.0,
// any change to the $$typeof property or public properties will be considered
// a breaking change.
// any change to Element’s properties will be considered a breaking change.
/**

@@ -135,2 +143,5 @@ * Elements are the basic building blocks of Crank applications. They are

// asynchronous components. This may or may not be a good idea.
//this._fb = undefined;
//this._inf = undefined;
//this._onv = undefined;
}

@@ -504,8 +515,8 @@ }

oldChild.tag === newChild.tag) {
if (oldChild.tag === Portal &&
oldChild.props.root !== newChild.props.root) {
renderer.arrange(oldChild, oldChild.props.root, []);
renderer.complete(oldChild.props.root);
}
// TODO: implement Raw element parse caching
if (oldChild.tag === Portal) {
if (oldChild.props.root !== newChild.props.root) {
renderer.arrange(oldChild, oldChild.props.root, []);
}
}
if (oldChild !== newChild) {

@@ -547,3 +558,3 @@ oldChild.props = newChild.props;

else if (typeof newChild === "string") {
value = renderer.escape(newChild, scope);
newChild = value = renderer.escape(newChild, scope);
}

@@ -573,16 +584,12 @@ return [newChild, value];

const values = [];
let async = false;
let seen;
let isAsync = false;
let seen = new Set();
for (let i = 0; i < newChildren.length; i++) {
let child = narrow(newChildren[i]);
if (typeof child === "object" && typeof child.key !== "undefined") {
if (seen === undefined) {
seen = new Set();
const key = child && child.key;
if (key !== undefined) {
if (seen.has(key)) {
console.error("Duplicate key", key);
}
else {
if (seen.has(child.key)) {
console.error("Duplicate key", child.key);
}
}
seen.add(child.key);
seen.add(key);
}

@@ -594,8 +601,6 @@ let value;

values.push(value);
if (!async && isPromiseLike(value)) {
async = true;
}
isAsync = isAsync || isPromiseLike(value);
}
el._ch = unwrap(newChildren);
if (async) {
if (isAsync) {
let onvalues;

@@ -620,5 +625,4 @@ const values1 = Promise.race([

function update(renderer, root, host, ctx, scope, el) {
if (typeof el.tag === "function") {
// el._ctx should probably never be undefined here
return el._ctx ? updateCtx(el._ctx) : undefined;
if (el._ctx) {
return updateCtx(el._ctx);
}

@@ -656,4 +660,4 @@ else if (el.tag === Raw) {

let i = 0;
let async = false;
let seen;
let isAsync = false;
let seen = new Set();
let childrenByKey;

@@ -665,5 +669,5 @@ // TODO: switch to mountChildren if there are no more children

// ALIGNMENT
let oldKey = typeof oldChild === "object" ? oldChild.key : undefined;
let newKey = typeof newChild === "object" ? newChild.key : undefined;
if (seen !== undefined && seen.has(newKey)) {
let oldKey = oldChild && oldChild.key;
let newKey = newChild && newChild.key;
if (newKey !== undefined && seen.has(newKey)) {
console.error("Duplicate key", newKey);

@@ -689,5 +693,2 @@ newKey = undefined;

}
if (!seen) {
seen = new Set();
}
seen.add(newKey);

@@ -707,5 +708,3 @@ }

newChildren[j] = newChild;
if (!async && isPromiseLike(value)) {
async = true;
}
isAsync = isAsync || isPromiseLike(value);
if (typeof oldChild === "object" && oldChild !== newChild) {

@@ -723,7 +722,6 @@ graveyard.push(oldChild);

}
// TODO: async unmounting
if (childrenByKey !== undefined && childrenByKey.size > 0) {
graveyard.push(...childrenByKey.values());
}
if (async) {
if (isAsync) {
let values1 = Promise.all(values).finally(() => {

@@ -752,8 +750,12 @@ graveyard.forEach((child) => unmount(renderer, host, ctx, child));

function commit(renderer, scope, el, values) {
let value = unwrap(values);
if (typeof el.tag === "function") {
if (typeof el._ctx === "object") {
commitCtx(el._ctx, value);
}
if (el._inf) {
el._inf = undefined;
}
if (el._fb) {
el._fb = undefined;
}
let value;
if (el._ctx) {
value = commitCtx(el._ctx, values);
}
else if (el.tag === Portal) {

@@ -765,3 +767,2 @@ if (!(el._f & IsCommitted)) {

renderer.complete(el.props.root);
value = undefined;
}

@@ -777,3 +778,6 @@ else if (el.tag === Raw) {

}
else if (el.tag !== Fragment) {
else if (el.tag === Fragment) {
value = unwrap(values);
}
else {
if (!(el._f & IsCommitted)) {

@@ -790,15 +794,7 @@ el._n = renderer.create(el, scope);

}
if (el._inf) {
el._inf = undefined;
}
if (el._fb) {
el._fb = undefined;
}
return value;
}
function unmount(renderer, host, ctx, el) {
if (typeof el.tag === "function") {
if (typeof el._ctx === "object") {
unmountCtx(el._ctx);
}
if (el._ctx) {
unmountCtx(el._ctx);
ctx = el._ctx;

@@ -1212,5 +1208,4 @@ }

const result1 = result instanceof Promise ? result : Promise.resolve(result);
const block = result1;
const value = result1.then((result) => updateCtxChildren(ctx, result));
return [block, value];
return [result1, value];
}

@@ -1253,3 +1248,2 @@ else {

}
const block = iteration;
const value = iteration.then((iteration) => {

@@ -1277,3 +1271,3 @@ if (!(ctx._f & IsIterating)) {

});
return [block, value];
return [iteration, value];
}

@@ -1327,3 +1321,3 @@ // sync generator component

let [block, value] = stepCtx(ctx);
if (isPromiseLike(block)) {
if (block) {
ctx._ib = block

@@ -1355,2 +1349,3 @@ .catch((err) => {

let resolve;
ctx._ev = new Promise((resolve1) => (resolve = resolve1));
ctx._eb = ctx._ib

@@ -1364,3 +1359,3 @@ .then(() => {

}
if (isPromiseLike(block)) {
if (block) {
return block.catch((err) => {

@@ -1380,3 +1375,2 @@ if (!(ctx._f & IsUpdating)) {

.finally(() => advanceCtx(ctx));
ctx._ev = new Promise((resolve1) => (resolve = resolve1));
}

@@ -1410,3 +1404,3 @@ return ctx._ev;

}
function commitCtx(ctx, value) {
function commitCtx(ctx, values) {
if (ctx._f & IsUnmounted) {

@@ -1416,6 +1410,6 @@ return;

if (typeof ctx._ls !== "undefined" && ctx._ls.length > 0) {
for (const child of wrap(value)) {
if (isEventTarget(child)) {
for (const v of values) {
if (isEventTarget(v)) {
for (const record of ctx._ls) {
child.addEventListener(record.type, record.callback, record.options);
v.addEventListener(record.type, record.callback, record.options);
}

@@ -1430,3 +1424,3 @@ }

const record = listeners[i];
for (const v of wrap(value)) {
for (const v of values) {
if (isEventTarget(v)) {

@@ -1446,2 +1440,3 @@ v.addEventListener(record.type, record.callback, record.options);

ctx._f &= ~IsUpdating;
const value = unwrap(values);
if (ctx._ss && ctx._ss.size > 0) {

@@ -1458,2 +1453,3 @@ // NOTE: We have to clear the set of callbacks before calling them, because

}
return value;
}

@@ -1460,0 +1456,0 @@ // TODO: async unmounting

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

const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
// TODO: maybe the HasChildren flag can be defined on (Crank) Element flags...
const HasChildren = Symbol.for("crank.HasChildren");
class DOMRenderer extends crank.Renderer {

@@ -138,27 +140,45 @@ render(children, root, ctx) {

}
if (!("innerHTML" in el.props) &&
(children.length !== 0 || node.__cranky)) {
if (("children" in el.props || node[HasChildren]) &&
!("innerHTML" in el.props)) {
if (children.length === 0) {
node.textContent = "";
return;
}
let oldChild = node.firstChild;
let i = 0;
while (oldChild !== null && i < children.length) {
const newChild = children[i];
if (oldChild === newChild) {
oldChild = oldChild.nextSibling;
i++;
}
else if (typeof newChild === "string") {
if (oldChild.nodeType === Node.TEXT_NODE) {
oldChild.nodeValue = newChild;
else {
let oldChild = node.firstChild;
let i = 0;
while (oldChild !== null && i < children.length) {
const newChild = children[i];
if (oldChild === newChild) {
oldChild = oldChild.nextSibling;
i++;
}
else if (typeof newChild === "string") {
if (oldChild.nodeType === Node.TEXT_NODE) {
if (oldChild.data !== newChild) {
oldChild.data = newChild;
}
oldChild = oldChild.nextSibling;
}
else {
node.insertBefore(document.createTextNode(newChild), oldChild);
}
i++;
}
else if (oldChild.nodeType === Node.TEXT_NODE) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
else {
node.insertBefore(document.createTextNode(newChild), oldChild);
node.insertBefore(newChild, oldChild);
i++;
// TODO: This is an optimization but we need to think a little more about other cases like prepending.
if (oldChild !== children[i]) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
}
i++;
}
else if (oldChild.nodeType === Node.TEXT_NODE) {
while (oldChild !== null) {
const nextSibling = oldChild.nextSibling;

@@ -168,31 +188,16 @@ node.removeChild(oldChild);

}
else {
node.insertBefore(newChild, oldChild);
i++;
// TODO: this is an optimization for the js frameworks benchmark swap rows, but we need to think a little more about other cases like prepending.
if (oldChild !== children[i]) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
for (; i < children.length; i++) {
const newChild = children[i];
node.appendChild(typeof newChild === "string"
? document.createTextNode(newChild)
: newChild);
}
}
while (oldChild !== null) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
for (; i < children.length; i++) {
const newChild = children[i];
node.appendChild(typeof newChild === "string"
? document.createTextNode(newChild)
: newChild);
}
if (children.length > 0) {
node.__cranky = true;
}
else if (node.__cranky) {
node.__cranky = false;
}
}
if (children.length > 0) {
node[HasChildren] = true;
}
else if (node[HasChildren]) {
node[HasChildren] = false;
}
}

@@ -199,0 +204,0 @@ }

@@ -7,3 +7,3 @@ /**

* elements, and their behavior is determined by the renderer, while elements
* whose tags are components are called “component” elements, and their
* whose tags are functions are called “component” elements, and their
* behavior is determined by the execution of the component.

@@ -30,3 +30,3 @@ */

*
* The tag is just the empty string, and you can use the empty string in
* This tag is just the empty string, and you can use the empty string in
* createElement calls or transpiler options to avoid having to reference this

@@ -133,3 +133,3 @@ * export directly.

* An object containing the “properties” of an element. These correspond to
* the “attributes” of an element when using JSX syntax.
* the attribute syntax from JSX.
*/

@@ -139,7 +139,6 @@ props: TagProps<TTag>;

* A value which uniquely identifies an element from its siblings so that it
* can be added/updated/moved/removed by the identity of the key rather than
* its position within the parent.
* can be added/updated/moved/removed by key rather than position.
*
* @remarks
* Passed to the element as the prop "crank-key".
* Passed in createElement() as the prop "crank-key".
*/

@@ -151,3 +150,3 @@ key: Key;

* @remarks
* Passed to the element as the prop "crank-ref".
* Passed in createElement() as the prop "crank-ref".
*/

@@ -184,4 +183,4 @@ ref: ((value: unknown) => unknown) | undefined;

* Until an element commits for the first time, we show any previously
* rendered values in its place. This is mainly important when the nearest
* host is rearranged concurrently.
* rendered values in its place. This allows the nearest host to be
* rearranged concurrently.
*/

@@ -188,0 +187,0 @@ _fb: NarrowedChild;

/// <reference types="./crank.d.ts" />
/*** UTILITIES ***/
const NOOP = () => { };

@@ -8,11 +7,21 @@ function wrap(value) {

function unwrap(arr) {
return arr.length > 1 ? arr : arr[0];
return arr.length === 0 ? undefined : arr.length === 1 ? arr[0] : arr;
}
/**
* Ensures a value is an array.
*
* @remarks
* This function pretty much does the same thing as wrap above except it
* handles nulls and iterables, and shallowly clones arrays, so it is
* appropriate for wrapping user-provided children from el.props.
*/
function arrayify(value) {
return value == null
? []
: typeof value !== "string" &&
typeof value[Symbol.iterator] === "function"
? Array.from(value)
: [value];
: Array.isArray(value)
? value.slice()
: typeof value === "string" ||
typeof value[Symbol.iterator] !== "function"
? [value]
: [...value];
}

@@ -37,3 +46,3 @@ function isIteratorLike(value) {

*
* The tag is just the empty string, and you can use the empty string in
* This tag is just the empty string, and you can use the empty string in
* createElement calls or transpiler options to avoid having to reference this

@@ -78,3 +87,3 @@ * export directly.

/**
* A flag which is set when the component has been mounted. Used mainly to
* A flag which is set when the element has been mounted. Used mainly to
* detect whether an element is being reused so that we clone it.

@@ -84,3 +93,3 @@ */

/**
* A flag which is set when the component has committed at least once.
* A flag which is set when the element has committed at least once.
*/

@@ -92,4 +101,3 @@ const IsCommitted = 1 << 1;

// NOTE: to maximize compatibility between Crank versions, starting with 0.2.0,
// any change to the $$typeof property or public properties will be considered
// a breaking change.
// any change to Element’s properties will be considered a breaking change.
/**

@@ -131,2 +139,5 @@ * Elements are the basic building blocks of Crank applications. They are

// asynchronous components. This may or may not be a good idea.
//this._fb = undefined;
//this._inf = undefined;
//this._onv = undefined;
}

@@ -500,8 +511,8 @@ }

oldChild.tag === newChild.tag) {
if (oldChild.tag === Portal &&
oldChild.props.root !== newChild.props.root) {
renderer.arrange(oldChild, oldChild.props.root, []);
renderer.complete(oldChild.props.root);
}
// TODO: implement Raw element parse caching
if (oldChild.tag === Portal) {
if (oldChild.props.root !== newChild.props.root) {
renderer.arrange(oldChild, oldChild.props.root, []);
}
}
if (oldChild !== newChild) {

@@ -543,3 +554,3 @@ oldChild.props = newChild.props;

else if (typeof newChild === "string") {
value = renderer.escape(newChild, scope);
newChild = value = renderer.escape(newChild, scope);
}

@@ -569,16 +580,12 @@ return [newChild, value];

const values = [];
let async = false;
let seen;
let isAsync = false;
let seen = new Set();
for (let i = 0; i < newChildren.length; i++) {
let child = narrow(newChildren[i]);
if (typeof child === "object" && typeof child.key !== "undefined") {
if (seen === undefined) {
seen = new Set();
const key = child && child.key;
if (key !== undefined) {
if (seen.has(key)) {
console.error("Duplicate key", key);
}
else {
if (seen.has(child.key)) {
console.error("Duplicate key", child.key);
}
}
seen.add(child.key);
seen.add(key);
}

@@ -590,8 +597,6 @@ let value;

values.push(value);
if (!async && isPromiseLike(value)) {
async = true;
}
isAsync = isAsync || isPromiseLike(value);
}
el._ch = unwrap(newChildren);
if (async) {
if (isAsync) {
let onvalues;

@@ -616,5 +621,4 @@ const values1 = Promise.race([

function update(renderer, root, host, ctx, scope, el) {
if (typeof el.tag === "function") {
// el._ctx should probably never be undefined here
return el._ctx ? updateCtx(el._ctx) : undefined;
if (el._ctx) {
return updateCtx(el._ctx);
}

@@ -652,4 +656,4 @@ else if (el.tag === Raw) {

let i = 0;
let async = false;
let seen;
let isAsync = false;
let seen = new Set();
let childrenByKey;

@@ -661,5 +665,5 @@ // TODO: switch to mountChildren if there are no more children

// ALIGNMENT
let oldKey = typeof oldChild === "object" ? oldChild.key : undefined;
let newKey = typeof newChild === "object" ? newChild.key : undefined;
if (seen !== undefined && seen.has(newKey)) {
let oldKey = oldChild && oldChild.key;
let newKey = newChild && newChild.key;
if (newKey !== undefined && seen.has(newKey)) {
console.error("Duplicate key", newKey);

@@ -685,5 +689,2 @@ newKey = undefined;

}
if (!seen) {
seen = new Set();
}
seen.add(newKey);

@@ -703,5 +704,3 @@ }

newChildren[j] = newChild;
if (!async && isPromiseLike(value)) {
async = true;
}
isAsync = isAsync || isPromiseLike(value);
if (typeof oldChild === "object" && oldChild !== newChild) {

@@ -719,7 +718,6 @@ graveyard.push(oldChild);

}
// TODO: async unmounting
if (childrenByKey !== undefined && childrenByKey.size > 0) {
graveyard.push(...childrenByKey.values());
}
if (async) {
if (isAsync) {
let values1 = Promise.all(values).finally(() => {

@@ -748,8 +746,12 @@ graveyard.forEach((child) => unmount(renderer, host, ctx, child));

function commit(renderer, scope, el, values) {
let value = unwrap(values);
if (typeof el.tag === "function") {
if (typeof el._ctx === "object") {
commitCtx(el._ctx, value);
}
if (el._inf) {
el._inf = undefined;
}
if (el._fb) {
el._fb = undefined;
}
let value;
if (el._ctx) {
value = commitCtx(el._ctx, values);
}
else if (el.tag === Portal) {

@@ -761,3 +763,2 @@ if (!(el._f & IsCommitted)) {

renderer.complete(el.props.root);
value = undefined;
}

@@ -773,3 +774,6 @@ else if (el.tag === Raw) {

}
else if (el.tag !== Fragment) {
else if (el.tag === Fragment) {
value = unwrap(values);
}
else {
if (!(el._f & IsCommitted)) {

@@ -786,15 +790,7 @@ el._n = renderer.create(el, scope);

}
if (el._inf) {
el._inf = undefined;
}
if (el._fb) {
el._fb = undefined;
}
return value;
}
function unmount(renderer, host, ctx, el) {
if (typeof el.tag === "function") {
if (typeof el._ctx === "object") {
unmountCtx(el._ctx);
}
if (el._ctx) {
unmountCtx(el._ctx);
ctx = el._ctx;

@@ -1208,5 +1204,4 @@ }

const result1 = result instanceof Promise ? result : Promise.resolve(result);
const block = result1;
const value = result1.then((result) => updateCtxChildren(ctx, result));
return [block, value];
return [result1, value];
}

@@ -1249,3 +1244,2 @@ else {

}
const block = iteration;
const value = iteration.then((iteration) => {

@@ -1273,3 +1267,3 @@ if (!(ctx._f & IsIterating)) {

});
return [block, value];
return [iteration, value];
}

@@ -1323,3 +1317,3 @@ // sync generator component

let [block, value] = stepCtx(ctx);
if (isPromiseLike(block)) {
if (block) {
ctx._ib = block

@@ -1351,2 +1345,3 @@ .catch((err) => {

let resolve;
ctx._ev = new Promise((resolve1) => (resolve = resolve1));
ctx._eb = ctx._ib

@@ -1360,3 +1355,3 @@ .then(() => {

}
if (isPromiseLike(block)) {
if (block) {
return block.catch((err) => {

@@ -1376,3 +1371,2 @@ if (!(ctx._f & IsUpdating)) {

.finally(() => advanceCtx(ctx));
ctx._ev = new Promise((resolve1) => (resolve = resolve1));
}

@@ -1406,3 +1400,3 @@ return ctx._ev;

}
function commitCtx(ctx, value) {
function commitCtx(ctx, values) {
if (ctx._f & IsUnmounted) {

@@ -1412,6 +1406,6 @@ return;

if (typeof ctx._ls !== "undefined" && ctx._ls.length > 0) {
for (const child of wrap(value)) {
if (isEventTarget(child)) {
for (const v of values) {
if (isEventTarget(v)) {
for (const record of ctx._ls) {
child.addEventListener(record.type, record.callback, record.options);
v.addEventListener(record.type, record.callback, record.options);
}

@@ -1426,3 +1420,3 @@ }

const record = listeners[i];
for (const v of wrap(value)) {
for (const v of values) {
if (isEventTarget(v)) {

@@ -1442,2 +1436,3 @@ v.addEventListener(record.type, record.callback, record.options);

ctx._f &= ~IsUpdating;
const value = unwrap(values);
if (ctx._ss && ctx._ss.size > 0) {

@@ -1454,2 +1449,3 @@ // NOTE: We have to clear the set of callbacks before calling them, because

}
return value;
}

@@ -1456,0 +1452,0 @@ // TODO: async unmounting

@@ -5,2 +5,4 @@ /// <reference types="./dom.d.ts" />

const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
// TODO: maybe the HasChildren flag can be defined on (Crank) Element flags...
const HasChildren = Symbol.for("crank.HasChildren");
class DOMRenderer extends Renderer {

@@ -135,27 +137,45 @@ render(children, root, ctx) {

}
if (!("innerHTML" in el.props) &&
(children.length !== 0 || node.__cranky)) {
if (("children" in el.props || node[HasChildren]) &&
!("innerHTML" in el.props)) {
if (children.length === 0) {
node.textContent = "";
return;
}
let oldChild = node.firstChild;
let i = 0;
while (oldChild !== null && i < children.length) {
const newChild = children[i];
if (oldChild === newChild) {
oldChild = oldChild.nextSibling;
i++;
}
else if (typeof newChild === "string") {
if (oldChild.nodeType === Node.TEXT_NODE) {
oldChild.nodeValue = newChild;
else {
let oldChild = node.firstChild;
let i = 0;
while (oldChild !== null && i < children.length) {
const newChild = children[i];
if (oldChild === newChild) {
oldChild = oldChild.nextSibling;
i++;
}
else if (typeof newChild === "string") {
if (oldChild.nodeType === Node.TEXT_NODE) {
if (oldChild.data !== newChild) {
oldChild.data = newChild;
}
oldChild = oldChild.nextSibling;
}
else {
node.insertBefore(document.createTextNode(newChild), oldChild);
}
i++;
}
else if (oldChild.nodeType === Node.TEXT_NODE) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
else {
node.insertBefore(document.createTextNode(newChild), oldChild);
node.insertBefore(newChild, oldChild);
i++;
// TODO: This is an optimization but we need to think a little more about other cases like prepending.
if (oldChild !== children[i]) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
}
i++;
}
else if (oldChild.nodeType === Node.TEXT_NODE) {
while (oldChild !== null) {
const nextSibling = oldChild.nextSibling;

@@ -165,31 +185,16 @@ node.removeChild(oldChild);

}
else {
node.insertBefore(newChild, oldChild);
i++;
// TODO: this is an optimization for the js frameworks benchmark swap rows, but we need to think a little more about other cases like prepending.
if (oldChild !== children[i]) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
for (; i < children.length; i++) {
const newChild = children[i];
node.appendChild(typeof newChild === "string"
? document.createTextNode(newChild)
: newChild);
}
}
while (oldChild !== null) {
const nextSibling = oldChild.nextSibling;
node.removeChild(oldChild);
oldChild = nextSibling;
}
for (; i < children.length; i++) {
const newChild = children[i];
node.appendChild(typeof newChild === "string"
? document.createTextNode(newChild)
: newChild);
}
if (children.length > 0) {
node.__cranky = true;
}
else if (node.__cranky) {
node.__cranky = false;
}
}
if (children.length > 0) {
node[HasChildren] = true;
}
else if (node[HasChildren]) {
node[HasChildren] = false;
}
}

@@ -196,0 +201,0 @@ }

{
"name": "@bikeshaving/crank",
"version": "0.3.6",
"version": "0.3.7",
"description": "Write JSX-driven components with functions, promises and generators.",

@@ -122,22 +122,22 @@ "homepage": "https://crank.js.org",

"devDependencies": {
"@types/jest": "^26.0.3",
"@typescript-eslint/eslint-plugin": "^3.5.0",
"@typescript-eslint/parser": "^3.5.0",
"core-js": "^3.6.5",
"eslint": "^7.3.1",
"eslint-config-prettier": "^6.10.1",
"eslint-plugin-jest": "^23.17.1",
"@types/jest": "^26.0.15",
"@typescript-eslint/eslint-plugin": "^4.7.0",
"@typescript-eslint/parser": "^4.7.0",
"core-js": "^3.7.0",
"eslint": "^7.13.0",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-jest": "^24.1.3",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.3",
"husky": "^4.2.5",
"jest": "^26.1.0",
"lint-staged": "^10.2.11",
"eslint-plugin-react": "^7.21.5",
"husky": "^4.3.0",
"jest": "^26.6.3",
"lint-staged": "^10.5.1",
"magic-string": "^0.25.7",
"prettier": "^2.0.4",
"rollup": "^2.18.1",
"rollup-plugin-typescript2": "^0.27.1",
"shx": "^0.3.2",
"ts-jest": "^26.1.1",
"ts-transform-import-path-rewrite": "^0.2.1",
"typescript": "^3.9.6"
"rollup": "^2.33.1",
"rollup-plugin-typescript2": "^0.29.0",
"shx": "^0.3.3",
"ts-jest": "^26.4.4",
"ts-transform-import-path-rewrite": "^0.3.0",
"typescript": "^4.0.5"
},

@@ -144,0 +144,0 @@ "publishConfig": {

@@ -7,3 +7,3 @@ /**

* elements, and their behavior is determined by the renderer, while elements
* whose tags are components are called “component” elements, and their
* whose tags are functions are called “component” elements, and their
* behavior is determined by the execution of the component.

@@ -30,3 +30,3 @@ */

*
* The tag is just the empty string, and you can use the empty string in
* This tag is just the empty string, and you can use the empty string in
* createElement calls or transpiler options to avoid having to reference this

@@ -133,3 +133,3 @@ * export directly.

* An object containing the “properties” of an element. These correspond to
* the “attributes” of an element when using JSX syntax.
* the attribute syntax from JSX.
*/

@@ -139,7 +139,6 @@ props: TagProps<TTag>;

* A value which uniquely identifies an element from its siblings so that it
* can be added/updated/moved/removed by the identity of the key rather than
* its position within the parent.
* can be added/updated/moved/removed by key rather than position.
*
* @remarks
* Passed to the element as the prop "crank-key".
* Passed in createElement() as the prop "crank-key".
*/

@@ -151,3 +150,3 @@ key: Key;

* @remarks
* Passed to the element as the prop "crank-ref".
* Passed in createElement() as the prop "crank-ref".
*/

@@ -184,4 +183,4 @@ ref: ((value: unknown) => unknown) | undefined;

* Until an element commits for the first time, we show any previously
* rendered values in its place. This is mainly important when the nearest
* host is rearranged concurrently.
* rendered values in its place. This allows the nearest host to be
* rearranged concurrently.
*/

@@ -188,0 +187,0 @@ _fb: NarrowedChild;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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