@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/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
- * Clones a given element, shallowly copying the props object.
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 jest test (cascades sync generator parent
741
- * and sync generator child) where synchronous code causes a stack overflow
742
- * error in a non-deterministic way. Deeply disturbing stuff.
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
- return addEventListener(this[$ContextImpl], type, listener, options);
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
- return removeEventListener(this[$ContextImpl], type, listener, options);
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
- return dispatchEvent(this[$ContextImpl], ev);
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 addEventListener(ctx, type, listener, options) {
1371
- let listeners;
1372
- if (listener == null) {
1373
- return;
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;