@b9g/crank 0.4.3 → 0.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -50
- package/crank.cjs +192 -171
- package/crank.cjs.map +1 -1
- package/crank.d.ts +3 -3
- package/crank.js +192 -172
- package/crank.js.map +1 -1
- package/dom.cjs.map +1 -1
- package/dom.js.map +1 -1
- package/html.cjs.map +1 -1
- package/html.js.map +1 -1
- package/index.cjs +3 -1
- package/index.cjs.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +2 -1
- package/index.js.map +1 -1
- package/package.json +32 -24
- package/umd.js +192 -171
- package/umd.js.map +1 -1
- package/xm.cjs +431 -0
- package/xm.cjs.map +1 -0
- package/xm.d.ts +2 -0
- package/xm.js +428 -0
- package/xm.js.map +1 -0
package/umd.js
CHANGED
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
this.static_ = static_;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
+
// See Element interface
|
|
113
114
|
Element.prototype.$$typeof = ElementSymbol;
|
|
114
115
|
function isElement(value) {
|
|
115
116
|
return value != null && value.$$typeof === ElementSymbol;
|
|
@@ -132,6 +133,7 @@
|
|
|
132
133
|
switch (name) {
|
|
133
134
|
case "crank-key":
|
|
134
135
|
case "c-key":
|
|
136
|
+
case "$key":
|
|
135
137
|
// We have to make sure we don’t assign null to the key because we
|
|
136
138
|
// don’t check for null keys in the diffing functions.
|
|
137
139
|
if (props[name] != null) {
|
|
@@ -140,12 +142,14 @@
|
|
|
140
142
|
break;
|
|
141
143
|
case "crank-ref":
|
|
142
144
|
case "c-ref":
|
|
145
|
+
case "$ref":
|
|
143
146
|
if (typeof props[name] === "function") {
|
|
144
147
|
ref = props[name];
|
|
145
148
|
}
|
|
146
149
|
break;
|
|
147
150
|
case "crank-static":
|
|
148
151
|
case "c-static":
|
|
152
|
+
case "$static":
|
|
149
153
|
static_ = !!props[name];
|
|
150
154
|
break;
|
|
151
155
|
default:
|
|
@@ -159,11 +163,27 @@
|
|
|
159
163
|
else if (children.length === 1) {
|
|
160
164
|
props1.children = children[0];
|
|
161
165
|
}
|
|
166
|
+
// string aliases for the special tags
|
|
167
|
+
// TODO: Does this logic belong here, or in the Element constructor
|
|
168
|
+
switch (tag) {
|
|
169
|
+
case "$FRAGMENT":
|
|
170
|
+
tag = Fragment;
|
|
171
|
+
break;
|
|
172
|
+
case "$PORTAL":
|
|
173
|
+
tag = Portal;
|
|
174
|
+
break;
|
|
175
|
+
case "$COPY":
|
|
176
|
+
tag = Copy;
|
|
177
|
+
break;
|
|
178
|
+
case "$RAW":
|
|
179
|
+
tag = Raw;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
162
182
|
return new Element(tag, props1, key, ref, static_);
|
|
163
183
|
}
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
|
|
184
|
+
/** A single-letter alias for createElement */
|
|
185
|
+
const c = createElement;
|
|
186
|
+
/** Clones a given element, shallowly copying the props object. */
|
|
167
187
|
function cloneElement(el) {
|
|
168
188
|
if (!isElement(el)) {
|
|
169
189
|
throw new TypeError("Cannot clone non-element");
|
|
@@ -737,9 +757,9 @@
|
|
|
737
757
|
*
|
|
738
758
|
* NOTE: This is mainly used to prevent some false positives in component
|
|
739
759
|
* yields or returns undefined warnings. The reason we’re using this versus
|
|
740
|
-
* IsUnmounted is a very troubling
|
|
741
|
-
*
|
|
742
|
-
*
|
|
760
|
+
* IsUnmounted is a very troubling test (cascades sync generator parent and
|
|
761
|
+
* sync generator child) where synchronous code causes a stack overflow error
|
|
762
|
+
* in a non-deterministic way. Deeply disturbing stuff.
|
|
743
763
|
*/
|
|
744
764
|
const IsErrored = 1 << 5;
|
|
745
765
|
/**
|
|
@@ -960,13 +980,170 @@
|
|
|
960
980
|
provisions.set(key, value);
|
|
961
981
|
}
|
|
962
982
|
addEventListener(type, listener, options) {
|
|
963
|
-
|
|
983
|
+
const impl = this[$ContextImpl];
|
|
984
|
+
let listeners;
|
|
985
|
+
if (!isListenerOrListenerObject(listener)) {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
else {
|
|
989
|
+
const listeners1 = listenersMap.get(impl);
|
|
990
|
+
if (listeners1) {
|
|
991
|
+
listeners = listeners1;
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
listeners = [];
|
|
995
|
+
listenersMap.set(impl, listeners);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
options = normalizeListenerOptions(options);
|
|
999
|
+
let callback;
|
|
1000
|
+
if (typeof listener === "object") {
|
|
1001
|
+
callback = () => listener.handleEvent.apply(listener, arguments);
|
|
1002
|
+
}
|
|
1003
|
+
else {
|
|
1004
|
+
callback = listener;
|
|
1005
|
+
}
|
|
1006
|
+
const record = { type, callback, listener, options };
|
|
1007
|
+
if (options.once) {
|
|
1008
|
+
record.callback = function () {
|
|
1009
|
+
const i = listeners.indexOf(record);
|
|
1010
|
+
if (i !== -1) {
|
|
1011
|
+
listeners.splice(i, 1);
|
|
1012
|
+
}
|
|
1013
|
+
return callback.apply(this, arguments);
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
if (listeners.some((record1) => record.type === record1.type &&
|
|
1017
|
+
record.listener === record1.listener &&
|
|
1018
|
+
!record.options.capture === !record1.options.capture)) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
listeners.push(record);
|
|
1022
|
+
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1023
|
+
for (const value of getChildValues(impl.ret)) {
|
|
1024
|
+
if (isEventTarget(value)) {
|
|
1025
|
+
value.addEventListener(record.type, record.callback, record.options);
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
964
1028
|
}
|
|
965
1029
|
removeEventListener(type, listener, options) {
|
|
966
|
-
|
|
1030
|
+
const impl = this[$ContextImpl];
|
|
1031
|
+
const listeners = listenersMap.get(impl);
|
|
1032
|
+
if (listeners == null || !isListenerOrListenerObject(listener)) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
const options1 = normalizeListenerOptions(options);
|
|
1036
|
+
const i = listeners.findIndex((record) => record.type === type &&
|
|
1037
|
+
record.listener === listener &&
|
|
1038
|
+
!record.options.capture === !options1.capture);
|
|
1039
|
+
if (i === -1) {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
const record = listeners[i];
|
|
1043
|
+
listeners.splice(i, 1);
|
|
1044
|
+
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1045
|
+
for (const value of getChildValues(impl.ret)) {
|
|
1046
|
+
if (isEventTarget(value)) {
|
|
1047
|
+
value.removeEventListener(record.type, record.callback, record.options);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
967
1050
|
}
|
|
968
1051
|
dispatchEvent(ev) {
|
|
969
|
-
|
|
1052
|
+
const impl = this[$ContextImpl];
|
|
1053
|
+
const path = [];
|
|
1054
|
+
for (let parent = impl.parent; parent !== undefined; parent = parent.parent) {
|
|
1055
|
+
path.push(parent);
|
|
1056
|
+
}
|
|
1057
|
+
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
1058
|
+
// only informs us if stopPropagation was called and there are no
|
|
1059
|
+
// properties which inform us if stopImmediatePropagation was called.
|
|
1060
|
+
let immediateCancelBubble = false;
|
|
1061
|
+
const stopImmediatePropagation = ev.stopImmediatePropagation;
|
|
1062
|
+
setEventProperty(ev, "stopImmediatePropagation", () => {
|
|
1063
|
+
immediateCancelBubble = true;
|
|
1064
|
+
return stopImmediatePropagation.call(ev);
|
|
1065
|
+
});
|
|
1066
|
+
setEventProperty(ev, "target", impl.ctx);
|
|
1067
|
+
// The only possible errors in this block are errors thrown by callbacks,
|
|
1068
|
+
// and dispatchEvent will only log these errors rather than throwing
|
|
1069
|
+
// them. Therefore, we place all code in a try block, log errors in the
|
|
1070
|
+
// catch block, and use an unsafe return statement in the finally block.
|
|
1071
|
+
//
|
|
1072
|
+
// Each early return within the try block returns true because while the
|
|
1073
|
+
// return value is overridden in the finally block, TypeScript
|
|
1074
|
+
// (justifiably) does not recognize the unsafe return statement.
|
|
1075
|
+
//
|
|
1076
|
+
// TODO: Run all callbacks even if one of them errors
|
|
1077
|
+
try {
|
|
1078
|
+
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1079
|
+
for (let i = path.length - 1; i >= 0; i--) {
|
|
1080
|
+
const target = path[i];
|
|
1081
|
+
const listeners = listenersMap.get(target);
|
|
1082
|
+
if (listeners) {
|
|
1083
|
+
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1084
|
+
for (const record of listeners) {
|
|
1085
|
+
if (record.type === ev.type && record.options.capture) {
|
|
1086
|
+
record.callback.call(target.ctx, ev);
|
|
1087
|
+
if (immediateCancelBubble) {
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (ev.cancelBubble) {
|
|
1094
|
+
return true;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
{
|
|
1098
|
+
const listeners = listenersMap.get(impl);
|
|
1099
|
+
if (listeners) {
|
|
1100
|
+
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1101
|
+
setEventProperty(ev, "currentTarget", impl.ctx);
|
|
1102
|
+
for (const record of listeners) {
|
|
1103
|
+
if (record.type === ev.type) {
|
|
1104
|
+
record.callback.call(impl.ctx, ev);
|
|
1105
|
+
if (immediateCancelBubble) {
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (ev.cancelBubble) {
|
|
1111
|
+
return true;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
if (ev.bubbles) {
|
|
1116
|
+
setEventProperty(ev, "eventPhase", BUBBLING_PHASE);
|
|
1117
|
+
for (let i = 0; i < path.length; i++) {
|
|
1118
|
+
const target = path[i];
|
|
1119
|
+
const listeners = listenersMap.get(target);
|
|
1120
|
+
if (listeners) {
|
|
1121
|
+
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1122
|
+
for (const record of listeners) {
|
|
1123
|
+
if (record.type === ev.type && !record.options.capture) {
|
|
1124
|
+
record.callback.call(target.ctx, ev);
|
|
1125
|
+
if (immediateCancelBubble) {
|
|
1126
|
+
return true;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
if (ev.cancelBubble) {
|
|
1132
|
+
return true;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
catch (err) {
|
|
1138
|
+
// TODO: Use setTimeout to rethrow the error.
|
|
1139
|
+
console.error(err);
|
|
1140
|
+
}
|
|
1141
|
+
finally {
|
|
1142
|
+
setEventProperty(ev, "eventPhase", NONE);
|
|
1143
|
+
setEventProperty(ev, "currentTarget", null);
|
|
1144
|
+
// eslint-disable-next-line no-unsafe-finally
|
|
1145
|
+
return !ev.defaultPrevented;
|
|
1146
|
+
}
|
|
970
1147
|
}
|
|
971
1148
|
}
|
|
972
1149
|
/*** PRIVATE CONTEXT FUNCTIONS ***/
|
|
@@ -1367,168 +1544,11 @@
|
|
|
1367
1544
|
const AT_TARGET = 2;
|
|
1368
1545
|
const BUBBLING_PHASE = 3;
|
|
1369
1546
|
const listenersMap = new WeakMap();
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
else {
|
|
1376
|
-
const listeners1 = listenersMap.get(ctx);
|
|
1377
|
-
if (listeners1) {
|
|
1378
|
-
listeners = listeners1;
|
|
1379
|
-
}
|
|
1380
|
-
else {
|
|
1381
|
-
listeners = [];
|
|
1382
|
-
listenersMap.set(ctx, listeners);
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
options = normalizeListenerOptions(options);
|
|
1386
|
-
let callback;
|
|
1387
|
-
if (typeof listener === "object") {
|
|
1388
|
-
callback = () => listener.handleEvent.apply(listener, arguments);
|
|
1389
|
-
}
|
|
1390
|
-
else {
|
|
1391
|
-
callback = listener;
|
|
1392
|
-
}
|
|
1393
|
-
const record = { type, callback, listener, options };
|
|
1394
|
-
if (options.once) {
|
|
1395
|
-
record.callback = function () {
|
|
1396
|
-
const i = listeners.indexOf(record);
|
|
1397
|
-
if (i !== -1) {
|
|
1398
|
-
listeners.splice(i, 1);
|
|
1399
|
-
}
|
|
1400
|
-
return callback.apply(this, arguments);
|
|
1401
|
-
};
|
|
1402
|
-
}
|
|
1403
|
-
if (listeners.some((record1) => record.type === record1.type &&
|
|
1404
|
-
record.listener === record1.listener &&
|
|
1405
|
-
!record.options.capture === !record1.options.capture)) {
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
|
-
listeners.push(record);
|
|
1409
|
-
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1410
|
-
for (const value of getChildValues(ctx.ret)) {
|
|
1411
|
-
if (isEventTarget(value)) {
|
|
1412
|
-
value.addEventListener(record.type, record.callback, record.options);
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
function removeEventListener(ctx, type, listener, options) {
|
|
1417
|
-
const listeners = listenersMap.get(ctx);
|
|
1418
|
-
if (listener == null || listeners == null) {
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
const options1 = normalizeListenerOptions(options);
|
|
1422
|
-
const i = listeners.findIndex((record) => record.type === type &&
|
|
1423
|
-
record.listener === listener &&
|
|
1424
|
-
!record.options.capture === !options1.capture);
|
|
1425
|
-
if (i === -1) {
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
const record = listeners[i];
|
|
1429
|
-
listeners.splice(i, 1);
|
|
1430
|
-
// TODO: is it possible to separate out the EventTarget delegation logic
|
|
1431
|
-
for (const value of getChildValues(ctx.ret)) {
|
|
1432
|
-
if (isEventTarget(value)) {
|
|
1433
|
-
value.removeEventListener(record.type, record.callback, record.options);
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
function dispatchEvent(ctx, ev) {
|
|
1438
|
-
const path = [];
|
|
1439
|
-
for (let parent = ctx.parent; parent !== undefined; parent = parent.parent) {
|
|
1440
|
-
path.push(parent);
|
|
1441
|
-
}
|
|
1442
|
-
// We patch the stopImmediatePropagation method because ev.cancelBubble
|
|
1443
|
-
// only informs us if stopPropagation was called and there are no
|
|
1444
|
-
// properties which inform us if stopImmediatePropagation was called.
|
|
1445
|
-
let immediateCancelBubble = false;
|
|
1446
|
-
const stopImmediatePropagation = ev.stopImmediatePropagation;
|
|
1447
|
-
setEventProperty(ev, "stopImmediatePropagation", () => {
|
|
1448
|
-
immediateCancelBubble = true;
|
|
1449
|
-
return stopImmediatePropagation.call(ev);
|
|
1450
|
-
});
|
|
1451
|
-
setEventProperty(ev, "target", ctx.ctx);
|
|
1452
|
-
// The only possible errors in this block are errors thrown by callbacks,
|
|
1453
|
-
// and dispatchEvent will only log these errors rather than throwing
|
|
1454
|
-
// them. Therefore, we place all code in a try block, log errors in the
|
|
1455
|
-
// catch block, and use an unsafe return statement in the finally block.
|
|
1456
|
-
//
|
|
1457
|
-
// Each early return within the try block returns true because while the
|
|
1458
|
-
// return value is overridden in the finally block, TypeScript
|
|
1459
|
-
// (justifiably) does not recognize the unsafe return statement.
|
|
1460
|
-
//
|
|
1461
|
-
// TODO: Run all callbacks even if one of them errors
|
|
1462
|
-
try {
|
|
1463
|
-
setEventProperty(ev, "eventPhase", CAPTURING_PHASE);
|
|
1464
|
-
for (let i = path.length - 1; i >= 0; i--) {
|
|
1465
|
-
const target = path[i];
|
|
1466
|
-
const listeners = listenersMap.get(target);
|
|
1467
|
-
if (listeners) {
|
|
1468
|
-
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1469
|
-
for (const record of listeners) {
|
|
1470
|
-
if (record.type === ev.type && record.options.capture) {
|
|
1471
|
-
record.callback.call(target.ctx, ev);
|
|
1472
|
-
if (immediateCancelBubble) {
|
|
1473
|
-
return true;
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
if (ev.cancelBubble) {
|
|
1479
|
-
return true;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
{
|
|
1483
|
-
const listeners = listenersMap.get(ctx);
|
|
1484
|
-
if (listeners) {
|
|
1485
|
-
setEventProperty(ev, "eventPhase", AT_TARGET);
|
|
1486
|
-
setEventProperty(ev, "currentTarget", ctx.ctx);
|
|
1487
|
-
for (const record of listeners) {
|
|
1488
|
-
if (record.type === ev.type) {
|
|
1489
|
-
record.callback.call(ctx.ctx, ev);
|
|
1490
|
-
if (immediateCancelBubble) {
|
|
1491
|
-
return true;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
if (ev.cancelBubble) {
|
|
1496
|
-
return true;
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
if (ev.bubbles) {
|
|
1501
|
-
setEventProperty(ev, "eventPhase", BUBBLING_PHASE);
|
|
1502
|
-
for (let i = 0; i < path.length; i++) {
|
|
1503
|
-
const target = path[i];
|
|
1504
|
-
const listeners = listenersMap.get(target);
|
|
1505
|
-
if (listeners) {
|
|
1506
|
-
setEventProperty(ev, "currentTarget", target.ctx);
|
|
1507
|
-
for (const record of listeners) {
|
|
1508
|
-
if (record.type === ev.type && !record.options.capture) {
|
|
1509
|
-
record.callback.call(target.ctx, ev);
|
|
1510
|
-
if (immediateCancelBubble) {
|
|
1511
|
-
return true;
|
|
1512
|
-
}
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
if (ev.cancelBubble) {
|
|
1517
|
-
return true;
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
catch (err) {
|
|
1523
|
-
// TODO: Use setTimeout to rethrow the error.
|
|
1524
|
-
console.error(err);
|
|
1525
|
-
}
|
|
1526
|
-
finally {
|
|
1527
|
-
setEventProperty(ev, "eventPhase", NONE);
|
|
1528
|
-
setEventProperty(ev, "currentTarget", null);
|
|
1529
|
-
// eslint-disable-next-line no-unsafe-finally
|
|
1530
|
-
return !ev.defaultPrevented;
|
|
1531
|
-
}
|
|
1547
|
+
function isListenerOrListenerObject(value) {
|
|
1548
|
+
return (typeof value === "function" ||
|
|
1549
|
+
(value !== null &&
|
|
1550
|
+
typeof value === "object" &&
|
|
1551
|
+
typeof value.handleEvent === "function"));
|
|
1532
1552
|
}
|
|
1533
1553
|
function normalizeListenerOptions(options) {
|
|
1534
1554
|
if (typeof options === "boolean") {
|
|
@@ -2012,6 +2032,7 @@
|
|
|
2012
2032
|
exports.Portal = Portal;
|
|
2013
2033
|
exports.Raw = Raw;
|
|
2014
2034
|
exports.Renderer = Renderer;
|
|
2035
|
+
exports.c = c;
|
|
2015
2036
|
exports.cloneElement = cloneElement;
|
|
2016
2037
|
exports.createElement = createElement;
|
|
2017
2038
|
exports.dom = dom;
|