@qwik.dev/core 2.0.0-beta.17 → 2.0.0-beta.18
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/bindings/qwik.darwin-arm64.node +0 -0
- package/bindings/qwik.linux-x64-gnu.node +0 -0
- package/bindings/qwik.win32-x64-msvc.node +0 -0
- package/bindings/qwik_wasm_bg.wasm +0 -0
- package/dist/backpatch/package.json +1 -1
- package/dist/build/package.json +1 -1
- package/dist/cli.mjs +57 -57
- package/dist/core-internal.d.ts +23 -30
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +1118 -688
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +753 -494
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.mjs +222 -220
- package/dist/qwikloader.debug.js +1 -1
- package/dist/qwikloader.js +1 -1
- package/dist/server.mjs +63 -105
- package/dist/starters/features/csr/package.json +1 -1
- package/dist/starters/features/playwright/playwright-report/index.html +0 -19
- package/dist/testing/index.d.ts +11 -11
- package/dist/testing/index.mjs +2907 -2466
- package/dist/testing/package.json +1 -1
- package/package.json +14 -11
- package/bindings/qwik.darwin-x64.node +0 -0
- package/bindings/qwik.wasm.cjs +0 -471
package/dist/core.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* @qwik.dev/core 2.0.0-beta.
|
|
3
|
+
* @qwik.dev/core 2.0.0-beta.18-dev+a8081d4
|
|
4
4
|
* Copyright QwikDev. All Rights Reserved.
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
|
|
@@ -14,7 +14,7 @@ import { p } from '@qwik.dev/core/preloader';
|
|
|
14
14
|
*
|
|
15
15
|
* @public
|
|
16
16
|
*/
|
|
17
|
-
const version = "2.0.0-beta.
|
|
17
|
+
const version = "2.0.0-beta.18-dev+a8081d4";
|
|
18
18
|
|
|
19
19
|
// same as isDev but separate so we can test
|
|
20
20
|
const qDev = globalThis.qDev !== false;
|
|
@@ -96,8 +96,8 @@ const isString = (v) => {
|
|
|
96
96
|
const isFunction = (v) => {
|
|
97
97
|
return typeof v === 'function';
|
|
98
98
|
};
|
|
99
|
-
const
|
|
100
|
-
return typeof v !== 'object' && typeof v !== 'function'
|
|
99
|
+
const isPrimitiveOrNullUndefined = (v) => {
|
|
100
|
+
return (typeof v !== 'object' && typeof v !== 'function') || v === null || v === undefined;
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
const codeToText = (code, ...parts) => {
|
|
@@ -248,6 +248,8 @@ const ELEMENT_KEY = 'q:key';
|
|
|
248
248
|
const ELEMENT_PROPS = 'q:props';
|
|
249
249
|
const ELEMENT_SEQ = 'q:seq';
|
|
250
250
|
const ELEMENT_SEQ_IDX = 'q:seqIdx';
|
|
251
|
+
const ITERATION_ITEM_SINGLE = 'q:p'; // Single iteration parameter (not an array)
|
|
252
|
+
const ITERATION_ITEM_MULTI = 'q:ps'; // Multiple iteration parameters (array)
|
|
251
253
|
/** Non serializable markers - always begins with `:` character */
|
|
252
254
|
const NON_SERIALIZABLE_MARKER_PREFIX = ':';
|
|
253
255
|
const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
|
|
@@ -260,6 +262,7 @@ const STREAM_BLOCK_END_COMMENT = 'qkssr-po';
|
|
|
260
262
|
const Q_PROPS_SEPARATOR = ':';
|
|
261
263
|
const dangerouslySetInnerHTML = 'dangerouslySetInnerHTML';
|
|
262
264
|
const qwikInspectorAttr = 'data-qwik-inspector';
|
|
265
|
+
const debugStyleScopeIdPrefixAttr = '__scopedStyleIdPrefix__';
|
|
263
266
|
|
|
264
267
|
// keep this import from core/build so the cjs build works
|
|
265
268
|
const createPlatform = () => {
|
|
@@ -388,17 +391,6 @@ const safeCall = (call, thenFn, rejectFn) => {
|
|
|
388
391
|
return rejectFn(e);
|
|
389
392
|
}
|
|
390
393
|
};
|
|
391
|
-
const catchError = (valueOrPromise, rejectFn) => {
|
|
392
|
-
try {
|
|
393
|
-
if (isPromise(valueOrPromise)) {
|
|
394
|
-
return valueOrPromise.catch(rejectFn);
|
|
395
|
-
}
|
|
396
|
-
return valueOrPromise;
|
|
397
|
-
}
|
|
398
|
-
catch (e) {
|
|
399
|
-
return rejectFn(e);
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
394
|
const maybeThen = (valueOrPromise, thenFn) => {
|
|
403
395
|
return isPromise(valueOrPromise)
|
|
404
396
|
? valueOrPromise.then(thenFn)
|
|
@@ -781,16 +773,11 @@ function vnode_cloneElementWithNamespace(elementVNode, parentVNode, namespace, n
|
|
|
781
773
|
}
|
|
782
774
|
return rootElement;
|
|
783
775
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
}
|
|
789
|
-
function isMath(tagOrVNode) {
|
|
790
|
-
return typeof tagOrVNode === 'string'
|
|
791
|
-
? isMathElement(tagOrVNode)
|
|
792
|
-
: (tagOrVNode.flags & 256 /* VNodeFlags.NS_math */) !== 0;
|
|
793
|
-
}
|
|
776
|
+
// reuse the same object to avoid creating new objects on every call
|
|
777
|
+
const NEW_NAMESPACE_DATA = {
|
|
778
|
+
elementNamespace: HTML_NS,
|
|
779
|
+
elementNamespaceFlag: 0 /* VNodeFlags.NS_html */,
|
|
780
|
+
};
|
|
794
781
|
function getNewElementNamespaceData(domParentVNode, tagOrVNode) {
|
|
795
782
|
const parentIsDefaultNamespace = domParentVNode
|
|
796
783
|
? !!vnode_getElementName(domParentVNode) && vnode_isDefaultNamespace(domParentVNode)
|
|
@@ -815,10 +802,28 @@ function getNewElementNamespaceData(domParentVNode, tagOrVNode) {
|
|
|
815
802
|
elementNamespace = isParentSvg ? SVG_NS : isParentMath ? MATH_NS : HTML_NS;
|
|
816
803
|
elementNamespaceFlag = domParentVNode.flags & 384 /* VNodeFlags.NAMESPACE_MASK */;
|
|
817
804
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
805
|
+
NEW_NAMESPACE_DATA.elementNamespace = elementNamespace;
|
|
806
|
+
NEW_NAMESPACE_DATA.elementNamespaceFlag = elementNamespaceFlag;
|
|
807
|
+
return NEW_NAMESPACE_DATA;
|
|
808
|
+
}
|
|
809
|
+
function isSvg(tagOrVNode) {
|
|
810
|
+
if (typeof tagOrVNode === 'string') {
|
|
811
|
+
return isSvgElement(tagOrVNode);
|
|
812
|
+
}
|
|
813
|
+
if (vnode_isElementVNode(tagOrVNode)) {
|
|
814
|
+
return (isSvgElement(vnode_getElementName(tagOrVNode)) || (tagOrVNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0);
|
|
815
|
+
}
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
function isMath(tagOrVNode) {
|
|
819
|
+
if (typeof tagOrVNode === 'string') {
|
|
820
|
+
return isMathElement(tagOrVNode);
|
|
821
|
+
}
|
|
822
|
+
if (vnode_isElementVNode(tagOrVNode)) {
|
|
823
|
+
return (isMathElement(vnode_getElementName(tagOrVNode)) ||
|
|
824
|
+
(tagOrVNode.flags & 256 /* VNodeFlags.NS_math */) !== 0);
|
|
825
|
+
}
|
|
826
|
+
return false;
|
|
822
827
|
}
|
|
823
828
|
function getAttributeNamespace(attributeName) {
|
|
824
829
|
switch (attributeName) {
|
|
@@ -854,18 +859,18 @@ class BackRef {
|
|
|
854
859
|
}
|
|
855
860
|
|
|
856
861
|
/** @internal */
|
|
857
|
-
class VNode
|
|
862
|
+
class VNode {
|
|
858
863
|
flags;
|
|
859
864
|
parent;
|
|
860
865
|
previousSibling;
|
|
861
866
|
nextSibling;
|
|
862
867
|
props;
|
|
868
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
863
869
|
slotParent = null;
|
|
864
870
|
dirty = 0 /* ChoreBits.NONE */;
|
|
865
871
|
dirtyChildren = null;
|
|
866
872
|
nextDirtyChildIndex = 0;
|
|
867
873
|
constructor(flags, parent, previousSibling, nextSibling, props) {
|
|
868
|
-
super();
|
|
869
874
|
this.flags = flags;
|
|
870
875
|
this.parent = parent;
|
|
871
876
|
this.previousSibling = previousSibling;
|
|
@@ -877,22 +882,29 @@ class VNode extends BackRef {
|
|
|
877
882
|
if (isDev) {
|
|
878
883
|
return vnode_toString.call(this);
|
|
879
884
|
}
|
|
880
|
-
return
|
|
885
|
+
return Object.prototype.toString.call(this);
|
|
881
886
|
}
|
|
882
887
|
}
|
|
883
888
|
|
|
884
889
|
/** @internal */
|
|
885
|
-
class
|
|
890
|
+
class VirtualVNode extends VNode {
|
|
886
891
|
key;
|
|
887
892
|
firstChild;
|
|
888
893
|
lastChild;
|
|
889
|
-
|
|
890
|
-
elementName;
|
|
891
|
-
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild, node, elementName) {
|
|
894
|
+
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild) {
|
|
892
895
|
super(flags, parent, previousSibling, nextSibling, props);
|
|
893
896
|
this.key = key;
|
|
894
897
|
this.firstChild = firstChild;
|
|
895
898
|
this.lastChild = lastChild;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/** @internal */
|
|
903
|
+
class ElementVNode extends VirtualVNode {
|
|
904
|
+
node;
|
|
905
|
+
elementName;
|
|
906
|
+
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild, node, elementName) {
|
|
907
|
+
super(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild);
|
|
896
908
|
this.node = node;
|
|
897
909
|
this.elementName = elementName;
|
|
898
910
|
}
|
|
@@ -911,19 +923,6 @@ class TextVNode extends VNode {
|
|
|
911
923
|
}
|
|
912
924
|
}
|
|
913
925
|
|
|
914
|
-
/** @internal */
|
|
915
|
-
class VirtualVNode extends VNode {
|
|
916
|
-
key;
|
|
917
|
-
firstChild;
|
|
918
|
-
lastChild;
|
|
919
|
-
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild) {
|
|
920
|
-
super(flags, parent, previousSibling, nextSibling, props);
|
|
921
|
-
this.key = key;
|
|
922
|
-
this.firstChild = firstChild;
|
|
923
|
-
this.lastChild = lastChild;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
|
|
927
926
|
/**
|
|
928
927
|
* @file Cursor queue management for cursor-based scheduling.
|
|
929
928
|
*
|
|
@@ -977,6 +976,7 @@ function getHighestPriorityCursor() {
|
|
|
977
976
|
function pauseCursor(cursor, container) {
|
|
978
977
|
pausedCursorQueue.push(cursor);
|
|
979
978
|
removeCursorFromQueue(cursor, container, true);
|
|
979
|
+
container.$pausedCursorCount$++;
|
|
980
980
|
}
|
|
981
981
|
function resumeCursor(cursor, container) {
|
|
982
982
|
const index = pausedCursorQueue.indexOf(cursor);
|
|
@@ -986,6 +986,7 @@ function resumeCursor(cursor, container) {
|
|
|
986
986
|
pausedCursorQueue[index] = pausedCursorQueue[lastIndex];
|
|
987
987
|
}
|
|
988
988
|
pausedCursorQueue.pop();
|
|
989
|
+
container.$pausedCursorCount$--;
|
|
989
990
|
}
|
|
990
991
|
addCursorToQueue(container, cursor);
|
|
991
992
|
}
|
|
@@ -995,9 +996,6 @@ function resumeCursor(cursor, container) {
|
|
|
995
996
|
* @param cursor - The cursor to remove
|
|
996
997
|
*/
|
|
997
998
|
function removeCursorFromQueue(cursor, container, keepCursorFlag) {
|
|
998
|
-
if (container.$cursorCount$ > 0) {
|
|
999
|
-
container.$cursorCount$--;
|
|
1000
|
-
}
|
|
1001
999
|
if (!keepCursorFlag) {
|
|
1002
1000
|
cursor.flags &= -65 /* VNodeFlags.Cursor */;
|
|
1003
1001
|
}
|
|
@@ -1011,6 +1009,7 @@ function removeCursorFromQueue(cursor, container, keepCursorFlag) {
|
|
|
1011
1009
|
// }
|
|
1012
1010
|
// globalCursorQueue.pop();
|
|
1013
1011
|
globalCursorQueue.splice(index, 1);
|
|
1012
|
+
container.$cursorCount$--;
|
|
1014
1013
|
}
|
|
1015
1014
|
}
|
|
1016
1015
|
|
|
@@ -1117,7 +1116,35 @@ class SignalImpl {
|
|
|
1117
1116
|
this.$untrackedValue$ = value;
|
|
1118
1117
|
}
|
|
1119
1118
|
get value() {
|
|
1120
|
-
|
|
1119
|
+
const ctx = tryGetInvokeContext();
|
|
1120
|
+
if (!ctx) {
|
|
1121
|
+
return this.untrackedValue;
|
|
1122
|
+
}
|
|
1123
|
+
if (this.$container$ === null) {
|
|
1124
|
+
if (!ctx.$container$) {
|
|
1125
|
+
return this.untrackedValue;
|
|
1126
|
+
}
|
|
1127
|
+
// Grab the container now we have access to it
|
|
1128
|
+
this.$container$ = ctx.$container$;
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
isDev &&
|
|
1132
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === this.$container$, 'Do not use signals across containers');
|
|
1133
|
+
}
|
|
1134
|
+
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1135
|
+
if (effectSubscriber) {
|
|
1136
|
+
// Let's make sure that we have a reference to this effect.
|
|
1137
|
+
// Adding reference is essentially adding a subscription, so if the signal
|
|
1138
|
+
// changes we know who to notify.
|
|
1139
|
+
ensureContainsSubscription((this.$effects$ ||= new Set()), effectSubscriber);
|
|
1140
|
+
// But when effect is scheduled in needs to be able to know which signals
|
|
1141
|
+
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1142
|
+
// to this signal.
|
|
1143
|
+
ensureContainsBackRef(effectSubscriber, this);
|
|
1144
|
+
(import.meta.env.TEST ? !isDomContainer(this.$container$) : isServer) &&
|
|
1145
|
+
addQrlToSerializationCtx(effectSubscriber, this.$container$);
|
|
1146
|
+
}
|
|
1147
|
+
return this.untrackedValue;
|
|
1121
1148
|
}
|
|
1122
1149
|
set value(value) {
|
|
1123
1150
|
if (value !== this.$untrackedValue$) {
|
|
@@ -1135,7 +1162,7 @@ class SignalImpl {
|
|
|
1135
1162
|
if (isDev) {
|
|
1136
1163
|
return (`[${this.constructor.name}${this.$flags$ & 1 /* SignalFlags.INVALID */ ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
|
|
1137
1164
|
(Array.from(this.$effects$ || [])
|
|
1138
|
-
.map((e) => '\n -> ' + pad(qwikDebugToString(e
|
|
1165
|
+
.map((e) => '\n -> ' + pad(qwikDebugToString(e.consumer), ' '))
|
|
1139
1166
|
.join('\n') || ''));
|
|
1140
1167
|
}
|
|
1141
1168
|
else {
|
|
@@ -1146,34 +1173,33 @@ class SignalImpl {
|
|
|
1146
1173
|
return { value: this.$untrackedValue$ };
|
|
1147
1174
|
}
|
|
1148
1175
|
}
|
|
1149
|
-
const addEffect = (signal, effectSubscriber, effects) => {
|
|
1150
|
-
// Let's make sure that we have a reference to this effect.
|
|
1151
|
-
// Adding reference is essentially adding a subscription, so if the signal
|
|
1152
|
-
// changes we know who to notify.
|
|
1153
|
-
ensureContainsSubscription(effects, effectSubscriber);
|
|
1154
|
-
// But when effect is scheduled in needs to be able to know which signals
|
|
1155
|
-
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1156
|
-
// to this signal.
|
|
1157
|
-
ensureContainsBackRef(effectSubscriber, signal);
|
|
1158
|
-
addQrlToSerializationCtx(effectSubscriber, signal.$container$);
|
|
1159
|
-
};
|
|
1160
1176
|
const setupSignalValueAccess = (target, effectsFn, returnValueFn) => {
|
|
1161
1177
|
const ctx = tryGetInvokeContext();
|
|
1162
|
-
if (ctx) {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
target.$container$ = ctx.$container$;
|
|
1178
|
+
if (!ctx) {
|
|
1179
|
+
return returnValueFn();
|
|
1180
|
+
}
|
|
1181
|
+
if (target.$container$ === null) {
|
|
1182
|
+
if (!ctx.$container$) {
|
|
1183
|
+
return returnValueFn();
|
|
1169
1184
|
}
|
|
1170
|
-
|
|
1185
|
+
// Grab the container now we have access to it
|
|
1186
|
+
target.$container$ = ctx.$container$;
|
|
1187
|
+
}
|
|
1188
|
+
else {
|
|
1189
|
+
isDev &&
|
|
1171
1190
|
assertTrue(!ctx.$container$ || ctx.$container$ === target.$container$, 'Do not use signals across containers');
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1191
|
+
}
|
|
1192
|
+
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1193
|
+
if (effectSubscriber) {
|
|
1194
|
+
// Let's make sure that we have a reference to this effect.
|
|
1195
|
+
// Adding reference is essentially adding a subscription, so if the signal
|
|
1196
|
+
// changes we know who to notify.
|
|
1197
|
+
ensureContainsSubscription(effectsFn(), effectSubscriber);
|
|
1198
|
+
// But when effect is scheduled in needs to be able to know which signals
|
|
1199
|
+
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1200
|
+
// to this signal.
|
|
1201
|
+
ensureContainsBackRef(effectSubscriber, target);
|
|
1202
|
+
addQrlToSerializationCtx(effectSubscriber, target.$container$);
|
|
1177
1203
|
}
|
|
1178
1204
|
return returnValueFn();
|
|
1179
1205
|
};
|
|
@@ -1203,9 +1229,13 @@ const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
|
1203
1229
|
*/
|
|
1204
1230
|
const EVENT_SUFFIX = '$';
|
|
1205
1231
|
const isHtmlAttributeAnEventName = (name) => {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1232
|
+
if (name.charCodeAt(0) !== 111 /* o */ || name.charCodeAt(1) !== 110 /* n */) {
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
if (name.charCodeAt(2) === 58 /* : */) {
|
|
1236
|
+
return true; // on:
|
|
1237
|
+
}
|
|
1238
|
+
return name.startsWith("on-window:" /* EventNameHtmlScope.window */) || name.startsWith("on-document:" /* EventNameHtmlScope.document */);
|
|
1209
1239
|
};
|
|
1210
1240
|
function jsxEventToHtmlAttribute(jsxEvent) {
|
|
1211
1241
|
if (jsxEvent.endsWith(EVENT_SUFFIX)) {
|
|
@@ -1431,7 +1461,8 @@ const addPropsProxyEffect = (propsProxy, prop) => {
|
|
|
1431
1461
|
}
|
|
1432
1462
|
}
|
|
1433
1463
|
else {
|
|
1434
|
-
|
|
1464
|
+
isDev &&
|
|
1465
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
1435
1466
|
}
|
|
1436
1467
|
}
|
|
1437
1468
|
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
@@ -1444,6 +1475,7 @@ const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
|
1444
1475
|
if (effects) {
|
|
1445
1476
|
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
1446
1477
|
}
|
|
1478
|
+
return !!effects;
|
|
1447
1479
|
};
|
|
1448
1480
|
function getEffects$1(effects, prop) {
|
|
1449
1481
|
// TODO: Handle STORE_ALL_PROPS
|
|
@@ -1493,30 +1525,6 @@ const cleanupDestroyable = (destroyable) => {
|
|
|
1493
1525
|
}
|
|
1494
1526
|
};
|
|
1495
1527
|
|
|
1496
|
-
function getSubscriber(effect, prop, data) {
|
|
1497
|
-
if (!effect[_EFFECT_BACK_REF]) {
|
|
1498
|
-
if (isServer && isSsrNode(effect)) {
|
|
1499
|
-
effect.setProp(QBackRefs, new Map());
|
|
1500
|
-
}
|
|
1501
|
-
else {
|
|
1502
|
-
effect[_EFFECT_BACK_REF] = new Map();
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
const subMap = effect[_EFFECT_BACK_REF];
|
|
1506
|
-
let sub = subMap.get(prop);
|
|
1507
|
-
if (!sub) {
|
|
1508
|
-
sub = [effect, prop];
|
|
1509
|
-
subMap.set(prop, sub);
|
|
1510
|
-
}
|
|
1511
|
-
if (data) {
|
|
1512
|
-
sub[3 /* EffectSubscriptionProp.DATA */] = data;
|
|
1513
|
-
}
|
|
1514
|
-
return sub;
|
|
1515
|
-
}
|
|
1516
|
-
function isSsrNode(value) {
|
|
1517
|
-
return '__brand__' in value && value.__brand__ === 'SsrNode';
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
1528
|
/**
|
|
1521
1529
|
* # ================================
|
|
1522
1530
|
*
|
|
@@ -1529,6 +1537,54 @@ function isSsrNode(value) {
|
|
|
1529
1537
|
* "marked as dirty" flag.
|
|
1530
1538
|
*/
|
|
1531
1539
|
const NEEDS_COMPUTATION = Symbol('invalid');
|
|
1540
|
+
/**
|
|
1541
|
+
* An effect consumer plus type of effect, back references to producers and additional data
|
|
1542
|
+
*
|
|
1543
|
+
* An effect can be trigger by one or more of signal inputs. The first step of re-running an effect
|
|
1544
|
+
* is to clear its subscriptions so that the effect can re add new set of subscriptions. In order to
|
|
1545
|
+
* clear the subscriptions we need to store them here.
|
|
1546
|
+
*
|
|
1547
|
+
* Imagine you have effect such as:
|
|
1548
|
+
*
|
|
1549
|
+
* ```
|
|
1550
|
+
* function effect1() {
|
|
1551
|
+
* console.log(signalA.value ? signalB.value : 'default');
|
|
1552
|
+
* }
|
|
1553
|
+
* ```
|
|
1554
|
+
*
|
|
1555
|
+
* In the above case the `signalB` needs to be unsubscribed when `signalA` is falsy. We do this by
|
|
1556
|
+
* always clearing all of the subscriptions
|
|
1557
|
+
*
|
|
1558
|
+
* The `EffectSubscription` stores
|
|
1559
|
+
*
|
|
1560
|
+
* ```
|
|
1561
|
+
* subscription1 = [effectConsumer1, EffectProperty.COMPONENT, Set[(signalA, signalB)]];
|
|
1562
|
+
* ```
|
|
1563
|
+
*
|
|
1564
|
+
* The `signal1` and `signal2` back references are needed to "clear" existing subscriptions.
|
|
1565
|
+
*
|
|
1566
|
+
* Both `signalA` as well as `signalB` will have a reference to `subscription` to the so that the
|
|
1567
|
+
* effect can be scheduled if either `signalA` or `signalB` triggers. The `subscription1` is shared
|
|
1568
|
+
* between the signals.
|
|
1569
|
+
*
|
|
1570
|
+
* The second position `EffectProperty|string` store the property name of the effect.
|
|
1571
|
+
*
|
|
1572
|
+
* - Property name of the VNode
|
|
1573
|
+
* - `EffectProperty.COMPONENT` if component
|
|
1574
|
+
* - `EffectProperty.VNODE` if VNode
|
|
1575
|
+
*/
|
|
1576
|
+
class EffectSubscription {
|
|
1577
|
+
consumer;
|
|
1578
|
+
property;
|
|
1579
|
+
backRef;
|
|
1580
|
+
data;
|
|
1581
|
+
constructor(consumer, property, backRef = null, data = null) {
|
|
1582
|
+
this.consumer = consumer;
|
|
1583
|
+
this.property = property;
|
|
1584
|
+
this.backRef = backRef;
|
|
1585
|
+
this.data = data;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1532
1588
|
/**
|
|
1533
1589
|
* # ================================
|
|
1534
1590
|
*
|
|
@@ -1540,6 +1596,30 @@ const STORE_TARGET = Symbol('store.target');
|
|
|
1540
1596
|
const STORE_HANDLER = Symbol('store.handler');
|
|
1541
1597
|
const STORE_ALL_PROPS = Symbol('store.all');
|
|
1542
1598
|
|
|
1599
|
+
function getSubscriber(effect, prop, data) {
|
|
1600
|
+
if (!effect[_EFFECT_BACK_REF]) {
|
|
1601
|
+
if (isServer && isSsrNode(effect)) {
|
|
1602
|
+
effect.setProp(QBackRefs, new Map());
|
|
1603
|
+
}
|
|
1604
|
+
else {
|
|
1605
|
+
effect[_EFFECT_BACK_REF] = new Map();
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
const subMap = effect[_EFFECT_BACK_REF];
|
|
1609
|
+
let sub = subMap.get(prop);
|
|
1610
|
+
if (!sub) {
|
|
1611
|
+
sub = new EffectSubscription(effect, prop);
|
|
1612
|
+
subMap.set(prop, sub);
|
|
1613
|
+
}
|
|
1614
|
+
if (data) {
|
|
1615
|
+
sub.data = data;
|
|
1616
|
+
}
|
|
1617
|
+
return sub;
|
|
1618
|
+
}
|
|
1619
|
+
function isSsrNode(value) {
|
|
1620
|
+
return '__brand__' in value && value.__brand__ === 'SsrNode';
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1543
1623
|
const trackFn = (target, container) => (obj, prop) => {
|
|
1544
1624
|
const ctx = newInvokeContext();
|
|
1545
1625
|
ctx.$effectSubscriber$ = getSubscriber(target, ":" /* EffectProperty.COMPONENT */);
|
|
@@ -1639,7 +1719,7 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1639
1719
|
}
|
|
1640
1720
|
get untrackedValue() {
|
|
1641
1721
|
this.$computeIfNeeded$();
|
|
1642
|
-
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1722
|
+
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1643
1723
|
return this.$untrackedValue$;
|
|
1644
1724
|
}
|
|
1645
1725
|
$computeIfNeeded$() {
|
|
@@ -1650,7 +1730,11 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1650
1730
|
throwIfQRLNotResolved(computeQrl);
|
|
1651
1731
|
const ctx = tryGetInvokeContext();
|
|
1652
1732
|
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
1653
|
-
|
|
1733
|
+
if (ctx) {
|
|
1734
|
+
const effectSubscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
1735
|
+
clearEffectSubscription(this.$container$, effectSubscriber);
|
|
1736
|
+
ctx.$effectSubscriber$ = effectSubscriber;
|
|
1737
|
+
}
|
|
1654
1738
|
try {
|
|
1655
1739
|
const untrackedValue = computeQrl.getFn(ctx)();
|
|
1656
1740
|
if (isPromise(untrackedValue)) {
|
|
@@ -1993,7 +2077,7 @@ const _wrapProp = (...args) => {
|
|
|
1993
2077
|
}
|
|
1994
2078
|
if (isSignal(obj)) {
|
|
1995
2079
|
if (!(obj instanceof AsyncComputedSignalImpl)) {
|
|
1996
|
-
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
2080
|
+
isDev && assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
1997
2081
|
}
|
|
1998
2082
|
if (obj instanceof WrappedSignalImpl && obj.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
1999
2083
|
return obj;
|
|
@@ -2003,11 +2087,11 @@ const _wrapProp = (...args) => {
|
|
|
2003
2087
|
if (isPropsProxy(obj)) {
|
|
2004
2088
|
const constProps = obj[_CONST_PROPS];
|
|
2005
2089
|
const varProps = obj[_VAR_PROPS];
|
|
2006
|
-
if (constProps && prop
|
|
2090
|
+
if (constProps && Object.prototype.hasOwnProperty.call(constProps, prop)) {
|
|
2007
2091
|
// Const props don't need wrapping
|
|
2008
2092
|
return constProps[prop];
|
|
2009
2093
|
}
|
|
2010
|
-
else if (prop
|
|
2094
|
+
else if (Object.prototype.hasOwnProperty.call(varProps, prop)) {
|
|
2011
2095
|
const value = varProps[prop];
|
|
2012
2096
|
return wrapIfNotSignal(value, args);
|
|
2013
2097
|
}
|
|
@@ -2086,7 +2170,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
2086
2170
|
}
|
|
2087
2171
|
get untrackedValue() {
|
|
2088
2172
|
this.$computeIfNeeded$();
|
|
2089
|
-
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2173
|
+
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2090
2174
|
return this.$untrackedValue$;
|
|
2091
2175
|
}
|
|
2092
2176
|
$computeIfNeeded$() {
|
|
@@ -2137,7 +2221,7 @@ function clearAllEffects(container, consumer) {
|
|
|
2137
2221
|
effects.clear();
|
|
2138
2222
|
}
|
|
2139
2223
|
function clearEffectSubscription(container, effect) {
|
|
2140
|
-
const backRefs = effect
|
|
2224
|
+
const backRefs = effect.backRef;
|
|
2141
2225
|
if (!backRefs) {
|
|
2142
2226
|
return;
|
|
2143
2227
|
}
|
|
@@ -2221,15 +2305,17 @@ const useLexicalScope = () => {
|
|
|
2221
2305
|
let qrl = context.$qrl$;
|
|
2222
2306
|
if (!qrl) {
|
|
2223
2307
|
const el = context.$hostElement$ instanceof ElementVNode ? context.$hostElement$.node : undefined;
|
|
2224
|
-
assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
2308
|
+
isDev && assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
2225
2309
|
const containerElement = _getQContainerElement(el);
|
|
2226
|
-
assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
2310
|
+
isDev && assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
2227
2311
|
const container = getDomContainer(containerElement);
|
|
2312
|
+
context.$container$ ||= container;
|
|
2228
2313
|
qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
|
|
2229
2314
|
}
|
|
2230
2315
|
else {
|
|
2231
|
-
assertQrl(qrl);
|
|
2232
|
-
|
|
2316
|
+
isDev && assertQrl(qrl);
|
|
2317
|
+
isDev &&
|
|
2318
|
+
assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
|
|
2233
2319
|
}
|
|
2234
2320
|
return qrl.$captureRef$;
|
|
2235
2321
|
};
|
|
@@ -2253,85 +2339,30 @@ const _chk = (_, element) => {
|
|
|
2253
2339
|
signal.value = element.checked;
|
|
2254
2340
|
};
|
|
2255
2341
|
|
|
2256
|
-
const _hasOwnProperty$
|
|
2257
|
-
const BIND_VALUE = 'bind:value';
|
|
2258
|
-
const BIND_CHECKED = 'bind:checked';
|
|
2342
|
+
const _hasOwnProperty$2 = Object.prototype.hasOwnProperty;
|
|
2259
2343
|
// TODO store props as the arrays the vnodes also use?
|
|
2260
2344
|
class JSXNodeImpl {
|
|
2261
2345
|
type;
|
|
2346
|
+
children;
|
|
2262
2347
|
toSort;
|
|
2263
2348
|
key;
|
|
2264
2349
|
varProps;
|
|
2265
2350
|
constProps;
|
|
2266
|
-
children;
|
|
2267
2351
|
dev;
|
|
2268
2352
|
_proxy = null;
|
|
2269
2353
|
constructor(type, varProps, constProps, children, key, toSort, dev) {
|
|
2270
2354
|
this.type = type;
|
|
2355
|
+
this.children = children;
|
|
2271
2356
|
this.toSort = !!toSort;
|
|
2272
|
-
this.key = key
|
|
2357
|
+
this.key = key === null || key === undefined ? null : typeof key === 'string' ? key : '' + key;
|
|
2273
2358
|
this.varProps = !varProps || isEmpty(varProps) ? EMPTY_OBJ : varProps;
|
|
2274
2359
|
this.constProps = !constProps || isEmpty(constProps) ? null : constProps;
|
|
2275
|
-
this.children = children;
|
|
2276
2360
|
if (qDev && dev) {
|
|
2277
2361
|
this.dev = {
|
|
2278
2362
|
...dev,
|
|
2279
2363
|
stack: new Error().stack?.split('\n').slice(2).join('\n'),
|
|
2280
2364
|
};
|
|
2281
2365
|
}
|
|
2282
|
-
if (typeof type === 'string') {
|
|
2283
|
-
// convert onEvent$ to on:event
|
|
2284
|
-
for (const k in this.constProps) {
|
|
2285
|
-
const attr = jsxEventToHtmlAttribute(k);
|
|
2286
|
-
if (attr) {
|
|
2287
|
-
mergeHandlers(this.constProps, attr, this.constProps[k]);
|
|
2288
|
-
delete this.constProps[k];
|
|
2289
|
-
}
|
|
2290
|
-
}
|
|
2291
|
-
for (const k in this.varProps) {
|
|
2292
|
-
const attr = jsxEventToHtmlAttribute(k);
|
|
2293
|
-
if (attr) {
|
|
2294
|
-
// constProps always wins
|
|
2295
|
-
if (!constProps || !_hasOwnProperty$1.call(constProps, k)) {
|
|
2296
|
-
toSort = mergeHandlers(this.varProps, attr, this.varProps[k]) || toSort;
|
|
2297
|
-
}
|
|
2298
|
-
delete this.varProps[k];
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
// bind:*
|
|
2302
|
-
if (_hasOwnProperty$1.call(this.varProps, BIND_CHECKED)) {
|
|
2303
|
-
toSort = handleBindProp(this.varProps, BIND_CHECKED) || toSort;
|
|
2304
|
-
}
|
|
2305
|
-
else if (_hasOwnProperty$1.call(this.varProps, BIND_VALUE)) {
|
|
2306
|
-
toSort = handleBindProp(this.varProps, BIND_VALUE) || toSort;
|
|
2307
|
-
}
|
|
2308
|
-
else if (this.constProps) {
|
|
2309
|
-
if (_hasOwnProperty$1.call(this.constProps, BIND_CHECKED)) {
|
|
2310
|
-
handleBindProp(this.constProps, BIND_CHECKED);
|
|
2311
|
-
}
|
|
2312
|
-
else {
|
|
2313
|
-
if (_hasOwnProperty$1.call(this.constProps, BIND_VALUE)) {
|
|
2314
|
-
handleBindProp(this.constProps, BIND_VALUE);
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
if (_hasOwnProperty$1.call(this.varProps, 'className')) {
|
|
2319
|
-
this.varProps.class = this.varProps.className;
|
|
2320
|
-
this.varProps.className = undefined;
|
|
2321
|
-
toSort = true;
|
|
2322
|
-
if (qDev) {
|
|
2323
|
-
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2324
|
-
}
|
|
2325
|
-
}
|
|
2326
|
-
// TODO let the optimizer do this instead
|
|
2327
|
-
if (this.constProps && _hasOwnProperty$1.call(this.constProps, 'className')) {
|
|
2328
|
-
this.constProps.class = this.constProps.className;
|
|
2329
|
-
this.constProps.className = undefined;
|
|
2330
|
-
if (qDev) {
|
|
2331
|
-
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
2366
|
seal(this);
|
|
2336
2367
|
}
|
|
2337
2368
|
get props() {
|
|
@@ -2362,9 +2393,9 @@ const isJSXNode = (n) => {
|
|
|
2362
2393
|
return true;
|
|
2363
2394
|
}
|
|
2364
2395
|
if (isObject(n) &&
|
|
2365
|
-
_hasOwnProperty$
|
|
2366
|
-
_hasOwnProperty$
|
|
2367
|
-
_hasOwnProperty$
|
|
2396
|
+
_hasOwnProperty$2.call(n, 'key') &&
|
|
2397
|
+
_hasOwnProperty$2.call(n, 'props') &&
|
|
2398
|
+
_hasOwnProperty$2.call(n, 'type')) {
|
|
2368
2399
|
logWarn(`Duplicate implementations of "JSXNode" found`);
|
|
2369
2400
|
return true;
|
|
2370
2401
|
}
|
|
@@ -2375,29 +2406,12 @@ const isJSXNode = (n) => {
|
|
|
2375
2406
|
}
|
|
2376
2407
|
};
|
|
2377
2408
|
const isEmpty = (obj) => {
|
|
2378
|
-
|
|
2379
|
-
if (obj[prop] !== undefined) {
|
|
2380
|
-
return false;
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
return true;
|
|
2384
|
-
};
|
|
2385
|
-
const handleBindProp = (props, prop) => {
|
|
2386
|
-
const value = props[prop];
|
|
2387
|
-
props[prop] = undefined;
|
|
2388
|
-
if (value) {
|
|
2389
|
-
if (prop === BIND_CHECKED) {
|
|
2390
|
-
props.checked = value;
|
|
2391
|
-
props['on:input'] = createQRL(null, '_chk', _chk, null, null, [value]);
|
|
2392
|
-
}
|
|
2393
|
-
else {
|
|
2394
|
-
props.value = value;
|
|
2395
|
-
props['on:input'] = createQRL(null, '_val', _val, null, null, [value]);
|
|
2396
|
-
}
|
|
2397
|
-
return true;
|
|
2398
|
-
}
|
|
2409
|
+
return Object.keys(obj).length === 0;
|
|
2399
2410
|
};
|
|
2400
2411
|
|
|
2412
|
+
const BIND_VALUE = 'bind:value';
|
|
2413
|
+
const BIND_CHECKED = 'bind:checked';
|
|
2414
|
+
const _hasOwnProperty$1 = Object.prototype.hasOwnProperty;
|
|
2401
2415
|
/**
|
|
2402
2416
|
* Create a JSXNode with the properties fully split into variable and constant parts, and children
|
|
2403
2417
|
* separated out. Furthermore, the varProps must be a sorted object, that is, the keys must be
|
|
@@ -2415,7 +2429,7 @@ const handleBindProp = (props, prop) => {
|
|
|
2415
2429
|
* @internal
|
|
2416
2430
|
*/
|
|
2417
2431
|
const _jsxSorted = (type, varProps, constProps, children, flags, key, dev) => {
|
|
2418
|
-
return
|
|
2432
|
+
return new JSXNodeImpl(type, varProps, constProps, children, key, false, dev);
|
|
2419
2433
|
};
|
|
2420
2434
|
/**
|
|
2421
2435
|
* Create a JSXNode, with the properties split into variable and constant parts, but the variable
|
|
@@ -2434,24 +2448,158 @@ const _jsxSorted = (type, varProps, constProps, children, flags, key, dev) => {
|
|
|
2434
2448
|
* @internal
|
|
2435
2449
|
*/
|
|
2436
2450
|
const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
|
|
2437
|
-
|
|
2451
|
+
let toSort = false;
|
|
2452
|
+
let constPropsCopied = false;
|
|
2453
|
+
let varPropsCopied = false;
|
|
2454
|
+
let bindValueSignal = null;
|
|
2455
|
+
let bindCheckedSignal = null;
|
|
2456
|
+
// Apply transformations for native HTML elements only
|
|
2457
|
+
if (typeof type === 'string') {
|
|
2458
|
+
// Transform event names (onClick$ -> on:click)
|
|
2459
|
+
if (constProps) {
|
|
2460
|
+
const processedKeys = new Set();
|
|
2461
|
+
for (const k in constProps) {
|
|
2462
|
+
const attr = jsxEventToHtmlAttribute(k);
|
|
2463
|
+
if (attr) {
|
|
2464
|
+
if (!constPropsCopied) {
|
|
2465
|
+
constProps = { ...constProps };
|
|
2466
|
+
constPropsCopied = true;
|
|
2467
|
+
}
|
|
2468
|
+
if (!_hasOwnProperty$1.call(constProps, attr) || processedKeys.has(attr)) {
|
|
2469
|
+
constProps[attr] = constProps[k];
|
|
2470
|
+
}
|
|
2471
|
+
delete constProps[k];
|
|
2472
|
+
}
|
|
2473
|
+
processedKeys.add(k);
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2438
2476
|
if (varProps) {
|
|
2477
|
+
const processedKeys = new Set();
|
|
2439
2478
|
for (const k in varProps) {
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2479
|
+
const attr = jsxEventToHtmlAttribute(k);
|
|
2480
|
+
if (attr) {
|
|
2481
|
+
if (!varPropsCopied) {
|
|
2482
|
+
varProps = { ...varProps };
|
|
2483
|
+
varPropsCopied = true;
|
|
2484
|
+
}
|
|
2485
|
+
// Transform event name in place
|
|
2486
|
+
if (!_hasOwnProperty$1.call(varProps, attr) || processedKeys.has(attr)) {
|
|
2487
|
+
varProps[attr] = varProps[k];
|
|
2488
|
+
}
|
|
2489
|
+
delete varProps[k];
|
|
2490
|
+
toSort = true;
|
|
2491
|
+
}
|
|
2492
|
+
else if (k === BIND_CHECKED) {
|
|
2493
|
+
// Set flag, will process after walk
|
|
2494
|
+
bindCheckedSignal = varProps[k];
|
|
2495
|
+
}
|
|
2496
|
+
else if (k === BIND_VALUE) {
|
|
2497
|
+
// Set flag, will process after walk
|
|
2498
|
+
bindValueSignal = varProps[k];
|
|
2499
|
+
}
|
|
2500
|
+
processedKeys.add(k);
|
|
2501
|
+
}
|
|
2502
|
+
// Handle bind:* - only in varProps, bind:* should be moved to varProps
|
|
2503
|
+
if (bindCheckedSignal || bindValueSignal) {
|
|
2504
|
+
if (!varPropsCopied) {
|
|
2505
|
+
varProps = { ...varProps };
|
|
2506
|
+
varPropsCopied = true;
|
|
2507
|
+
}
|
|
2508
|
+
if (bindCheckedSignal) {
|
|
2509
|
+
delete varProps[BIND_CHECKED];
|
|
2510
|
+
varProps.checked = bindCheckedSignal;
|
|
2511
|
+
const handler = createQRL(null, '_chk', _chk, null, null, [bindCheckedSignal]);
|
|
2512
|
+
// Move on:input from constProps if it exists
|
|
2513
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'on:input')) {
|
|
2514
|
+
if (!constPropsCopied) {
|
|
2515
|
+
constProps = { ...constProps };
|
|
2516
|
+
constPropsCopied = true;
|
|
2517
|
+
}
|
|
2518
|
+
const existingHandler = constProps['on:input'];
|
|
2519
|
+
delete constProps['on:input'];
|
|
2520
|
+
toSort = mergeHandlers(varProps, 'on:input', existingHandler) || toSort;
|
|
2521
|
+
}
|
|
2522
|
+
toSort = mergeHandlers(varProps, 'on:input', handler) || toSort;
|
|
2523
|
+
}
|
|
2524
|
+
else if (bindValueSignal) {
|
|
2525
|
+
delete varProps[BIND_VALUE];
|
|
2526
|
+
varProps.value = bindValueSignal;
|
|
2527
|
+
const handler = createQRL(null, '_val', _val, null, null, [bindValueSignal]);
|
|
2528
|
+
// Move on:input from constProps if it exists
|
|
2529
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'on:input')) {
|
|
2530
|
+
if (!constPropsCopied) {
|
|
2531
|
+
constProps = { ...constProps };
|
|
2532
|
+
constPropsCopied = true;
|
|
2533
|
+
}
|
|
2534
|
+
const existingHandler = constProps['on:input'];
|
|
2535
|
+
delete constProps['on:input'];
|
|
2536
|
+
toSort = mergeHandlers(varProps, 'on:input', existingHandler) || toSort;
|
|
2537
|
+
}
|
|
2538
|
+
toSort = mergeHandlers(varProps, 'on:input', handler) || toSort;
|
|
2443
2539
|
}
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
// Transform className -> class
|
|
2543
|
+
if (varProps && _hasOwnProperty$1.call(varProps, 'className')) {
|
|
2544
|
+
if (!varPropsCopied) {
|
|
2545
|
+
varProps = { ...varProps };
|
|
2546
|
+
varPropsCopied = true;
|
|
2547
|
+
}
|
|
2548
|
+
varProps.class = varProps.className;
|
|
2549
|
+
varProps.className = undefined;
|
|
2550
|
+
toSort = true;
|
|
2551
|
+
if (qDev) {
|
|
2552
|
+
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'className')) {
|
|
2556
|
+
if (!constPropsCopied) {
|
|
2557
|
+
constProps = { ...constProps };
|
|
2558
|
+
constPropsCopied = true;
|
|
2559
|
+
}
|
|
2560
|
+
constProps.class = constProps.className;
|
|
2561
|
+
constProps.className = undefined;
|
|
2562
|
+
if (qDev) {
|
|
2563
|
+
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
if (varProps) {
|
|
2568
|
+
for (const k in varProps) {
|
|
2569
|
+
if (k === 'children') {
|
|
2570
|
+
if (!varPropsCopied) {
|
|
2571
|
+
varProps = { ...varProps };
|
|
2572
|
+
varPropsCopied = true;
|
|
2447
2573
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2574
|
+
children ||= varProps.children;
|
|
2575
|
+
delete varProps.children;
|
|
2576
|
+
}
|
|
2577
|
+
else if (k === 'key') {
|
|
2578
|
+
if (!varPropsCopied) {
|
|
2579
|
+
varProps = { ...varProps };
|
|
2580
|
+
varPropsCopied = true;
|
|
2581
|
+
}
|
|
2582
|
+
key ||= varProps.key;
|
|
2583
|
+
delete varProps.key;
|
|
2584
|
+
}
|
|
2585
|
+
else if (constProps && k in constProps) {
|
|
2586
|
+
if (!varPropsCopied) {
|
|
2587
|
+
varProps = { ...varProps };
|
|
2588
|
+
varPropsCopied = true;
|
|
2589
|
+
}
|
|
2590
|
+
delete varProps[k];
|
|
2591
|
+
}
|
|
2592
|
+
else if (varProps[k] === null) {
|
|
2593
|
+
if (!varPropsCopied) {
|
|
2594
|
+
varProps = { ...varProps };
|
|
2595
|
+
varPropsCopied = true;
|
|
2450
2596
|
}
|
|
2597
|
+
// Clean up null markers (from event conversions)
|
|
2598
|
+
delete varProps[k];
|
|
2451
2599
|
}
|
|
2452
2600
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2601
|
+
}
|
|
2602
|
+
return new JSXNodeImpl(type, varProps, constProps, children, key, toSort || true, dev);
|
|
2455
2603
|
};
|
|
2456
2604
|
/** @internal @deprecated v1 compat */
|
|
2457
2605
|
const _jsxC = (type, mutable, _flags, key) => jsx(type, mutable, key);
|
|
@@ -2547,7 +2695,7 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2547
2695
|
let isInlineComponent = false;
|
|
2548
2696
|
if (componentQRL === null) {
|
|
2549
2697
|
componentQRL = container.getHostProp(renderHost, OnRenderProp);
|
|
2550
|
-
assertDefined(componentQRL, 'No Component found at this location');
|
|
2698
|
+
isDev && assertDefined(componentQRL, 'No Component found at this location');
|
|
2551
2699
|
}
|
|
2552
2700
|
if (isQrl(componentQRL)) {
|
|
2553
2701
|
props = props || container.getHostProp(renderHost, ELEMENT_PROPS) || EMPTY_OBJ;
|
|
@@ -2566,6 +2714,7 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2566
2714
|
const inlineComponent = componentQRL;
|
|
2567
2715
|
componentFn = () => invokeApply(iCtx, inlineComponent, [props || EMPTY_OBJ]);
|
|
2568
2716
|
}
|
|
2717
|
+
const isSsr = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
2569
2718
|
const executeComponentWithPromiseExceptionRetry = (retryCount = 0) => safeCall(() => {
|
|
2570
2719
|
if (!isInlineComponent) {
|
|
2571
2720
|
container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
|
|
@@ -2576,6 +2725,19 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2576
2725
|
}
|
|
2577
2726
|
return maybeThen(componentFn(props), (jsx) => maybeThen(iCtx.$waitOn$, () => jsx));
|
|
2578
2727
|
}, (jsx) => {
|
|
2728
|
+
// In SSR, check if the component was marked dirty (COMPONENT bit) during execution.
|
|
2729
|
+
// This happens when something completes and updates reactive primitives
|
|
2730
|
+
// while we're waiting on $waitOn$. If so, we need to re-execute the component
|
|
2731
|
+
// to get fresh JSX with updated values.
|
|
2732
|
+
if (isSsr && !isInlineComponent) {
|
|
2733
|
+
const ssrNode = renderHost;
|
|
2734
|
+
if (ssrNode.dirty & 4 /* ChoreBits.COMPONENT */) {
|
|
2735
|
+
ssrNode.dirty &= ~4 /* ChoreBits.COMPONENT */;
|
|
2736
|
+
if (retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
|
|
2737
|
+
return executeComponentWithPromiseExceptionRetry(retryCount + 1);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2579
2741
|
const useOnEvents = container.getHostProp(renderHost, USE_ON_LOCAL);
|
|
2580
2742
|
if (useOnEvents) {
|
|
2581
2743
|
return addUseOnEvents(jsx, useOnEvents);
|
|
@@ -2744,7 +2906,7 @@ function injectPlaceholderElement(jsx) {
|
|
|
2744
2906
|
return [placeholder, jsx];
|
|
2745
2907
|
}
|
|
2746
2908
|
// For primitives, we can't add children, so we wrap them in a fragment.
|
|
2747
|
-
if (
|
|
2909
|
+
if (isPrimitiveOrNullUndefined(jsx)) {
|
|
2748
2910
|
const placeholder = createPlaceholderScriptNode();
|
|
2749
2911
|
return [placeholder, _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null)];
|
|
2750
2912
|
}
|
|
@@ -2758,7 +2920,7 @@ function injectPlaceholderElement(jsx) {
|
|
|
2758
2920
|
}
|
|
2759
2921
|
/** @returns An empty <script> element for adding qwik metadata attributes to */
|
|
2760
2922
|
function createPlaceholderScriptNode() {
|
|
2761
|
-
return new JSXNodeImpl('script', null, { hidden: '' });
|
|
2923
|
+
return new JSXNodeImpl('script', null, { hidden: '' }, null, null);
|
|
2762
2924
|
}
|
|
2763
2925
|
|
|
2764
2926
|
/**
|
|
@@ -2874,15 +3036,12 @@ const _restProps = (props, omit = [], target = {}) => {
|
|
|
2874
3036
|
varPropsTarget[key] = varProps[key];
|
|
2875
3037
|
}
|
|
2876
3038
|
}
|
|
2877
|
-
return createPropsProxy(new JSXNodeImpl(null, varPropsTarget, constPropsTarget));
|
|
3039
|
+
return createPropsProxy(new JSXNodeImpl(null, varPropsTarget, constPropsTarget, null, null));
|
|
2878
3040
|
};
|
|
2879
3041
|
|
|
2880
3042
|
const styleContent = (styleId) => {
|
|
2881
3043
|
return ComponentStylesPrefixContent + styleId;
|
|
2882
3044
|
};
|
|
2883
|
-
function hasClassAttr(props) {
|
|
2884
|
-
return 'class' in props;
|
|
2885
|
-
}
|
|
2886
3045
|
function isClassAttr(key) {
|
|
2887
3046
|
return key === 'class';
|
|
2888
3047
|
}
|
|
@@ -3061,119 +3220,9 @@ const styleKey = (qStyles, index) => {
|
|
|
3061
3220
|
return `${hashCode(qStyles.$hash$)}-${index}`;
|
|
3062
3221
|
};
|
|
3063
3222
|
|
|
3064
|
-
/**
|
|
3065
|
-
* @internal
|
|
3066
|
-
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
3067
|
-
*/
|
|
3068
|
-
const useSequentialScope = () => {
|
|
3069
|
-
const iCtx = useInvokeContext();
|
|
3070
|
-
const hostElement = iCtx.$hostElement$;
|
|
3071
|
-
const host = hostElement;
|
|
3072
|
-
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
3073
|
-
if (seq === null) {
|
|
3074
|
-
seq = [];
|
|
3075
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
3076
|
-
}
|
|
3077
|
-
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
3078
|
-
if (seqIdx === null) {
|
|
3079
|
-
seqIdx = 0;
|
|
3080
|
-
}
|
|
3081
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
3082
|
-
while (seq.length <= seqIdx) {
|
|
3083
|
-
seq.push(undefined);
|
|
3084
|
-
}
|
|
3085
|
-
const set = (value) => {
|
|
3086
|
-
if (qDev && qSerialize) {
|
|
3087
|
-
verifySerializable(value);
|
|
3088
|
-
}
|
|
3089
|
-
return (seq[seqIdx] = value);
|
|
3090
|
-
};
|
|
3091
|
-
return {
|
|
3092
|
-
val: seq[seqIdx],
|
|
3093
|
-
set,
|
|
3094
|
-
i: seqIdx,
|
|
3095
|
-
iCtx,
|
|
3096
|
-
};
|
|
3097
|
-
};
|
|
3098
|
-
|
|
3099
|
-
/** @internal */
|
|
3100
|
-
const useTaskQrl = (qrl, opts) => {
|
|
3101
|
-
const { val, set, iCtx, i } = useSequentialScope();
|
|
3102
|
-
if (val) {
|
|
3103
|
-
return;
|
|
3104
|
-
}
|
|
3105
|
-
assertQrl(qrl);
|
|
3106
|
-
set(1);
|
|
3107
|
-
const taskFlags =
|
|
3108
|
-
// enabled by default
|
|
3109
|
-
opts?.deferUpdates === false ? 0 : 16 /* TaskFlags.RENDER_BLOCKING */;
|
|
3110
|
-
const task = new Task(8 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
3111
|
-
// In V2 we add the task to the sequential scope. We need to do this
|
|
3112
|
-
// in order to be able to retrieve it later when the parent element is
|
|
3113
|
-
// deleted and we need to be able to release the task subscriptions.
|
|
3114
|
-
set(task);
|
|
3115
|
-
const container = iCtx.$container$;
|
|
3116
|
-
const { $waitOn$: waitOn } = iCtx;
|
|
3117
|
-
const result = maybeThen(waitOn, () => runTask(task, container, iCtx.$hostElement$));
|
|
3118
|
-
if (isPromise(result)) {
|
|
3119
|
-
iCtx.$waitOn$ = result;
|
|
3120
|
-
}
|
|
3121
|
-
};
|
|
3122
|
-
const runTask = (task, container, host) => {
|
|
3123
|
-
task.$flags$ &= -9 /* TaskFlags.DIRTY */;
|
|
3124
|
-
cleanupDestroyable(task);
|
|
3125
|
-
const iCtx = newInvokeContext(container.$locale$, host, TaskEvent);
|
|
3126
|
-
iCtx.$container$ = container;
|
|
3127
|
-
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
3128
|
-
const track = trackFn(task, container);
|
|
3129
|
-
const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
3130
|
-
const taskApi = { track, cleanup };
|
|
3131
|
-
return safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
3132
|
-
// If a Promise is thrown, that means we need to re-run the task.
|
|
3133
|
-
if (isPromise(err)) {
|
|
3134
|
-
return err.then(() => runTask(task, container, host));
|
|
3135
|
-
}
|
|
3136
|
-
else {
|
|
3137
|
-
container.handleError(err, host);
|
|
3138
|
-
}
|
|
3139
|
-
});
|
|
3140
|
-
};
|
|
3141
|
-
class Task extends BackRef {
|
|
3142
|
-
$flags$;
|
|
3143
|
-
$index$;
|
|
3144
|
-
$el$;
|
|
3145
|
-
$qrl$;
|
|
3146
|
-
$state$;
|
|
3147
|
-
$destroy$;
|
|
3148
|
-
constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
|
|
3149
|
-
super();
|
|
3150
|
-
this.$flags$ = $flags$;
|
|
3151
|
-
this.$index$ = $index$;
|
|
3152
|
-
this.$el$ = $el$;
|
|
3153
|
-
this.$qrl$ = $qrl$;
|
|
3154
|
-
this.$state$ = $state$;
|
|
3155
|
-
this.$destroy$ = $destroy$;
|
|
3156
|
-
}
|
|
3157
|
-
}
|
|
3158
|
-
/** @internal */
|
|
3159
|
-
const isTask = (value) => {
|
|
3160
|
-
return value instanceof Task;
|
|
3161
|
-
};
|
|
3162
|
-
/**
|
|
3163
|
-
* Used internally as a qrl event handler to schedule a task.
|
|
3164
|
-
*
|
|
3165
|
-
* @internal
|
|
3166
|
-
*/
|
|
3167
|
-
const scheduleTask = (_event, element) => {
|
|
3168
|
-
const [task] = useLexicalScope();
|
|
3169
|
-
const container = getDomContainer(element);
|
|
3170
|
-
task.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
3171
|
-
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
3172
|
-
};
|
|
3173
|
-
|
|
3174
3223
|
/** @internal */
|
|
3175
3224
|
const mapApp_findIndx = (array, key, start) => {
|
|
3176
|
-
assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
3225
|
+
isDev && assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
3177
3226
|
let bottom = start >> 1;
|
|
3178
3227
|
let top = (array.length - 2) >> 1;
|
|
3179
3228
|
while (bottom <= top) {
|
|
@@ -3220,6 +3269,127 @@ const mapArray_has = (array, key, start) => {
|
|
|
3220
3269
|
return mapApp_findIndx(array, key, start) >= 0;
|
|
3221
3270
|
};
|
|
3222
3271
|
|
|
3272
|
+
class DeleteOperation {
|
|
3273
|
+
target;
|
|
3274
|
+
constructor(target) {
|
|
3275
|
+
this.target = target;
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
class RemoveAllChildrenOperation {
|
|
3279
|
+
target;
|
|
3280
|
+
constructor(target) {
|
|
3281
|
+
this.target = target;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
class SetTextOperation {
|
|
3285
|
+
target;
|
|
3286
|
+
text;
|
|
3287
|
+
operationType = 16 /* VNodeOperationType.SetText */;
|
|
3288
|
+
constructor(target, text) {
|
|
3289
|
+
this.target = target;
|
|
3290
|
+
this.text = text;
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
class InsertOrMoveOperation {
|
|
3294
|
+
target;
|
|
3295
|
+
parent;
|
|
3296
|
+
beforeTarget;
|
|
3297
|
+
constructor(target, parent, beforeTarget) {
|
|
3298
|
+
this.target = target;
|
|
3299
|
+
this.parent = parent;
|
|
3300
|
+
this.beforeTarget = beforeTarget;
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
class SetAttributeOperation {
|
|
3304
|
+
target;
|
|
3305
|
+
attrName;
|
|
3306
|
+
attrValue;
|
|
3307
|
+
scopedStyleIdPrefix;
|
|
3308
|
+
isSvg;
|
|
3309
|
+
constructor(target, attrName, attrValue, scopedStyleIdPrefix, isSvg) {
|
|
3310
|
+
this.target = target;
|
|
3311
|
+
this.attrName = attrName;
|
|
3312
|
+
this.attrValue = attrValue;
|
|
3313
|
+
this.scopedStyleIdPrefix = scopedStyleIdPrefix;
|
|
3314
|
+
this.isSvg = isSvg;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
/** Factory functions to create operations with consistent hidden classes. */
|
|
3318
|
+
const createDeleteOperation = (target) => new DeleteOperation(target);
|
|
3319
|
+
const createRemoveAllChildrenOperation = (target) => new RemoveAllChildrenOperation(target);
|
|
3320
|
+
const createSetTextOperation = (target, text) => new SetTextOperation(target, text);
|
|
3321
|
+
const createInsertOrMoveOperation = (target, parent, beforeTarget) => new InsertOrMoveOperation(target, parent, beforeTarget);
|
|
3322
|
+
const createSetAttributeOperation = (target, attrName, attrValue, scopedStyleIdPrefix = null, isSvg = false) => new SetAttributeOperation(target, attrName, attrValue, scopedStyleIdPrefix, isSvg);
|
|
3323
|
+
|
|
3324
|
+
function callQrl(container, host, qrl, event, element, useGetObjectById) {
|
|
3325
|
+
const getObjectById = useGetObjectById ? container?.$getObjectById$ || null : null;
|
|
3326
|
+
const singleItem = vnode_getProp(host, ITERATION_ITEM_SINGLE, getObjectById);
|
|
3327
|
+
if (singleItem !== null) {
|
|
3328
|
+
return qrl(event, element, singleItem);
|
|
3329
|
+
}
|
|
3330
|
+
const multiItems = vnode_getProp(host, ITERATION_ITEM_MULTI, getObjectById);
|
|
3331
|
+
if (multiItems !== null) {
|
|
3332
|
+
return qrl(event, element, ...multiItems);
|
|
3333
|
+
}
|
|
3334
|
+
return qrl(event, element);
|
|
3335
|
+
}
|
|
3336
|
+
/**
|
|
3337
|
+
* This is called by qwik-loader to run a QRL. It has to be synchronous.
|
|
3338
|
+
*
|
|
3339
|
+
* @internal
|
|
3340
|
+
*/
|
|
3341
|
+
const _run = (...args) => {
|
|
3342
|
+
// This will already check container
|
|
3343
|
+
const [qrl] = useLexicalScope();
|
|
3344
|
+
const context = getInvokeContext();
|
|
3345
|
+
const hostElement = context.$hostElement$;
|
|
3346
|
+
if (hostElement) {
|
|
3347
|
+
context.$container$ ||= getDomContainer(hostElement.node);
|
|
3348
|
+
vnode_ensureElementInflated(hostElement);
|
|
3349
|
+
return retryOnPromise(() => {
|
|
3350
|
+
if (!(hostElement.flags & 32 /* VNodeFlags.Deleted */)) {
|
|
3351
|
+
return callQrl(context.$container$, hostElement, qrl, args[0], args[1], true).catch((err) => {
|
|
3352
|
+
const container = context.$container$;
|
|
3353
|
+
if (container) {
|
|
3354
|
+
container.handleError(err, hostElement);
|
|
3355
|
+
}
|
|
3356
|
+
else {
|
|
3357
|
+
throw err;
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
};
|
|
3364
|
+
|
|
3365
|
+
let _setAttribute = null;
|
|
3366
|
+
const fastSetAttribute = (target, name, value) => {
|
|
3367
|
+
if (!_setAttribute) {
|
|
3368
|
+
_setAttribute = target.setAttribute;
|
|
3369
|
+
}
|
|
3370
|
+
_setAttribute.call(target, name, value);
|
|
3371
|
+
};
|
|
3372
|
+
let _setAttributeNS = null;
|
|
3373
|
+
const fastSetAttributeNS = (target, namespace, name, value) => {
|
|
3374
|
+
if (!_setAttributeNS) {
|
|
3375
|
+
_setAttributeNS = target.setAttributeNS;
|
|
3376
|
+
}
|
|
3377
|
+
_setAttributeNS.call(target, namespace, name, value);
|
|
3378
|
+
};
|
|
3379
|
+
function directSetAttribute(element, attrName, attrValue, isSvg) {
|
|
3380
|
+
if (attrValue != null) {
|
|
3381
|
+
if (isSvg) {
|
|
3382
|
+
// only svg elements can have namespace attributes
|
|
3383
|
+
const namespace = getAttributeNamespace(attrName);
|
|
3384
|
+
if (namespace) {
|
|
3385
|
+
fastSetAttributeNS(element, namespace, attrName, attrValue);
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
fastSetAttribute(element, attrName, attrValue);
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3223
3393
|
/**
|
|
3224
3394
|
* Helper to get the next sibling of a VNode. Extracted to module scope to help V8 inline it
|
|
3225
3395
|
* reliably.
|
|
@@ -3229,9 +3399,12 @@ function peekNextSibling(vCurrent) {
|
|
|
3229
3399
|
}
|
|
3230
3400
|
const _hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
3231
3401
|
/** Helper to set an attribute on a vnode. Extracted to module scope to avoid closure allocation. */
|
|
3232
|
-
function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix) {
|
|
3233
|
-
|
|
3234
|
-
|
|
3402
|
+
function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix, originalValue) {
|
|
3403
|
+
import.meta.env.TEST &&
|
|
3404
|
+
scopedStyleIdPrefix &&
|
|
3405
|
+
vnode_setProp(vnode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
3406
|
+
vnode_setProp(vnode, key, originalValue);
|
|
3407
|
+
addVNodeOperation(journal, createSetAttributeOperation(vnode.node, key, value, scopedStyleIdPrefix, (vnode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
3235
3408
|
}
|
|
3236
3409
|
const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyleIdPrefix) => {
|
|
3237
3410
|
const diffContext = {
|
|
@@ -3253,6 +3426,7 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3253
3426
|
jsxIdx: 0,
|
|
3254
3427
|
jsxCount: 0,
|
|
3255
3428
|
shouldAdvance: true,
|
|
3429
|
+
isCreationMode: false,
|
|
3256
3430
|
subscriptionData: {
|
|
3257
3431
|
const: new SubscriptionData({
|
|
3258
3432
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
@@ -3281,8 +3455,8 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3281
3455
|
//////////////////////////////////////////////
|
|
3282
3456
|
//////////////////////////////////////////////
|
|
3283
3457
|
function diff(diffContext, jsxNode, vStartNode) {
|
|
3284
|
-
assertFalse(vnode_isVNode(jsxNode), 'JSXNode should not be a VNode');
|
|
3285
|
-
assertTrue(vnode_isVNode(vStartNode), 'vStartNode should be a VNode');
|
|
3458
|
+
isDev && assertFalse(vnode_isVNode(jsxNode), 'JSXNode should not be a VNode');
|
|
3459
|
+
isDev && assertTrue(vnode_isVNode(vStartNode), 'vStartNode should be a VNode');
|
|
3286
3460
|
diffContext.vParent = vStartNode;
|
|
3287
3461
|
diffContext.vNewNode = null;
|
|
3288
3462
|
diffContext.vCurrent = vnode_getFirstChild(vStartNode);
|
|
@@ -3293,7 +3467,8 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3293
3467
|
}
|
|
3294
3468
|
while (diffContext.stack.length) {
|
|
3295
3469
|
while (diffContext.jsxIdx < diffContext.jsxCount) {
|
|
3296
|
-
|
|
3470
|
+
isDev &&
|
|
3471
|
+
assertFalse(diffContext.vParent === diffContext.vCurrent, "Parent and current can't be the same");
|
|
3297
3472
|
if (typeof diffContext.jsxValue === 'string') {
|
|
3298
3473
|
expectText(diffContext, diffContext.jsxValue);
|
|
3299
3474
|
}
|
|
@@ -3301,26 +3476,7 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3301
3476
|
expectText(diffContext, String(diffContext.jsxValue));
|
|
3302
3477
|
}
|
|
3303
3478
|
else if (diffContext.jsxValue && typeof diffContext.jsxValue === 'object') {
|
|
3304
|
-
if (
|
|
3305
|
-
descend(diffContext, diffContext.jsxValue, false);
|
|
3306
|
-
}
|
|
3307
|
-
else if (isSignal(diffContext.jsxValue)) {
|
|
3308
|
-
expectVirtual(diffContext, "S" /* VirtualType.WrappedSignal */, null);
|
|
3309
|
-
const unwrappedSignal = diffContext.jsxValue instanceof WrappedSignalImpl
|
|
3310
|
-
? diffContext.jsxValue.$unwrapIfSignal$()
|
|
3311
|
-
: diffContext.jsxValue;
|
|
3312
|
-
const hasUnwrappedSignal = diffContext.vCurrent?.[_EFFECT_BACK_REF]
|
|
3313
|
-
?.get("." /* EffectProperty.VNODE */)?.[2 /* EffectSubscriptionProp.BACK_REF */]?.has(unwrappedSignal);
|
|
3314
|
-
if (!hasUnwrappedSignal) {
|
|
3315
|
-
const vHost = (diffContext.vNewNode || diffContext.vCurrent);
|
|
3316
|
-
descend(diffContext, resolveSignalAndDescend(diffContext, () => trackSignalAndAssignHost(unwrappedSignal, vHost, "." /* EffectProperty.VNODE */, diffContext.container)), true);
|
|
3317
|
-
}
|
|
3318
|
-
}
|
|
3319
|
-
else if (isPromise(diffContext.jsxValue)) {
|
|
3320
|
-
expectVirtual(diffContext, "A" /* VirtualType.Awaited */, null);
|
|
3321
|
-
diffContext.asyncQueue.push(diffContext.jsxValue, diffContext.vNewNode || diffContext.vCurrent);
|
|
3322
|
-
}
|
|
3323
|
-
else if (isJSXNode(diffContext.jsxValue)) {
|
|
3479
|
+
if (isJSXNode(diffContext.jsxValue)) {
|
|
3324
3480
|
const type = diffContext.jsxValue.type;
|
|
3325
3481
|
if (typeof type === 'string') {
|
|
3326
3482
|
expectNoMoreTextNodes(diffContext);
|
|
@@ -3368,6 +3524,28 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3368
3524
|
}
|
|
3369
3525
|
}
|
|
3370
3526
|
}
|
|
3527
|
+
else if (Array.isArray(diffContext.jsxValue)) {
|
|
3528
|
+
descend(diffContext, diffContext.jsxValue, false);
|
|
3529
|
+
}
|
|
3530
|
+
else if (isSignal(diffContext.jsxValue)) {
|
|
3531
|
+
expectVirtual(diffContext, "S" /* VirtualType.WrappedSignal */, null);
|
|
3532
|
+
const unwrappedSignal = diffContext.jsxValue instanceof WrappedSignalImpl
|
|
3533
|
+
? diffContext.jsxValue.$unwrapIfSignal$()
|
|
3534
|
+
: diffContext.jsxValue;
|
|
3535
|
+
const signals = diffContext.vCurrent?.[_EFFECT_BACK_REF]?.get("." /* EffectProperty.VNODE */)?.backRef;
|
|
3536
|
+
let hasUnwrappedSignal = signals?.has(unwrappedSignal);
|
|
3537
|
+
if (signals && unwrappedSignal instanceof WrappedSignalImpl) {
|
|
3538
|
+
hasUnwrappedSignal = containsWrappedSignal(signals, unwrappedSignal);
|
|
3539
|
+
}
|
|
3540
|
+
if (!hasUnwrappedSignal) {
|
|
3541
|
+
const vHost = (diffContext.vNewNode || diffContext.vCurrent);
|
|
3542
|
+
descend(diffContext, resolveSignalAndDescend(diffContext, () => trackSignalAndAssignHost(unwrappedSignal, vHost, "." /* EffectProperty.VNODE */, diffContext.container)), true);
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
else if (isPromise(diffContext.jsxValue)) {
|
|
3546
|
+
expectVirtual(diffContext, "A" /* VirtualType.Awaited */, null);
|
|
3547
|
+
diffContext.asyncQueue.push(diffContext.jsxValue, diffContext.vNewNode || diffContext.vCurrent);
|
|
3548
|
+
}
|
|
3371
3549
|
}
|
|
3372
3550
|
else if (diffContext.jsxValue === SkipRender) ;
|
|
3373
3551
|
else {
|
|
@@ -3447,7 +3625,12 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
3447
3625
|
}
|
|
3448
3626
|
stackPush(diffContext, children, descendVNode);
|
|
3449
3627
|
if (descendVNode) {
|
|
3450
|
-
|
|
3628
|
+
isDev &&
|
|
3629
|
+
assertDefined(diffContext.vCurrent || diffContext.vNewNode, 'Expecting vCurrent to be defined.');
|
|
3630
|
+
const creationMode = diffContext.isCreationMode ||
|
|
3631
|
+
!!diffContext.vNewNode ||
|
|
3632
|
+
!vnode_getFirstChild(diffContext.vCurrent);
|
|
3633
|
+
diffContext.isCreationMode = creationMode;
|
|
3451
3634
|
diffContext.vSideBuffer = null;
|
|
3452
3635
|
diffContext.vSiblings = null;
|
|
3453
3636
|
diffContext.vSiblingsArray = null;
|
|
@@ -3460,6 +3643,7 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
3460
3643
|
function ascend(diffContext) {
|
|
3461
3644
|
const descendVNode = diffContext.stack.pop(); // boolean: descendVNode
|
|
3462
3645
|
if (descendVNode) {
|
|
3646
|
+
diffContext.isCreationMode = diffContext.stack.pop();
|
|
3463
3647
|
diffContext.vSideBuffer = diffContext.stack.pop();
|
|
3464
3648
|
diffContext.vSiblings = diffContext.stack.pop();
|
|
3465
3649
|
diffContext.vSiblingsArray = diffContext.stack.pop();
|
|
@@ -3476,7 +3660,7 @@ function ascend(diffContext) {
|
|
|
3476
3660
|
function stackPush(diffContext, children, descendVNode) {
|
|
3477
3661
|
diffContext.stack.push(diffContext.jsxChildren, diffContext.jsxIdx, diffContext.jsxCount, diffContext.jsxValue);
|
|
3478
3662
|
if (descendVNode) {
|
|
3479
|
-
diffContext.stack.push(diffContext.vParent, diffContext.vCurrent, diffContext.vNewNode, diffContext.vSiblingsArray, diffContext.vSiblings, diffContext.vSideBuffer);
|
|
3663
|
+
diffContext.stack.push(diffContext.vParent, diffContext.vCurrent, diffContext.vNewNode, diffContext.vSiblingsArray, diffContext.vSiblings, diffContext.vSideBuffer, diffContext.isCreationMode);
|
|
3480
3664
|
}
|
|
3481
3665
|
diffContext.stack.push(descendVNode);
|
|
3482
3666
|
if (Array.isArray(children)) {
|
|
@@ -3604,12 +3788,20 @@ function expectSlot(diffContext) {
|
|
|
3604
3788
|
else if (vProjectedNode === diffContext.vCurrent) ;
|
|
3605
3789
|
else {
|
|
3606
3790
|
// move from q:template to the target node
|
|
3791
|
+
const oldParent = vProjectedNode.parent;
|
|
3607
3792
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vProjectedNode), diffContext.vCurrent && getInsertBefore(diffContext));
|
|
3608
3793
|
vnode_setProp(diffContext.vNewNode, QSlot, slotNameKey);
|
|
3609
3794
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.vNewNode);
|
|
3610
3795
|
isDev &&
|
|
3611
3796
|
vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
3612
3797
|
isDev && vnode_setProp(diffContext.vNewNode, 'q:code', 'expectSlot' + count++);
|
|
3798
|
+
// If we moved from a q:template and it's now empty, remove it
|
|
3799
|
+
if (oldParent &&
|
|
3800
|
+
vnode_isElementVNode(oldParent) &&
|
|
3801
|
+
!oldParent.firstChild &&
|
|
3802
|
+
vnode_getElementName(oldParent) === QTemplate) {
|
|
3803
|
+
vnode_remove(diffContext.journal, oldParent.parent, oldParent, true);
|
|
3804
|
+
}
|
|
3613
3805
|
}
|
|
3614
3806
|
return true;
|
|
3615
3807
|
}
|
|
@@ -3684,7 +3876,8 @@ function expectNoChildren(diffContext, removeDOM = true) {
|
|
|
3684
3876
|
}
|
|
3685
3877
|
/** Expect no more nodes - Any nodes which are still at cursor, need to be removed. */
|
|
3686
3878
|
function expectNoMore(diffContext) {
|
|
3687
|
-
|
|
3879
|
+
isDev &&
|
|
3880
|
+
assertFalse(diffContext.vParent === diffContext.vCurrent, "Parent and current can't be the same");
|
|
3688
3881
|
if (diffContext.vCurrent !== null) {
|
|
3689
3882
|
while (diffContext.vCurrent) {
|
|
3690
3883
|
const toRemove = diffContext.vCurrent;
|
|
@@ -3714,20 +3907,6 @@ function expectNoMoreTextNodes(diffContext) {
|
|
|
3714
3907
|
*/
|
|
3715
3908
|
function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
3716
3909
|
const element = createElementWithNamespace(diffContext, elementName);
|
|
3717
|
-
function setAttribute(key, value, vHost) {
|
|
3718
|
-
value = serializeAttribute(key, value, diffContext.scopedStyleIdPrefix);
|
|
3719
|
-
if (value != null) {
|
|
3720
|
-
if (vHost.flags & 128 /* VNodeFlags.NS_svg */) {
|
|
3721
|
-
// only svg elements can have namespace attributes
|
|
3722
|
-
const namespace = getAttributeNamespace(key);
|
|
3723
|
-
if (namespace) {
|
|
3724
|
-
element.setAttributeNS(namespace, key, value);
|
|
3725
|
-
return;
|
|
3726
|
-
}
|
|
3727
|
-
}
|
|
3728
|
-
element.setAttribute(key, value);
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
3910
|
const { constProps } = jsx;
|
|
3732
3911
|
let needsQDispatchEventPatch = false;
|
|
3733
3912
|
if (constProps) {
|
|
@@ -3778,7 +3957,7 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3778
3957
|
}
|
|
3779
3958
|
if (isPromise(value)) {
|
|
3780
3959
|
const vHost = diffContext.vNewNode;
|
|
3781
|
-
const attributePromise = value.then((resolvedValue) =>
|
|
3960
|
+
const attributePromise = value.then((resolvedValue) => directSetAttribute(element, key, serializeAttribute(key, resolvedValue, diffContext.scopedStyleIdPrefix), (vHost.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
3782
3961
|
diffContext.asyncAttributePromises.push(attributePromise);
|
|
3783
3962
|
continue;
|
|
3784
3963
|
}
|
|
@@ -3799,7 +3978,7 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3799
3978
|
element.value = escapeHTML(value || '');
|
|
3800
3979
|
continue;
|
|
3801
3980
|
}
|
|
3802
|
-
|
|
3981
|
+
directSetAttribute(element, key, serializeAttribute(key, value, diffContext.scopedStyleIdPrefix), (diffContext.vNewNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0);
|
|
3803
3982
|
}
|
|
3804
3983
|
}
|
|
3805
3984
|
const key = jsx.key;
|
|
@@ -3808,7 +3987,8 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3808
3987
|
}
|
|
3809
3988
|
// append class attribute if styleScopedId exists and there is no class attribute
|
|
3810
3989
|
if (diffContext.scopedStyleIdPrefix) {
|
|
3811
|
-
const classAttributeExists =
|
|
3990
|
+
const classAttributeExists = _hasOwnProperty.call(jsx.varProps, 'class') ||
|
|
3991
|
+
(jsx.constProps && _hasOwnProperty.call(jsx.constProps, 'class'));
|
|
3812
3992
|
if (!classAttributeExists) {
|
|
3813
3993
|
element.setAttribute('class', diffContext.scopedStyleIdPrefix);
|
|
3814
3994
|
}
|
|
@@ -3818,28 +3998,35 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3818
3998
|
}
|
|
3819
3999
|
function createElementWithNamespace(diffContext, elementName) {
|
|
3820
4000
|
const domParentVNode = vnode_getDomParentVNode(diffContext.vParent, true);
|
|
3821
|
-
const
|
|
3822
|
-
const
|
|
4001
|
+
const namespaceData = getNewElementNamespaceData(domParentVNode, elementName);
|
|
4002
|
+
const currentDocument = import.meta.env.TEST ? diffContext.container.document : document;
|
|
4003
|
+
const element = namespaceData.elementNamespaceFlag === 0 /* VNodeFlags.NS_html */
|
|
4004
|
+
? currentDocument.createElement(elementName)
|
|
4005
|
+
: currentDocument.createElementNS(namespaceData.elementNamespace, elementName);
|
|
3823
4006
|
diffContext.vNewNode = vnode_newElement(element, elementName);
|
|
3824
|
-
diffContext.vNewNode.flags |= elementNamespaceFlag;
|
|
4007
|
+
diffContext.vNewNode.flags |= namespaceData.elementNamespaceFlag;
|
|
3825
4008
|
return element;
|
|
3826
4009
|
}
|
|
3827
4010
|
function expectElement(diffContext, jsx, elementName) {
|
|
3828
|
-
const isSameElementName = diffContext.vCurrent &&
|
|
3829
|
-
vnode_isElementVNode(diffContext.vCurrent) &&
|
|
3830
|
-
elementName === vnode_getElementName(diffContext.vCurrent);
|
|
3831
|
-
const jsxKey = jsx.key;
|
|
3832
4011
|
let needsQDispatchEventPatch = false;
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
const sideBufferKey = getSideBufferKey(elementName, jsxKey);
|
|
3836
|
-
if (moveOrCreateKeyedNode(diffContext, elementName, jsxKey, sideBufferKey, diffContext.vParent)) {
|
|
3837
|
-
needsQDispatchEventPatch = createNewElement(diffContext, jsx, elementName, null);
|
|
3838
|
-
}
|
|
4012
|
+
if (diffContext.isCreationMode) {
|
|
4013
|
+
needsQDispatchEventPatch = createNewElement(diffContext, jsx, elementName, null);
|
|
3839
4014
|
}
|
|
3840
4015
|
else {
|
|
3841
|
-
|
|
3842
|
-
|
|
4016
|
+
const isElementVNode = diffContext.vCurrent && vnode_isElementVNode(diffContext.vCurrent);
|
|
4017
|
+
const isSameElementName = isElementVNode && elementName === vnode_getElementName(diffContext.vCurrent);
|
|
4018
|
+
const jsxKey = jsx.key;
|
|
4019
|
+
const currentKey = isElementVNode && diffContext.vCurrent.key;
|
|
4020
|
+
if (!isSameElementName || jsxKey !== currentKey) {
|
|
4021
|
+
const sideBufferKey = getSideBufferKey(elementName, jsxKey);
|
|
4022
|
+
if (moveOrCreateKeyedNode(diffContext, elementName, jsxKey, sideBufferKey, diffContext.vParent)) {
|
|
4023
|
+
needsQDispatchEventPatch = createNewElement(diffContext, jsx, elementName, null);
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
else {
|
|
4027
|
+
// delete the key from the side buffer if it is the same element
|
|
4028
|
+
deleteFromSideBuffer(diffContext, elementName, jsxKey);
|
|
4029
|
+
}
|
|
3843
4030
|
}
|
|
3844
4031
|
// reconcile attributes
|
|
3845
4032
|
const jsxProps = jsx.varProps;
|
|
@@ -3847,7 +4034,8 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3847
4034
|
const element = vNode.node;
|
|
3848
4035
|
if (jsxProps) {
|
|
3849
4036
|
needsQDispatchEventPatch =
|
|
3850
|
-
diffProps(diffContext, vNode, jsxProps, (
|
|
4037
|
+
diffProps(diffContext, vNode, jsxProps, (isDev && getFileLocationFromJsx(jsx.dev)) || null) ||
|
|
4038
|
+
needsQDispatchEventPatch;
|
|
3851
4039
|
}
|
|
3852
4040
|
if (needsQDispatchEventPatch) {
|
|
3853
4041
|
// Event handler needs to be patched onto the element.
|
|
@@ -3864,7 +4052,7 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3864
4052
|
];
|
|
3865
4053
|
for (const qrl of qrls.flat(2)) {
|
|
3866
4054
|
if (qrl) {
|
|
3867
|
-
|
|
4055
|
+
callQrl(diffContext.container, vNode, qrl, event, vNode.node, false).catch((e) => {
|
|
3868
4056
|
diffContext.container.handleError(e, vNode);
|
|
3869
4057
|
});
|
|
3870
4058
|
}
|
|
@@ -3873,92 +4061,127 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3873
4061
|
}
|
|
3874
4062
|
}
|
|
3875
4063
|
}
|
|
3876
|
-
function diffProps(diffContext, vnode, newAttrs,
|
|
3877
|
-
|
|
4064
|
+
function diffProps(diffContext, vnode, newAttrs, currentFile) {
|
|
4065
|
+
if (!diffContext.isCreationMode) {
|
|
4066
|
+
// inflate only resumed vnodes
|
|
4067
|
+
vnode_ensureElementInflated(vnode);
|
|
4068
|
+
}
|
|
4069
|
+
const oldAttrs = vnode.props;
|
|
3878
4070
|
let patchEventDispatch = false;
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
4071
|
+
// Actual diffing logic
|
|
4072
|
+
// Apply all new attributes
|
|
4073
|
+
for (const key in newAttrs) {
|
|
4074
|
+
const newValue = newAttrs[key];
|
|
4075
|
+
const isEvent = isHtmlAttributeAnEventName(key);
|
|
4076
|
+
if (oldAttrs && _hasOwnProperty.call(oldAttrs, key)) {
|
|
4077
|
+
const oldValue = oldAttrs[key];
|
|
4078
|
+
if (newValue !== oldValue) {
|
|
4079
|
+
if (newValue instanceof WrappedSignalImpl &&
|
|
4080
|
+
oldValue instanceof WrappedSignalImpl &&
|
|
4081
|
+
areWrappedSignalsEqual(newValue, oldValue)) {
|
|
4082
|
+
continue;
|
|
4083
|
+
}
|
|
4084
|
+
if (isEvent) {
|
|
4085
|
+
const result = recordJsxEvent(diffContext, vnode, key, newValue, currentFile);
|
|
4086
|
+
patchEventDispatch ||= result;
|
|
4087
|
+
}
|
|
4088
|
+
else {
|
|
4089
|
+
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
4090
|
+
}
|
|
3891
4091
|
}
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
4092
|
+
}
|
|
4093
|
+
else if (newValue != null) {
|
|
4094
|
+
if (isEvent) {
|
|
4095
|
+
const result = recordJsxEvent(diffContext, vnode, key, newValue, currentFile);
|
|
4096
|
+
patchEventDispatch ||= result;
|
|
3895
4097
|
}
|
|
3896
4098
|
else {
|
|
3897
|
-
|
|
4099
|
+
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
3898
4100
|
}
|
|
3899
4101
|
}
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
4102
|
+
}
|
|
4103
|
+
if (oldAttrs) {
|
|
4104
|
+
// Remove attributes that no longer exist in new props
|
|
4105
|
+
for (const key in oldAttrs) {
|
|
4106
|
+
if (!_hasOwnProperty.call(newAttrs, key) &&
|
|
4107
|
+
!key.startsWith(HANDLER_PREFIX) &&
|
|
4108
|
+
!isHtmlAttributeAnEventName(key)) {
|
|
4109
|
+
patchProperty(diffContext, vnode, key, null, currentFile);
|
|
3908
4110
|
}
|
|
3909
|
-
const vHost = vnode;
|
|
3910
|
-
value = retryOnPromise(() => trackSignalAndAssignHost(unwrappedSignal, vHost, key, diffContext.container, diffContext.subscriptionData.var));
|
|
3911
4111
|
}
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
4112
|
+
}
|
|
4113
|
+
return patchEventDispatch;
|
|
4114
|
+
}
|
|
4115
|
+
const patchProperty = (diffContext, vnode, key, value, currentFile) => {
|
|
4116
|
+
if (
|
|
4117
|
+
// set only property for iteration item, not an attribute
|
|
4118
|
+
key === ITERATION_ITEM_SINGLE ||
|
|
4119
|
+
key === ITERATION_ITEM_MULTI ||
|
|
4120
|
+
key.charAt(0) === HANDLER_PREFIX) {
|
|
4121
|
+
// TODO: there is a potential deoptimization here, because we are setting different keys on props.
|
|
4122
|
+
// Eager bailout - Insufficient type feedback for generic keyed access
|
|
4123
|
+
vnode_setProp(vnode, key, value);
|
|
4124
|
+
return;
|
|
4125
|
+
}
|
|
4126
|
+
const originalValue = value;
|
|
4127
|
+
if (key === 'ref') {
|
|
4128
|
+
const element = vnode.node;
|
|
4129
|
+
if (isSignal(value)) {
|
|
4130
|
+
value.value = element;
|
|
4131
|
+
return;
|
|
3916
4132
|
}
|
|
3917
|
-
if (
|
|
3918
|
-
|
|
3919
|
-
const attributePromise = value.then((resolvedValue) => {
|
|
3920
|
-
setAttribute(diffContext.journal, vHost, key, resolvedValue, diffContext.scopedStyleIdPrefix);
|
|
3921
|
-
});
|
|
3922
|
-
diffContext.asyncAttributePromises.push(attributePromise);
|
|
4133
|
+
else if (typeof value === 'function') {
|
|
4134
|
+
value(element);
|
|
3923
4135
|
return;
|
|
3924
4136
|
}
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
const recordJsxEvent = (key, value) => {
|
|
3928
|
-
const data = getEventDataFromHtmlAttribute(key);
|
|
3929
|
-
if (data) {
|
|
3930
|
-
const [scope, eventName] = data;
|
|
3931
|
-
const scopedEvent = getScopedEventName(scope, eventName);
|
|
3932
|
-
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
3933
|
-
record(':' + scopedEvent, value);
|
|
3934
|
-
registerQwikLoaderEvent(diffContext, loaderScopedEvent);
|
|
3935
|
-
patchEventDispatch = true;
|
|
4137
|
+
else {
|
|
4138
|
+
throw qError(15 /* QError.invalidRefValue */, [currentFile]);
|
|
3936
4139
|
}
|
|
3937
|
-
}
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
if (_hasOwnProperty.call(oldAttrs, key)) {
|
|
3944
|
-
if (newValue !== oldAttrs[key]) {
|
|
3945
|
-
isEvent ? recordJsxEvent(key, newValue) : record(key, newValue);
|
|
3946
|
-
}
|
|
4140
|
+
}
|
|
4141
|
+
const currentEffect = vnode[_EFFECT_BACK_REF]?.get(key);
|
|
4142
|
+
if (isSignal(value)) {
|
|
4143
|
+
const unwrappedSignal = value instanceof WrappedSignalImpl ? value.$unwrapIfSignal$() : value;
|
|
4144
|
+
if (currentEffect?.backRef?.has(unwrappedSignal)) {
|
|
4145
|
+
return;
|
|
3947
4146
|
}
|
|
3948
|
-
|
|
3949
|
-
|
|
4147
|
+
if (currentEffect) {
|
|
4148
|
+
clearEffectSubscription(diffContext.container, currentEffect);
|
|
4149
|
+
}
|
|
4150
|
+
const vHost = vnode;
|
|
4151
|
+
value = retryOnPromise(() => trackSignalAndAssignHost(unwrappedSignal, vHost, key, diffContext.container, diffContext.subscriptionData.var));
|
|
4152
|
+
}
|
|
4153
|
+
else {
|
|
4154
|
+
if (currentEffect) {
|
|
4155
|
+
clearEffectSubscription(diffContext.container, currentEffect);
|
|
3950
4156
|
}
|
|
3951
4157
|
}
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
4158
|
+
if (isPromise(value)) {
|
|
4159
|
+
const vHost = vnode;
|
|
4160
|
+
const attributePromise = value.then((resolvedValue) => {
|
|
4161
|
+
setAttribute(diffContext.journal, vHost, key, resolvedValue, diffContext.scopedStyleIdPrefix, originalValue);
|
|
4162
|
+
});
|
|
4163
|
+
diffContext.asyncAttributePromises.push(attributePromise);
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4166
|
+
setAttribute(diffContext.journal, vnode, key, value, diffContext.scopedStyleIdPrefix, originalValue);
|
|
4167
|
+
};
|
|
4168
|
+
const recordJsxEvent = (diffContext, vnode, key, value, currentFile) => {
|
|
4169
|
+
const data = getEventDataFromHtmlAttribute(key);
|
|
4170
|
+
if (data) {
|
|
4171
|
+
const props = vnode.props;
|
|
4172
|
+
const [scope, eventName] = data;
|
|
4173
|
+
const scopedEvent = getScopedEventName(scope, eventName);
|
|
4174
|
+
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
4175
|
+
const scopedEventKey = ':' + scopedEvent;
|
|
4176
|
+
if (props && _hasOwnProperty.call(props, scopedEventKey)) {
|
|
4177
|
+
return false;
|
|
3958
4178
|
}
|
|
4179
|
+
patchProperty(diffContext, vnode, scopedEventKey, value, currentFile);
|
|
4180
|
+
registerQwikLoaderEvent(diffContext, loaderScopedEvent);
|
|
4181
|
+
return true;
|
|
3959
4182
|
}
|
|
3960
|
-
return
|
|
3961
|
-
}
|
|
4183
|
+
return false;
|
|
4184
|
+
};
|
|
3962
4185
|
function registerQwikLoaderEvent(diffContext, eventName) {
|
|
3963
4186
|
const qWindow = import.meta.env.TEST
|
|
3964
4187
|
? diffContext.container.document.defaultView
|
|
@@ -3970,6 +4193,16 @@ function registerQwikLoaderEvent(diffContext, eventName) {
|
|
|
3970
4193
|
function retrieveChildWithKey(diffContext, nodeName, key) {
|
|
3971
4194
|
let vNodeWithKey = null;
|
|
3972
4195
|
if (diffContext.vSiblings === null) {
|
|
4196
|
+
// check if the current node is the one we are looking for
|
|
4197
|
+
const vCurrent = diffContext.vCurrent;
|
|
4198
|
+
if (vCurrent) {
|
|
4199
|
+
const name = vnode_isElementVNode(vCurrent) ? vnode_getElementName(vCurrent) : null;
|
|
4200
|
+
const vKey = getKey(vCurrent) ||
|
|
4201
|
+
getComponentHash(vCurrent, diffContext.container.$getObjectById$);
|
|
4202
|
+
if (vKey === key && name === nodeName) {
|
|
4203
|
+
return vCurrent;
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
3973
4206
|
// it is not materialized; so materialize it.
|
|
3974
4207
|
diffContext.vSiblings = new Map();
|
|
3975
4208
|
diffContext.vSiblingsArray = [];
|
|
@@ -4005,8 +4238,9 @@ function retrieveChildWithKey(diffContext, nodeName, key) {
|
|
|
4005
4238
|
}
|
|
4006
4239
|
else {
|
|
4007
4240
|
const siblingsKey = getSideBufferKey(nodeName, key);
|
|
4008
|
-
|
|
4009
|
-
|
|
4241
|
+
const sibling = diffContext.vSiblings.get(siblingsKey);
|
|
4242
|
+
if (sibling) {
|
|
4243
|
+
vNodeWithKey = sibling;
|
|
4010
4244
|
diffContext.vSiblings.delete(siblingsKey);
|
|
4011
4245
|
}
|
|
4012
4246
|
}
|
|
@@ -4075,6 +4309,7 @@ function moveOrCreateKeyedNode(diffContext, nodeName, lookupKey, sideBufferKey,
|
|
|
4075
4309
|
// 1) Try to find the node among upcoming siblings
|
|
4076
4310
|
diffContext.vNewNode = retrieveChildWithKey(diffContext, nodeName, lookupKey);
|
|
4077
4311
|
if (diffContext.vNewNode) {
|
|
4312
|
+
vnode_insertBefore(diffContext.journal, parentForInsert, diffContext.vNewNode, diffContext.vCurrent);
|
|
4078
4313
|
diffContext.vCurrent = diffContext.vNewNode;
|
|
4079
4314
|
diffContext.vNewNode = null;
|
|
4080
4315
|
return false;
|
|
@@ -4118,7 +4353,7 @@ function expectVirtual(diffContext, type, jsxKey) {
|
|
|
4118
4353
|
return;
|
|
4119
4354
|
}
|
|
4120
4355
|
// For fragments without a key, always create a new virtual node (ensures rerender semantics)
|
|
4121
|
-
if (jsxKey === null) {
|
|
4356
|
+
if (jsxKey === null || diffContext.isCreationMode) {
|
|
4122
4357
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newVirtual()), diffContext.vCurrent && getInsertBefore(diffContext));
|
|
4123
4358
|
diffContext.vNewNode.key = jsxKey;
|
|
4124
4359
|
isDev && vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, type);
|
|
@@ -4247,7 +4482,7 @@ function expectText(diffContext, text) {
|
|
|
4247
4482
|
return;
|
|
4248
4483
|
}
|
|
4249
4484
|
}
|
|
4250
|
-
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newText(diffContext.container.document.createTextNode(text), text)), diffContext.vCurrent);
|
|
4485
|
+
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newText((import.meta.env.TEST ? diffContext.container.document : document).createTextNode(text), text)), diffContext.vCurrent);
|
|
4251
4486
|
}
|
|
4252
4487
|
/**
|
|
4253
4488
|
* Retrieve the key from the VNode.
|
|
@@ -4304,13 +4539,10 @@ function Projection() { }
|
|
|
4304
4539
|
function handleProps(host, jsxProps, vNodeProps, container) {
|
|
4305
4540
|
let shouldRender = false;
|
|
4306
4541
|
if (vNodeProps) {
|
|
4307
|
-
const effects = vNodeProps[_PROPS_HANDLER].$effects$;
|
|
4308
4542
|
const constPropsDifferent = handleChangedProps(jsxProps[_CONST_PROPS], vNodeProps[_CONST_PROPS], vNodeProps[_PROPS_HANDLER], container, false);
|
|
4309
4543
|
shouldRender ||= constPropsDifferent;
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
// don't mark as should render, effects will take care of it
|
|
4313
|
-
}
|
|
4544
|
+
const varPropsDifferent = handleChangedProps(jsxProps[_VAR_PROPS], vNodeProps[_VAR_PROPS], vNodeProps[_PROPS_HANDLER], container, true);
|
|
4545
|
+
shouldRender ||= varPropsDifferent;
|
|
4314
4546
|
// Update the owner after all props have been synced
|
|
4315
4547
|
vNodeProps[_OWNER] = jsxProps[_OWNER];
|
|
4316
4548
|
}
|
|
@@ -4335,7 +4567,6 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4335
4567
|
continue;
|
|
4336
4568
|
}
|
|
4337
4569
|
if (!dst || src[key] !== dst[key]) {
|
|
4338
|
-
changed = true;
|
|
4339
4570
|
if (triggerEffects) {
|
|
4340
4571
|
if (dst) {
|
|
4341
4572
|
// Update the value in dst BEFORE triggering effects
|
|
@@ -4343,7 +4574,11 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4343
4574
|
// Note: Value is not triggering effects, because we are modyfing direct VAR_PROPS object
|
|
4344
4575
|
dst[key] = src[key];
|
|
4345
4576
|
}
|
|
4346
|
-
triggerPropsProxyEffect(propsHandler, key);
|
|
4577
|
+
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
4578
|
+
if (!didTigger) {
|
|
4579
|
+
// If the effect was not triggered, then the prop has changed and we should rerender
|
|
4580
|
+
changed = true;
|
|
4581
|
+
}
|
|
4347
4582
|
}
|
|
4348
4583
|
else {
|
|
4349
4584
|
// Early return for const props (no effects)
|
|
@@ -4359,10 +4594,13 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4359
4594
|
continue;
|
|
4360
4595
|
}
|
|
4361
4596
|
if (!src || !_hasOwnProperty.call(src, key)) {
|
|
4362
|
-
changed = true;
|
|
4363
4597
|
if (triggerEffects) {
|
|
4364
4598
|
delete dst[key];
|
|
4365
|
-
triggerPropsProxyEffect(propsHandler, key);
|
|
4599
|
+
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
4600
|
+
if (!didTigger) {
|
|
4601
|
+
// If the effect was not triggered, then the prop has changed and we should rerender
|
|
4602
|
+
changed = true;
|
|
4603
|
+
}
|
|
4366
4604
|
}
|
|
4367
4605
|
}
|
|
4368
4606
|
}
|
|
@@ -4535,6 +4773,37 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
4535
4773
|
*/
|
|
4536
4774
|
vCursor.flags |= 32 /* VNodeFlags.Deleted */;
|
|
4537
4775
|
}
|
|
4776
|
+
function areWrappedSignalsEqual(oldSignal, newSignal) {
|
|
4777
|
+
if (oldSignal === newSignal) {
|
|
4778
|
+
return true;
|
|
4779
|
+
}
|
|
4780
|
+
return (newSignal.$func$ === oldSignal.$func$ && areArgumentsEqual(newSignal.$args$, oldSignal.$args$));
|
|
4781
|
+
}
|
|
4782
|
+
function areArgumentsEqual(oldArgs, newArgs) {
|
|
4783
|
+
if (oldArgs === newArgs) {
|
|
4784
|
+
return true;
|
|
4785
|
+
}
|
|
4786
|
+
if (!oldArgs || !newArgs || oldArgs.length !== newArgs.length) {
|
|
4787
|
+
return false;
|
|
4788
|
+
}
|
|
4789
|
+
for (let i = 0; i < oldArgs.length; i++) {
|
|
4790
|
+
if (oldArgs[i] !== newArgs[i]) {
|
|
4791
|
+
return false;
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
return true;
|
|
4795
|
+
}
|
|
4796
|
+
function containsWrappedSignal(data, signal) {
|
|
4797
|
+
if (!(signal instanceof WrappedSignalImpl)) {
|
|
4798
|
+
return false;
|
|
4799
|
+
}
|
|
4800
|
+
for (const item of data) {
|
|
4801
|
+
if (item instanceof WrappedSignalImpl && areWrappedSignalsEqual(item, signal)) {
|
|
4802
|
+
return true;
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
return false;
|
|
4806
|
+
}
|
|
4538
4807
|
/**
|
|
4539
4808
|
* This marks the property as immutable. It is needed for the QRLs so that QwikLoader can get a hold
|
|
4540
4809
|
* of them. This character must be `:` so that the `vnode_getAttr` can ignore them.
|
|
@@ -4542,6 +4811,41 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
4542
4811
|
const HANDLER_PREFIX = ':';
|
|
4543
4812
|
let count = 0;
|
|
4544
4813
|
|
|
4814
|
+
/**
|
|
4815
|
+
* @internal
|
|
4816
|
+
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
4817
|
+
*/
|
|
4818
|
+
const useSequentialScope = () => {
|
|
4819
|
+
const iCtx = useInvokeContext();
|
|
4820
|
+
const hostElement = iCtx.$hostElement$;
|
|
4821
|
+
const host = hostElement;
|
|
4822
|
+
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
4823
|
+
if (seq === null) {
|
|
4824
|
+
seq = [];
|
|
4825
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
4826
|
+
}
|
|
4827
|
+
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
4828
|
+
if (seqIdx === null) {
|
|
4829
|
+
seqIdx = 0;
|
|
4830
|
+
}
|
|
4831
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
4832
|
+
while (seq.length <= seqIdx) {
|
|
4833
|
+
seq.push(undefined);
|
|
4834
|
+
}
|
|
4835
|
+
const set = (value) => {
|
|
4836
|
+
if (qDev && qSerialize) {
|
|
4837
|
+
verifySerializable(value);
|
|
4838
|
+
}
|
|
4839
|
+
return (seq[seqIdx] = value);
|
|
4840
|
+
};
|
|
4841
|
+
return {
|
|
4842
|
+
val: seq[seqIdx],
|
|
4843
|
+
set,
|
|
4844
|
+
i: seqIdx,
|
|
4845
|
+
iCtx,
|
|
4846
|
+
};
|
|
4847
|
+
};
|
|
4848
|
+
|
|
4545
4849
|
/** @internal */
|
|
4546
4850
|
const useResourceQrl = (qrl, opts) => {
|
|
4547
4851
|
const { val, set, i, iCtx } = useSequentialScope();
|
|
@@ -4683,7 +4987,8 @@ const runResource = (task, container, host) => {
|
|
|
4683
4987
|
iCtx.$container$ = container;
|
|
4684
4988
|
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
4685
4989
|
const resource = task.$state$;
|
|
4686
|
-
|
|
4990
|
+
isDev &&
|
|
4991
|
+
assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
|
|
4687
4992
|
const track = trackFn(task, container);
|
|
4688
4993
|
const [cleanup, cleanups] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
4689
4994
|
const resourceTarget = unwrapStore(resource);
|
|
@@ -4776,33 +5081,6 @@ const runResource = (task, container, host) => {
|
|
|
4776
5081
|
return promise;
|
|
4777
5082
|
};
|
|
4778
5083
|
|
|
4779
|
-
/** Factory functions to create operations with consistent hidden classes. */
|
|
4780
|
-
const createDeleteOperation = (target) => ({
|
|
4781
|
-
operationType: 1 /* VNodeOperationType.Delete */,
|
|
4782
|
-
target,
|
|
4783
|
-
});
|
|
4784
|
-
const createRemoveAllChildrenOperation = (target) => ({
|
|
4785
|
-
operationType: 4 /* VNodeOperationType.RemoveAllChildren */,
|
|
4786
|
-
target,
|
|
4787
|
-
});
|
|
4788
|
-
const createSetTextOperation = (target, text) => ({
|
|
4789
|
-
operationType: 16 /* VNodeOperationType.SetText */,
|
|
4790
|
-
target,
|
|
4791
|
-
text,
|
|
4792
|
-
});
|
|
4793
|
-
const createInsertOrMoveOperation = (target, parent, beforeTarget) => ({
|
|
4794
|
-
operationType: 2 /* VNodeOperationType.InsertOrMove */,
|
|
4795
|
-
target,
|
|
4796
|
-
parent,
|
|
4797
|
-
beforeTarget,
|
|
4798
|
-
});
|
|
4799
|
-
const createSetAttributeOperation = (target, attrName, attrValue) => ({
|
|
4800
|
-
operationType: 8 /* VNodeOperationType.SetAttribute */,
|
|
4801
|
-
target,
|
|
4802
|
-
attrName,
|
|
4803
|
-
attrValue,
|
|
4804
|
-
});
|
|
4805
|
-
|
|
4806
5084
|
/**
|
|
4807
5085
|
* Executes tasks for a vNode if the TASKS dirty bit is set. Tasks are stored in the ELEMENT_SEQ
|
|
4808
5086
|
* property and executed in order.
|
|
@@ -4947,8 +5225,8 @@ function clearNodePropData(vNode) {
|
|
|
4947
5225
|
const props = (vNode.props ||= {});
|
|
4948
5226
|
delete props[NODE_PROPS_DATA_KEY];
|
|
4949
5227
|
}
|
|
4950
|
-
function setNodeProp(domVNode, journal, property, value, isConst) {
|
|
4951
|
-
journal.push(createSetAttributeOperation(domVNode.node, property, value));
|
|
5228
|
+
function setNodeProp(domVNode, journal, property, value, isConst, scopedStyleIdPrefix = null) {
|
|
5229
|
+
journal.push(createSetAttributeOperation(domVNode.node, property, value, scopedStyleIdPrefix, (domVNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
4952
5230
|
if (!isConst) {
|
|
4953
5231
|
if (domVNode.props && value == null) {
|
|
4954
5232
|
delete domVNode.props[property];
|
|
@@ -4983,10 +5261,9 @@ function executeNodeProps(vNode, journal) {
|
|
|
4983
5261
|
// TODO: Handle async signals (promises) - need to track pending async prop data
|
|
4984
5262
|
value = value.value;
|
|
4985
5263
|
}
|
|
4986
|
-
//
|
|
4987
|
-
const serializedValue = serializeAttribute(property, value, nodeProp.scopedStyleIdPrefix);
|
|
5264
|
+
// Pass raw value and scopedStyleIdPrefix - serialization happens in flush
|
|
4988
5265
|
const isConst = nodeProp.isConst;
|
|
4989
|
-
setNodeProp(domVNode, journal, property,
|
|
5266
|
+
setNodeProp(domVNode, journal, property, value, isConst, nodeProp.scopedStyleIdPrefix);
|
|
4990
5267
|
}
|
|
4991
5268
|
// Clear pending prop data after processing
|
|
4992
5269
|
clearNodePropData(vNode);
|
|
@@ -5065,59 +5342,129 @@ const fastInsertBefore = (insertBeforeParent, target, insertBefore) => {
|
|
|
5065
5342
|
_insertBefore.call(insertBeforeParent, target, insertBefore);
|
|
5066
5343
|
};
|
|
5067
5344
|
function _flushJournal(journal) {
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
}
|
|
5077
|
-
case 1 /* VNodeOperationType.Delete */: {
|
|
5078
|
-
operation.target.remove();
|
|
5079
|
-
break;
|
|
5345
|
+
let batchParent = null;
|
|
5346
|
+
let batchBefore = null;
|
|
5347
|
+
let batchNodes = null;
|
|
5348
|
+
const batchSet = new Set();
|
|
5349
|
+
const flush = () => {
|
|
5350
|
+
if (batchNodes) {
|
|
5351
|
+
if (batchNodes.length === 1) {
|
|
5352
|
+
fastInsertBefore(batchParent, batchNodes[0], batchBefore);
|
|
5080
5353
|
}
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
const element = operation.target;
|
|
5087
|
-
const attrName = operation.attrName;
|
|
5088
|
-
const attrValue = operation.attrValue;
|
|
5089
|
-
const shouldRemove = attrValue == null || attrValue === false;
|
|
5090
|
-
if (isBooleanAttr(element, attrName)) {
|
|
5091
|
-
element[attrName] = parseBoolean(attrValue);
|
|
5092
|
-
}
|
|
5093
|
-
else if (attrName === dangerouslySetInnerHTML) {
|
|
5094
|
-
element.innerHTML = attrValue;
|
|
5095
|
-
element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
|
|
5354
|
+
else {
|
|
5355
|
+
const doc = batchParent.ownerDocument || batchParent;
|
|
5356
|
+
const fragment = doc.createDocumentFragment();
|
|
5357
|
+
for (const node of batchNodes) {
|
|
5358
|
+
fragment.appendChild(node);
|
|
5096
5359
|
}
|
|
5097
|
-
|
|
5098
|
-
|
|
5360
|
+
fastInsertBefore(batchParent, fragment, batchBefore);
|
|
5361
|
+
}
|
|
5362
|
+
batchNodes = null;
|
|
5363
|
+
batchParent = null;
|
|
5364
|
+
batchBefore = null;
|
|
5365
|
+
batchSet.clear();
|
|
5366
|
+
}
|
|
5367
|
+
};
|
|
5368
|
+
for (const operation of journal) {
|
|
5369
|
+
if (operation instanceof InsertOrMoveOperation) {
|
|
5370
|
+
if (batchParent === operation.parent && batchBefore === operation.beforeTarget) {
|
|
5371
|
+
if (!batchNodes) {
|
|
5372
|
+
batchNodes = [];
|
|
5099
5373
|
}
|
|
5100
|
-
|
|
5101
|
-
|
|
5374
|
+
batchNodes.push(operation.target);
|
|
5375
|
+
batchSet.add(operation.target);
|
|
5376
|
+
continue;
|
|
5377
|
+
}
|
|
5378
|
+
if (batchNodes) {
|
|
5379
|
+
// If we have an existing batch, we need to check if the new operation conflicts with it.
|
|
5380
|
+
// 1. If we are inserting into the same parent but with a different "before" reference, we must flush.
|
|
5381
|
+
if (batchParent === operation.parent) {
|
|
5382
|
+
flush();
|
|
5383
|
+
batchParent = operation.parent;
|
|
5384
|
+
batchBefore = operation.beforeTarget;
|
|
5385
|
+
batchNodes = [operation.target];
|
|
5386
|
+
batchSet.add(operation.target);
|
|
5387
|
+
continue;
|
|
5102
5388
|
}
|
|
5103
|
-
|
|
5104
|
-
|
|
5389
|
+
// 2. If we are moving a node that is currently in the batch, or moving the node that is the reference for the batch.
|
|
5390
|
+
if (batchSet.has(operation.target) ||
|
|
5391
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5392
|
+
(batchParent && operation.target === batchParent)) {
|
|
5393
|
+
flush();
|
|
5394
|
+
batchParent = operation.parent;
|
|
5395
|
+
batchBefore = operation.beforeTarget;
|
|
5396
|
+
batchNodes = [operation.target];
|
|
5397
|
+
batchSet.add(operation.target);
|
|
5398
|
+
continue;
|
|
5105
5399
|
}
|
|
5106
|
-
|
|
5400
|
+
// 3. Otherwise, we can execute this operation immediately without flushing the current batch.
|
|
5401
|
+
// This is important for "interleaved" inserts, e.g. inserting <tr> into <tbody> (batched)
|
|
5402
|
+
// and then inserting <td> into that <tr> (immediate).
|
|
5403
|
+
// The <tr> is in memory, so inserting <td> into it is fine and doesn't require the <tr> to be in the DOM.
|
|
5107
5404
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5405
|
+
else {
|
|
5406
|
+
batchParent = operation.parent;
|
|
5407
|
+
batchBefore = operation.beforeTarget;
|
|
5408
|
+
batchNodes = [operation.target];
|
|
5409
|
+
batchSet.add(operation.target);
|
|
5410
|
+
continue;
|
|
5411
|
+
}
|
|
5412
|
+
fastInsertBefore(operation.parent, operation.target, operation.beforeTarget);
|
|
5413
|
+
continue;
|
|
5414
|
+
}
|
|
5415
|
+
if (operation instanceof DeleteOperation) {
|
|
5416
|
+
if (batchSet.has(operation.target) ||
|
|
5417
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5418
|
+
(batchParent && operation.target === batchParent)) {
|
|
5419
|
+
flush();
|
|
5420
|
+
}
|
|
5421
|
+
operation.target.remove();
|
|
5422
|
+
continue;
|
|
5423
|
+
}
|
|
5424
|
+
if (operation instanceof RemoveAllChildrenOperation) {
|
|
5425
|
+
if (batchSet.has(operation.target) ||
|
|
5426
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5427
|
+
(batchParent && operation.target === batchParent)) {
|
|
5428
|
+
flush();
|
|
5429
|
+
}
|
|
5430
|
+
// Removing children of a node in the batch is safe (clears detached node)
|
|
5431
|
+
const removeParent = operation.target;
|
|
5432
|
+
removeParent.textContent = '';
|
|
5433
|
+
continue;
|
|
5434
|
+
}
|
|
5435
|
+
if (operation instanceof SetTextOperation) {
|
|
5436
|
+
operation.target.nodeValue = operation.text;
|
|
5437
|
+
}
|
|
5438
|
+
else if (operation instanceof SetAttributeOperation) {
|
|
5439
|
+
const element = operation.target;
|
|
5440
|
+
const attrName = operation.attrName;
|
|
5441
|
+
const rawValue = operation.attrValue;
|
|
5442
|
+
const attrValue = rawValue != null
|
|
5443
|
+
? serializeAttribute(attrName, rawValue, operation.scopedStyleIdPrefix)
|
|
5444
|
+
: null;
|
|
5445
|
+
const shouldRemove = attrValue == null || attrValue === false;
|
|
5446
|
+
if (isBooleanAttr(element, attrName)) {
|
|
5447
|
+
element[attrName] = parseBoolean(attrValue);
|
|
5448
|
+
}
|
|
5449
|
+
else if (attrName === dangerouslySetInnerHTML) {
|
|
5450
|
+
if (batchParent === element) {
|
|
5451
|
+
flush();
|
|
5116
5452
|
}
|
|
5117
|
-
|
|
5453
|
+
element.innerHTML = attrValue;
|
|
5454
|
+
element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
|
|
5455
|
+
}
|
|
5456
|
+
else if (shouldRemove) {
|
|
5457
|
+
element.removeAttribute(attrName);
|
|
5458
|
+
}
|
|
5459
|
+
else if (attrName === 'value' && attrName in element) {
|
|
5460
|
+
element.value = attrValue;
|
|
5461
|
+
}
|
|
5462
|
+
else {
|
|
5463
|
+
directSetAttribute(element, attrName, attrValue, operation.isSvg);
|
|
5118
5464
|
}
|
|
5119
5465
|
}
|
|
5120
5466
|
}
|
|
5467
|
+
flush();
|
|
5121
5468
|
}
|
|
5122
5469
|
function executeAfterFlush(container, cursorData) {
|
|
5123
5470
|
const visibleTasks = cursorData.afterFlushTasks;
|
|
@@ -5253,7 +5600,7 @@ function processCursorQueue(options = {
|
|
|
5253
5600
|
*/
|
|
5254
5601
|
function walkCursor(cursor, options) {
|
|
5255
5602
|
const { timeBudget } = options;
|
|
5256
|
-
const
|
|
5603
|
+
const isRunningOnServer = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
5257
5604
|
const startTime = performance.now();
|
|
5258
5605
|
const cursorData = getCursorData(cursor);
|
|
5259
5606
|
// Check if cursor is blocked by a promise
|
|
@@ -5262,10 +5609,10 @@ function walkCursor(cursor, options) {
|
|
|
5262
5609
|
return;
|
|
5263
5610
|
}
|
|
5264
5611
|
const container = cursorData.container;
|
|
5265
|
-
assertDefined(container, 'Cursor container not found');
|
|
5612
|
+
isDev && assertDefined(container, 'Cursor container not found');
|
|
5266
5613
|
// Check if cursor is already complete
|
|
5267
5614
|
if (!cursor.dirty) {
|
|
5268
|
-
finishWalk(container, cursor, cursorData,
|
|
5615
|
+
finishWalk(container, cursor, cursorData, isRunningOnServer);
|
|
5269
5616
|
return;
|
|
5270
5617
|
}
|
|
5271
5618
|
const journal = (cursorData.journal ||= []);
|
|
@@ -5273,7 +5620,7 @@ function walkCursor(cursor, options) {
|
|
|
5273
5620
|
let currentVNode = null;
|
|
5274
5621
|
while ((currentVNode = cursorData.position)) {
|
|
5275
5622
|
// Check time budget (only for DOM, not SSR)
|
|
5276
|
-
if (!
|
|
5623
|
+
if (!isRunningOnServer && !import.meta.env.TEST) {
|
|
5277
5624
|
const elapsed = performance.now() - startTime;
|
|
5278
5625
|
if (elapsed >= timeBudget) {
|
|
5279
5626
|
// Schedule continuation as macrotask to actually yield to browser
|
|
@@ -5356,8 +5703,9 @@ function walkCursor(cursor, options) {
|
|
|
5356
5703
|
return;
|
|
5357
5704
|
}
|
|
5358
5705
|
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5706
|
+
isDev &&
|
|
5707
|
+
assertFalse(!!(cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */ && !cursorData.position), 'Cursor is still dirty and position is not set after walking');
|
|
5708
|
+
finishWalk(container, cursor, cursorData, isRunningOnServer);
|
|
5361
5709
|
}
|
|
5362
5710
|
function finishWalk(container, cursor, cursorData, isServer) {
|
|
5363
5711
|
if (!(cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */)) {
|
|
@@ -5377,7 +5725,7 @@ function finishWalk(container, cursor, cursorData, isServer) {
|
|
|
5377
5725
|
function resolveCursor(container) {
|
|
5378
5726
|
// TODO streaming as a cursor? otherwise we need to wait separately for it
|
|
5379
5727
|
// or just ignore and resolve manually
|
|
5380
|
-
if (container.$cursorCount$ === 0) {
|
|
5728
|
+
if (container.$cursorCount$ === 0 && container.$pausedCursorCount$ === 0) {
|
|
5381
5729
|
container.$resolveRenderPromise$();
|
|
5382
5730
|
container.$renderPromise$ = null;
|
|
5383
5731
|
}
|
|
@@ -5441,6 +5789,7 @@ function getNextVNode(vNode, cursor) {
|
|
|
5441
5789
|
// all array items checked, children are no longer dirty
|
|
5442
5790
|
parent.dirty &= -33 /* ChoreBits.CHILDREN */;
|
|
5443
5791
|
parent.dirtyChildren = null;
|
|
5792
|
+
parent.nextDirtyChildIndex = 0;
|
|
5444
5793
|
return getNextVNode(parent, cursor);
|
|
5445
5794
|
}
|
|
5446
5795
|
|
|
@@ -5529,8 +5878,13 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
5529
5878
|
promise = result;
|
|
5530
5879
|
}
|
|
5531
5880
|
}
|
|
5532
|
-
|
|
5533
|
-
|
|
5881
|
+
// In SSR, we don't handle the COMPONENT bit here.
|
|
5882
|
+
// During initial render, if a task completes and marks the component dirty,
|
|
5883
|
+
// we want to leave the COMPONENT bit set so that executeComponent can detect
|
|
5884
|
+
// it after $waitOn$ completes and re-execute the component function.
|
|
5885
|
+
// executeComponent will clear the bit after re-executing.
|
|
5886
|
+
// Clear all dirty bits EXCEPT COMPONENT
|
|
5887
|
+
ssrNode.dirty &= -124;
|
|
5534
5888
|
if (promise) {
|
|
5535
5889
|
return promise;
|
|
5536
5890
|
}
|
|
@@ -5649,7 +6003,7 @@ function findAndPropagateToBlockingCursor(vNode) {
|
|
|
5649
6003
|
return false;
|
|
5650
6004
|
}
|
|
5651
6005
|
function isSsrNodeGuard(_vNode) {
|
|
5652
|
-
return isServerPlatform();
|
|
6006
|
+
return import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
5653
6007
|
}
|
|
5654
6008
|
/**
|
|
5655
6009
|
* Marks a vNode as dirty and propagates dirty bits up the tree.
|
|
@@ -5855,21 +6209,22 @@ const fastGetter = (prototype, name) => {
|
|
|
5855
6209
|
*/
|
|
5856
6210
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
5857
6211
|
const vnode_newElement = (element, elementName, key = null) => {
|
|
5858
|
-
assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
6212
|
+
isDev && assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
5859
6213
|
const vnode = new ElementVNode(key, 1 /* VNodeFlags.Element */ | 8 /* VNodeFlags.Inflated */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5860
6214
|
null, null, null, null, null, null, element, elementName);
|
|
5861
6215
|
element.vNode = vnode;
|
|
5862
6216
|
return vnode;
|
|
5863
6217
|
};
|
|
5864
6218
|
const vnode_newUnMaterializedElement = (element) => {
|
|
5865
|
-
assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
6219
|
+
isDev && assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
5866
6220
|
const vnode = new ElementVNode(null, 1 /* VNodeFlags.Element */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5867
6221
|
null, null, null, null, undefined, undefined, element, undefined);
|
|
5868
6222
|
element.vNode = vnode;
|
|
5869
6223
|
return vnode;
|
|
5870
6224
|
};
|
|
5871
6225
|
const vnode_newSharedText = (previousTextNode, sharedTextNode, textContent) => {
|
|
5872
|
-
|
|
6226
|
+
isDev &&
|
|
6227
|
+
sharedTextNode &&
|
|
5873
6228
|
assertEqual(fastNodeType(sharedTextNode), 3 /* TEXT_NODE */, 'Expecting text node.');
|
|
5874
6229
|
const vnode = new TextVNode(4 /* VNodeFlags.Text */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5875
6230
|
null, // Parent
|
|
@@ -5886,18 +6241,18 @@ const vnode_newText = (textNode, textContent) => {
|
|
|
5886
6241
|
null, textNode, // TextNode
|
|
5887
6242
|
textContent // Text Content
|
|
5888
6243
|
);
|
|
5889
|
-
assertEqual(fastNodeType(textNode), 3 /* TEXT_NODE */, 'Expecting text node.');
|
|
5890
|
-
assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5891
|
-
assertTrue(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5892
|
-
assertFalse(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6244
|
+
isDev && assertEqual(fastNodeType(textNode), 3 /* TEXT_NODE */, 'Expecting text node.');
|
|
6245
|
+
isDev && assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6246
|
+
isDev && assertTrue(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6247
|
+
isDev && assertFalse(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5893
6248
|
return vnode;
|
|
5894
6249
|
};
|
|
5895
6250
|
const vnode_newVirtual = () => {
|
|
5896
6251
|
const vnode = new VirtualVNode(null, 2 /* VNodeFlags.Virtual */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flags
|
|
5897
6252
|
null, null, null, null, null, null);
|
|
5898
|
-
assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5899
|
-
assertFalse(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5900
|
-
assertTrue(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6253
|
+
isDev && assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6254
|
+
isDev && assertFalse(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6255
|
+
isDev && assertTrue(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5901
6256
|
return vnode;
|
|
5902
6257
|
};
|
|
5903
6258
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -5905,16 +6260,16 @@ const vnode_isVNode = (vNode) => {
|
|
|
5905
6260
|
return vNode instanceof VNode;
|
|
5906
6261
|
};
|
|
5907
6262
|
const vnode_isElementVNode = (vNode) => {
|
|
5908
|
-
return vNode
|
|
6263
|
+
return (vNode.flags & 1 /* VNodeFlags.Element */) === 1 /* VNodeFlags.Element */;
|
|
5909
6264
|
};
|
|
5910
6265
|
const vnode_isElementOrTextVNode = (vNode) => {
|
|
5911
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6266
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5912
6267
|
const flag = vNode.flags;
|
|
5913
6268
|
return (flag & 5 /* VNodeFlags.ELEMENT_OR_TEXT_MASK */) !== 0;
|
|
5914
6269
|
};
|
|
5915
6270
|
/** @internal */
|
|
5916
6271
|
const vnode_isMaterialized = (vNode) => {
|
|
5917
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6272
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5918
6273
|
const flag = vNode.flags;
|
|
5919
6274
|
return ((flag & 1 /* VNodeFlags.Element */) === 1 /* VNodeFlags.Element */ &&
|
|
5920
6275
|
vNode.firstChild !== undefined &&
|
|
@@ -5922,27 +6277,30 @@ const vnode_isMaterialized = (vNode) => {
|
|
|
5922
6277
|
};
|
|
5923
6278
|
/** @internal */
|
|
5924
6279
|
const vnode_isTextVNode = (vNode) => {
|
|
5925
|
-
return vNode
|
|
6280
|
+
return (vNode.flags & 4 /* VNodeFlags.Text */) === 4 /* VNodeFlags.Text */;
|
|
5926
6281
|
};
|
|
5927
6282
|
/** @internal */
|
|
5928
6283
|
const vnode_isVirtualVNode = (vNode) => {
|
|
5929
|
-
return vNode
|
|
6284
|
+
return (vNode.flags & 2 /* VNodeFlags.Virtual */) === 2 /* VNodeFlags.Virtual */;
|
|
5930
6285
|
};
|
|
5931
6286
|
const vnode_isProjection = (vNode) => {
|
|
5932
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6287
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5933
6288
|
const flag = vNode.flags;
|
|
5934
6289
|
return ((flag & 2 /* VNodeFlags.Virtual */) === 2 /* VNodeFlags.Virtual */ && vnode_getProp(vNode, QSlot, null) !== null);
|
|
5935
6290
|
};
|
|
5936
6291
|
const ensureTextVNode = (vNode) => {
|
|
5937
|
-
|
|
6292
|
+
isDev &&
|
|
6293
|
+
assertTrue(vnode_isTextVNode(vNode), 'Expecting TextVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5938
6294
|
return vNode;
|
|
5939
6295
|
};
|
|
5940
6296
|
const ensureElementOrVirtualVNode = (vNode) => {
|
|
5941
|
-
assertDefined(vNode, 'Missing vNode');
|
|
5942
|
-
|
|
6297
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
6298
|
+
isDev &&
|
|
6299
|
+
assertTrue((vNode.flags & 3 /* VNodeFlags.ELEMENT_OR_VIRTUAL_MASK */) !== 0, 'Expecting ElementVNode or VirtualVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5943
6300
|
};
|
|
5944
6301
|
const ensureElementVNode = (vNode) => {
|
|
5945
|
-
|
|
6302
|
+
isDev &&
|
|
6303
|
+
assertTrue(vnode_isElementVNode(vNode), 'Expecting ElementVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5946
6304
|
return vNode;
|
|
5947
6305
|
};
|
|
5948
6306
|
const vnode_getNodeTypeName = (vNode) => {
|
|
@@ -5972,20 +6330,21 @@ const vnode_getProp = (vNode, key, getObject) => {
|
|
|
5972
6330
|
return null;
|
|
5973
6331
|
};
|
|
5974
6332
|
const vnode_setProp = (vNode, key, value) => {
|
|
5975
|
-
if (
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
vNode.props[key] = value;
|
|
5982
|
-
}
|
|
6333
|
+
if (value == null && vNode.props) {
|
|
6334
|
+
delete vNode.props[key];
|
|
6335
|
+
}
|
|
6336
|
+
else {
|
|
6337
|
+
vNode.props ||= {};
|
|
6338
|
+
vNode.props[key] = value;
|
|
5983
6339
|
}
|
|
5984
6340
|
};
|
|
5985
|
-
const vnode_setAttr = (journal, vNode, key, value) => {
|
|
6341
|
+
const vnode_setAttr = (journal, vNode, key, value, scopedStyleIdPrefix = null) => {
|
|
5986
6342
|
if (vnode_isElementVNode(vNode)) {
|
|
6343
|
+
import.meta.env.TEST &&
|
|
6344
|
+
scopedStyleIdPrefix &&
|
|
6345
|
+
vnode_setProp(vNode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
5987
6346
|
vnode_setProp(vNode, key, value);
|
|
5988
|
-
addVNodeOperation(journal, createSetAttributeOperation(vNode.node, key, value));
|
|
6347
|
+
addVNodeOperation(journal, createSetAttributeOperation(vNode.node, key, value, scopedStyleIdPrefix, (vNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
5989
6348
|
}
|
|
5990
6349
|
};
|
|
5991
6350
|
const vnode_ensureElementKeyInflated = (vnode) => {
|
|
@@ -6218,7 +6577,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
|
|
|
6218
6577
|
const flags = textVNode.flags;
|
|
6219
6578
|
if ((flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
6220
6579
|
const parentNode = vnode_getDomParent(vnode, true);
|
|
6221
|
-
assertDefined(parentNode, 'Missing parent node.');
|
|
6580
|
+
isDev && assertDefined(parentNode, 'Missing parent node.');
|
|
6222
6581
|
const sharedTextNode = textVNode.node;
|
|
6223
6582
|
const doc = fastOwnerDocument(parentNode);
|
|
6224
6583
|
// Walk the previous siblings and inflate them.
|
|
@@ -6228,7 +6587,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
|
|
|
6228
6587
|
// case we know that the next node MUST be either NULL or an Element.
|
|
6229
6588
|
const node = vnode_getDomSibling(vnode, true, true);
|
|
6230
6589
|
const insertBeforeNode = sharedTextNode ||
|
|
6231
|
-
((node
|
|
6590
|
+
((node && vnode_isElementVNode(node) ? node.node : node?.node) || null);
|
|
6232
6591
|
let lastPreviousTextNode = insertBeforeNode;
|
|
6233
6592
|
while (vCursor && vnode_isTextVNode(vCursor)) {
|
|
6234
6593
|
if ((vCursor.flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
@@ -6268,7 +6627,7 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6268
6627
|
let elementOffset = -1;
|
|
6269
6628
|
let refElement;
|
|
6270
6629
|
if (typeof id === 'string') {
|
|
6271
|
-
assertDefined(qVNodeRefs, 'Missing qVNodeRefs.');
|
|
6630
|
+
isDev && assertDefined(qVNodeRefs, 'Missing qVNodeRefs.');
|
|
6272
6631
|
elementOffset = parseInt(id);
|
|
6273
6632
|
refElement = qVNodeRefs.get(elementOffset);
|
|
6274
6633
|
}
|
|
@@ -6279,9 +6638,10 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6279
6638
|
return vNode;
|
|
6280
6639
|
}
|
|
6281
6640
|
}
|
|
6282
|
-
assertDefined(refElement, 'Missing refElement.');
|
|
6641
|
+
isDev && assertDefined(refElement, 'Missing refElement.');
|
|
6283
6642
|
if (!vnode_isVNode(refElement)) {
|
|
6284
|
-
|
|
6643
|
+
isDev &&
|
|
6644
|
+
assertTrue(containerElement.contains(refElement), `Couldn't find the element inside the container while locating the VNode.`);
|
|
6285
6645
|
// We need to find the vnode.
|
|
6286
6646
|
let parent = refElement;
|
|
6287
6647
|
const elementPath = [refElement];
|
|
@@ -6329,10 +6689,10 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6329
6689
|
};
|
|
6330
6690
|
const vnode_getChildWithIdx = (vNode, childIdx) => {
|
|
6331
6691
|
let child = vnode_getFirstChild(vNode);
|
|
6332
|
-
assertDefined(child, 'Missing child.');
|
|
6692
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6333
6693
|
while (child.flags >>> 9 /* VNodeFlagsIndex.shift */ !== childIdx) {
|
|
6334
6694
|
child = child.nextSibling;
|
|
6335
|
-
assertDefined(child, 'Missing child.');
|
|
6695
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6336
6696
|
}
|
|
6337
6697
|
return child;
|
|
6338
6698
|
};
|
|
@@ -6340,7 +6700,7 @@ const vNodeStack = [];
|
|
|
6340
6700
|
const vnode_getVNodeForChildNode = (vNode, childElement) => {
|
|
6341
6701
|
ensureElementVNode(vNode);
|
|
6342
6702
|
let child = vnode_getFirstChild(vNode);
|
|
6343
|
-
assertDefined(child, 'Missing child.');
|
|
6703
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6344
6704
|
while (child && (child instanceof ElementVNode ? child.node !== childElement : true)) {
|
|
6345
6705
|
if (vnode_isVirtualVNode(child)) {
|
|
6346
6706
|
const next = child.nextSibling;
|
|
@@ -6362,13 +6722,13 @@ const vnode_getVNodeForChildNode = (vNode, childElement) => {
|
|
|
6362
6722
|
child = next || vNodeStack.pop();
|
|
6363
6723
|
}
|
|
6364
6724
|
}
|
|
6365
|
-
assertDefined(child, 'Missing child.');
|
|
6725
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6366
6726
|
}
|
|
6367
6727
|
while (vNodeStack.length) {
|
|
6368
6728
|
vNodeStack.pop();
|
|
6369
6729
|
}
|
|
6370
6730
|
ensureElementVNode(child);
|
|
6371
|
-
assertEqual(child.node, childElement, 'Child not found.');
|
|
6731
|
+
isDev && assertEqual(child.node, childElement, 'Child not found.');
|
|
6372
6732
|
// console.log('FOUND', child[VNodeProps.node]?.outerHTML);
|
|
6373
6733
|
return child;
|
|
6374
6734
|
};
|
|
@@ -6543,7 +6903,7 @@ const vnode_getDomParentVNode = (vnode, includeProjection) => {
|
|
|
6543
6903
|
return vnode;
|
|
6544
6904
|
};
|
|
6545
6905
|
const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
6546
|
-
assertEqual(vParent, vToRemove.parent, 'Parent mismatch.');
|
|
6906
|
+
isDev && assertEqual(vParent, vToRemove.parent, 'Parent mismatch.');
|
|
6547
6907
|
if (vnode_isTextVNode(vToRemove)) {
|
|
6548
6908
|
vnode_ensureTextInflated(journal, vToRemove);
|
|
6549
6909
|
}
|
|
@@ -6580,7 +6940,7 @@ const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
|
6580
6940
|
vToRemove.nextSibling = null;
|
|
6581
6941
|
};
|
|
6582
6942
|
const vnode_truncate = (journal, vParent, vDelete, removeDOM = true) => {
|
|
6583
|
-
assertDefined(vDelete, 'Missing vDelete.');
|
|
6943
|
+
isDev && assertDefined(vDelete, 'Missing vDelete.');
|
|
6584
6944
|
const parent = vnode_getDomParent(vParent, true);
|
|
6585
6945
|
if (parent && removeDOM) {
|
|
6586
6946
|
if (vnode_isElementVNode(vParent)) {
|
|
@@ -6699,8 +7059,8 @@ const ensureMaterialized = (vnode) => {
|
|
|
6699
7059
|
vFirstChild = vnode_materialize(vParent);
|
|
6700
7060
|
}
|
|
6701
7061
|
}
|
|
6702
|
-
assertTrue(vParent.firstChild !== undefined, 'Did not materialize.');
|
|
6703
|
-
assertTrue(vParent.lastChild !== undefined, 'Did not materialize.');
|
|
7062
|
+
isDev && assertTrue(vParent.firstChild !== undefined, 'Did not materialize.');
|
|
7063
|
+
isDev && assertTrue(vParent.lastChild !== undefined, 'Did not materialize.');
|
|
6704
7064
|
return vFirstChild;
|
|
6705
7065
|
};
|
|
6706
7066
|
let _fastHasAttribute = null;
|
|
@@ -7018,8 +7378,11 @@ function vnode_toString(depth = 20, offset = '', materialize = false, siblings =
|
|
|
7018
7378
|
else if (vnode_isVirtualVNode(vnode)) {
|
|
7019
7379
|
const idx = vnode.flags >>> 9 /* VNodeFlagsIndex.shift */;
|
|
7020
7380
|
const attrs = ['[' + String(idx) + ']'];
|
|
7381
|
+
if (vnode.dirty) {
|
|
7382
|
+
attrs.push(` dirty:${vnode.dirty}`);
|
|
7383
|
+
}
|
|
7021
7384
|
vnode_getAttrKeys(vnode).forEach((key) => {
|
|
7022
|
-
if (key !== DEBUG_TYPE) {
|
|
7385
|
+
if (key !== DEBUG_TYPE && key !== debugStyleScopeIdPrefixAttr) {
|
|
7023
7386
|
const value = vnode_getProp(vnode, key, null);
|
|
7024
7387
|
attrs.push(' ' + key + '=' + qwikDebugToString(value));
|
|
7025
7388
|
}
|
|
@@ -7336,8 +7699,8 @@ const useInvokeContext = () => {
|
|
|
7336
7699
|
if (!ctx || ctx.$event$ !== RenderEvent) {
|
|
7337
7700
|
throw qError(10 /* QError.useInvokeContext */);
|
|
7338
7701
|
}
|
|
7339
|
-
assertDefined(ctx.$hostElement$, `invoke: $hostElement$ must be defined`, ctx);
|
|
7340
|
-
assertDefined(ctx.$effectSubscriber$, `invoke: $effectSubscriber$ must be defined`, ctx);
|
|
7702
|
+
isDev && assertDefined(ctx.$hostElement$, `invoke: $hostElement$ must be defined`, ctx);
|
|
7703
|
+
isDev && assertDefined(ctx.$effectSubscriber$, `invoke: $effectSubscriber$ must be defined`, ctx);
|
|
7341
7704
|
return ctx;
|
|
7342
7705
|
};
|
|
7343
7706
|
function useBindInvokeContext(fn) {
|
|
@@ -7556,7 +7919,8 @@ const _waitUntilRendered = (elm) => {
|
|
|
7556
7919
|
*/
|
|
7557
7920
|
// </docs>
|
|
7558
7921
|
const createContextId = (name) => {
|
|
7559
|
-
|
|
7922
|
+
isDev &&
|
|
7923
|
+
assertTrue(/^[\w/.-]+$/.test(name), 'Context name must only contain A-Z,a-z,0-9,_,.,-', name);
|
|
7560
7924
|
return /*#__PURE__*/ Object.freeze({
|
|
7561
7925
|
id: fromCamelToKebabCase(name),
|
|
7562
7926
|
});
|
|
@@ -7803,6 +8167,7 @@ const _typeIdNames = [
|
|
|
7803
8167
|
'JSXNode',
|
|
7804
8168
|
'PropsProxy',
|
|
7805
8169
|
'SubscriptionData',
|
|
8170
|
+
'EffectSubscription',
|
|
7806
8171
|
];
|
|
7807
8172
|
|
|
7808
8173
|
function qrlToString(serializationContext, value, raw) {
|
|
@@ -7860,13 +8225,16 @@ function qrlToString(serializationContext, value, raw) {
|
|
|
7860
8225
|
return qrlStringInline;
|
|
7861
8226
|
}
|
|
7862
8227
|
function createQRLWithBackChannel(chunk, symbol, captureIds) {
|
|
7863
|
-
let
|
|
8228
|
+
let qrlImporter = null;
|
|
7864
8229
|
if (isDev && chunk === QRL_RUNTIME_CHUNK) {
|
|
7865
8230
|
const backChannel = globalThis.__qrl_back_channel__;
|
|
7866
|
-
assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
7867
|
-
|
|
8231
|
+
isDev && assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
8232
|
+
const fn = backChannel.get(symbol);
|
|
8233
|
+
if (fn) {
|
|
8234
|
+
qrlImporter = () => Promise.resolve({ [symbol]: fn });
|
|
8235
|
+
}
|
|
7868
8236
|
}
|
|
7869
|
-
return createQRL(chunk, symbol,
|
|
8237
|
+
return createQRL(chunk, symbol, null, qrlImporter, captureIds, null);
|
|
7870
8238
|
}
|
|
7871
8239
|
/** Parses "chunk#hash[...rootRef]" */
|
|
7872
8240
|
function parseQRL(qrl) {
|
|
@@ -7978,7 +8346,7 @@ const allocate = (container, typeId, value) => {
|
|
|
7978
8346
|
case 30 /* TypeIds.FormData */:
|
|
7979
8347
|
return new FormData();
|
|
7980
8348
|
case 31 /* TypeIds.JSXNode */:
|
|
7981
|
-
return new JSXNodeImpl(null);
|
|
8349
|
+
return new JSXNodeImpl(null, null, null, null, null);
|
|
7982
8350
|
case 11 /* TypeIds.BigInt */:
|
|
7983
8351
|
return BigInt(value);
|
|
7984
8352
|
case 16 /* TypeIds.Set */:
|
|
@@ -8042,6 +8410,8 @@ const allocate = (container, typeId, value) => {
|
|
|
8042
8410
|
}
|
|
8043
8411
|
case 33 /* TypeIds.SubscriptionData */:
|
|
8044
8412
|
return new SubscriptionData({});
|
|
8413
|
+
case 34 /* TypeIds.EffectSubscription */:
|
|
8414
|
+
return new EffectSubscription(null, null, null, null);
|
|
8045
8415
|
default:
|
|
8046
8416
|
throw qError(18 /* QError.serializeErrorCannotAllocate */, [typeId]);
|
|
8047
8417
|
}
|
|
@@ -8164,33 +8534,6 @@ const _regSymbol = (symbol, hash) => {
|
|
|
8164
8534
|
return symbol;
|
|
8165
8535
|
};
|
|
8166
8536
|
|
|
8167
|
-
/**
|
|
8168
|
-
* This is called by qwik-loader to run a QRL. It has to be synchronous.
|
|
8169
|
-
*
|
|
8170
|
-
* @internal
|
|
8171
|
-
*/
|
|
8172
|
-
const _run = (...args) => {
|
|
8173
|
-
// This will already check container
|
|
8174
|
-
const [runQrl] = useLexicalScope();
|
|
8175
|
-
const context = getInvokeContext();
|
|
8176
|
-
const hostElement = context.$hostElement$;
|
|
8177
|
-
if (hostElement) {
|
|
8178
|
-
return retryOnPromise(() => {
|
|
8179
|
-
if (!(hostElement.flags & 32 /* VNodeFlags.Deleted */)) {
|
|
8180
|
-
return catchError(runQrl(...args), (err) => {
|
|
8181
|
-
const container = (context.$container$ ||= getDomContainer(hostElement.node));
|
|
8182
|
-
if (container) {
|
|
8183
|
-
container.handleError(err, hostElement);
|
|
8184
|
-
}
|
|
8185
|
-
else {
|
|
8186
|
-
throw err;
|
|
8187
|
-
}
|
|
8188
|
-
});
|
|
8189
|
-
}
|
|
8190
|
-
});
|
|
8191
|
-
}
|
|
8192
|
-
};
|
|
8193
|
-
|
|
8194
8537
|
/** @file Shared types */
|
|
8195
8538
|
/** @internal */
|
|
8196
8539
|
function isStringifiable(value) {
|
|
@@ -8469,6 +8812,14 @@ async function serialize(serializationContext) {
|
|
|
8469
8812
|
else if (value instanceof SubscriptionData) {
|
|
8470
8813
|
output(33 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
|
|
8471
8814
|
}
|
|
8815
|
+
else if (value instanceof EffectSubscription) {
|
|
8816
|
+
output(34 /* TypeIds.EffectSubscription */, [
|
|
8817
|
+
value.consumer,
|
|
8818
|
+
value.property,
|
|
8819
|
+
value.backRef,
|
|
8820
|
+
value.data,
|
|
8821
|
+
]);
|
|
8822
|
+
}
|
|
8472
8823
|
else if (isStore(value)) {
|
|
8473
8824
|
if (isResource(value)) {
|
|
8474
8825
|
// let render know about the resource
|
|
@@ -8918,7 +9269,7 @@ function filterEffectBackRefs(effectBackRef) {
|
|
|
8918
9269
|
let effectBackRefToSerialize = undefined;
|
|
8919
9270
|
if (effectBackRef) {
|
|
8920
9271
|
for (const [effectProp, effect] of effectBackRef) {
|
|
8921
|
-
if (effect
|
|
9272
|
+
if (effect.backRef) {
|
|
8922
9273
|
effectBackRefToSerialize ||= new Map();
|
|
8923
9274
|
effectBackRefToSerialize.set(effectProp, effect);
|
|
8924
9275
|
}
|
|
@@ -9087,6 +9438,7 @@ class _SharedContainer {
|
|
|
9087
9438
|
$renderPromise$ = null;
|
|
9088
9439
|
$resolveRenderPromise$ = null;
|
|
9089
9440
|
$cursorCount$ = 0;
|
|
9441
|
+
$pausedCursorCount$ = 0;
|
|
9090
9442
|
constructor(serverData, locale) {
|
|
9091
9443
|
this.$serverData$ = serverData;
|
|
9092
9444
|
this.$locale$ = locale;
|
|
@@ -9125,8 +9477,6 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
|
|
|
9125
9477
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
9126
9478
|
}
|
|
9127
9479
|
return executeComponent(ssr, host, host, componentQrl, srcProps);
|
|
9128
|
-
// const componentChore = ssr.$scheduler$(ChoreType.COMPONENT, host, componentQrl, srcProps);
|
|
9129
|
-
// return getChorePromise(componentChore);
|
|
9130
9480
|
};
|
|
9131
9481
|
|
|
9132
9482
|
class ParentComponentData {
|
|
@@ -9276,7 +9626,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
9276
9626
|
children != null && enqueue(children);
|
|
9277
9627
|
}
|
|
9278
9628
|
else if (type === Slot) {
|
|
9279
|
-
const componentFrame = options.parentComponentFrame
|
|
9629
|
+
const componentFrame = options.parentComponentFrame;
|
|
9280
9630
|
if (componentFrame) {
|
|
9281
9631
|
const compId = componentFrame.componentNode.id || '';
|
|
9282
9632
|
const projectionAttrs = isDev ? [DEBUG_TYPE, "P" /* VirtualType.Projection */] : [];
|
|
@@ -9398,6 +9748,9 @@ function toSsrAttrs(record, options) {
|
|
|
9398
9748
|
if (isPreventDefault(key)) {
|
|
9399
9749
|
addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
|
|
9400
9750
|
}
|
|
9751
|
+
else if (key === ITERATION_ITEM_SINGLE || key === ITERATION_ITEM_MULTI) {
|
|
9752
|
+
value = options.serializationCtx.$addRoot$(value);
|
|
9753
|
+
}
|
|
9401
9754
|
value = serializeAttribute(key, value, options.styleScopedId);
|
|
9402
9755
|
ssrAttrs.push(key, value);
|
|
9403
9756
|
};
|
|
@@ -9714,7 +10067,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9714
10067
|
const d = data;
|
|
9715
10068
|
let owner = d[0];
|
|
9716
10069
|
if (owner === _UNINITIALIZED) {
|
|
9717
|
-
owner = new JSXNodeImpl(Fragment, d[1], d[2]);
|
|
10070
|
+
owner = new JSXNodeImpl(Fragment, d[1], d[2], null, null);
|
|
9718
10071
|
owner._proxy = propsProxy;
|
|
9719
10072
|
}
|
|
9720
10073
|
propsProxy[_OWNER] = owner;
|
|
@@ -9726,6 +10079,15 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9726
10079
|
effectData.data.$isConst$ = data[1];
|
|
9727
10080
|
break;
|
|
9728
10081
|
}
|
|
10082
|
+
case 34 /* TypeIds.EffectSubscription */: {
|
|
10083
|
+
const effectSub = target;
|
|
10084
|
+
const d = data;
|
|
10085
|
+
effectSub.consumer = d[0];
|
|
10086
|
+
effectSub.property = d[1];
|
|
10087
|
+
effectSub.backRef = d[2];
|
|
10088
|
+
effectSub.data = d[3];
|
|
10089
|
+
break;
|
|
10090
|
+
}
|
|
9729
10091
|
default:
|
|
9730
10092
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
9731
10093
|
}
|
|
@@ -9770,7 +10132,8 @@ function inflateWrappedSignalValue(signal) {
|
|
|
9770
10132
|
let hasAttrValue = false;
|
|
9771
10133
|
if (effects) {
|
|
9772
10134
|
// Find string keys (attribute names) in the effect back refs
|
|
9773
|
-
for (const
|
|
10135
|
+
for (const effect of effects) {
|
|
10136
|
+
const key = effect.property;
|
|
9774
10137
|
if (isString(key)) {
|
|
9775
10138
|
// This is an attribute name, try to read its value
|
|
9776
10139
|
const attrValue = vnode_getProp(hostVNode, key, null);
|
|
@@ -10399,7 +10762,7 @@ class DomContainer extends _SharedContainer {
|
|
|
10399
10762
|
};
|
|
10400
10763
|
getSyncFn(id) {
|
|
10401
10764
|
const fn = this.$qFuncs$[id];
|
|
10402
|
-
assertTrue(typeof fn === 'function', 'Invalid reference: ' + id);
|
|
10765
|
+
isDev && assertTrue(typeof fn === 'function', 'Invalid reference: ' + id);
|
|
10403
10766
|
return fn;
|
|
10404
10767
|
}
|
|
10405
10768
|
$appendStyle$(content, styleId, host, scoped) {
|
|
@@ -10441,6 +10804,81 @@ class DomContainer extends _SharedContainer {
|
|
|
10441
10804
|
}
|
|
10442
10805
|
}
|
|
10443
10806
|
|
|
10807
|
+
/** @internal */
|
|
10808
|
+
const useTaskQrl = (qrl, opts) => {
|
|
10809
|
+
const { val, set, iCtx, i } = useSequentialScope();
|
|
10810
|
+
if (val) {
|
|
10811
|
+
return;
|
|
10812
|
+
}
|
|
10813
|
+
assertQrl(qrl);
|
|
10814
|
+
set(1);
|
|
10815
|
+
const taskFlags =
|
|
10816
|
+
// enabled by default
|
|
10817
|
+
opts?.deferUpdates === false ? 0 : 16 /* TaskFlags.RENDER_BLOCKING */;
|
|
10818
|
+
const task = new Task(8 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
10819
|
+
// In V2 we add the task to the sequential scope. We need to do this
|
|
10820
|
+
// in order to be able to retrieve it later when the parent element is
|
|
10821
|
+
// deleted and we need to be able to release the task subscriptions.
|
|
10822
|
+
set(task);
|
|
10823
|
+
const container = iCtx.$container$;
|
|
10824
|
+
const { $waitOn$: waitOn } = iCtx;
|
|
10825
|
+
const result = maybeThen(waitOn, () => runTask(task, container, iCtx.$hostElement$));
|
|
10826
|
+
if (isPromise(result)) {
|
|
10827
|
+
iCtx.$waitOn$ = result;
|
|
10828
|
+
}
|
|
10829
|
+
};
|
|
10830
|
+
const runTask = (task, container, host) => {
|
|
10831
|
+
task.$flags$ &= -9 /* TaskFlags.DIRTY */;
|
|
10832
|
+
cleanupDestroyable(task);
|
|
10833
|
+
const iCtx = newInvokeContext(container.$locale$, host, TaskEvent);
|
|
10834
|
+
iCtx.$container$ = container;
|
|
10835
|
+
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
10836
|
+
const track = trackFn(task, container);
|
|
10837
|
+
const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
10838
|
+
const taskApi = { track, cleanup };
|
|
10839
|
+
return safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
10840
|
+
// If a Promise is thrown, that means we need to re-run the task.
|
|
10841
|
+
if (isPromise(err)) {
|
|
10842
|
+
return err.then(() => runTask(task, container, host));
|
|
10843
|
+
}
|
|
10844
|
+
else {
|
|
10845
|
+
container.handleError(err, host);
|
|
10846
|
+
}
|
|
10847
|
+
});
|
|
10848
|
+
};
|
|
10849
|
+
class Task extends BackRef {
|
|
10850
|
+
$flags$;
|
|
10851
|
+
$index$;
|
|
10852
|
+
$el$;
|
|
10853
|
+
$qrl$;
|
|
10854
|
+
$state$;
|
|
10855
|
+
$destroy$;
|
|
10856
|
+
constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
|
|
10857
|
+
super();
|
|
10858
|
+
this.$flags$ = $flags$;
|
|
10859
|
+
this.$index$ = $index$;
|
|
10860
|
+
this.$el$ = $el$;
|
|
10861
|
+
this.$qrl$ = $qrl$;
|
|
10862
|
+
this.$state$ = $state$;
|
|
10863
|
+
this.$destroy$ = $destroy$;
|
|
10864
|
+
}
|
|
10865
|
+
}
|
|
10866
|
+
/** @internal */
|
|
10867
|
+
const isTask = (value) => {
|
|
10868
|
+
return value instanceof Task;
|
|
10869
|
+
};
|
|
10870
|
+
/**
|
|
10871
|
+
* Used internally as a qrl event handler to schedule a task.
|
|
10872
|
+
*
|
|
10873
|
+
* @internal
|
|
10874
|
+
*/
|
|
10875
|
+
const scheduleTask = (_event, element) => {
|
|
10876
|
+
const [task] = useLexicalScope();
|
|
10877
|
+
const container = getDomContainer(element);
|
|
10878
|
+
task.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
10879
|
+
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
10880
|
+
};
|
|
10881
|
+
|
|
10444
10882
|
const throwIfQRLNotResolved = (qrl) => {
|
|
10445
10883
|
const resolved = qrl.resolved;
|
|
10446
10884
|
if (!resolved) {
|
|
@@ -10457,18 +10895,16 @@ const isSignal = (value) => {
|
|
|
10457
10895
|
return value instanceof SignalImpl;
|
|
10458
10896
|
};
|
|
10459
10897
|
const ensureContainsSubscription = (array, effectSubscription) => {
|
|
10460
|
-
|
|
10898
|
+
array.add(effectSubscription);
|
|
10461
10899
|
};
|
|
10462
10900
|
/** Ensure the item is in back refs set */
|
|
10463
10901
|
const ensureContainsBackRef = (array, value) => {
|
|
10464
|
-
array
|
|
10465
|
-
!array[2 /* EffectSubscriptionProp.BACK_REF */].has(value) &&
|
|
10466
|
-
array[2 /* EffectSubscriptionProp.BACK_REF */].add(value);
|
|
10902
|
+
(array.backRef ||= new Set()).add(value);
|
|
10467
10903
|
};
|
|
10468
10904
|
const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
10469
|
-
if (
|
|
10470
|
-
const effect = effectSubscriber
|
|
10471
|
-
const property = effectSubscriber
|
|
10905
|
+
if (container) {
|
|
10906
|
+
const effect = effectSubscriber.consumer;
|
|
10907
|
+
const property = effectSubscriber.property;
|
|
10472
10908
|
let qrl = null;
|
|
10473
10909
|
if (isTask(effect)) {
|
|
10474
10910
|
qrl = effect.$qrl$;
|
|
@@ -10485,24 +10921,15 @@ const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
|
10485
10921
|
}
|
|
10486
10922
|
};
|
|
10487
10923
|
const scheduleEffects = (container, signal, effects) => {
|
|
10488
|
-
const isBrowser = !isServerPlatform();
|
|
10924
|
+
const isBrowser = import.meta.env.TEST ? !isServerPlatform() : !isServer;
|
|
10489
10925
|
if (effects) {
|
|
10490
|
-
let tasksToTrigger = null;
|
|
10491
10926
|
const scheduleEffect = (effectSubscription) => {
|
|
10492
|
-
const consumer = effectSubscription
|
|
10493
|
-
const property = effectSubscription
|
|
10494
|
-
assertDefined(container, 'Container must be defined.');
|
|
10927
|
+
const consumer = effectSubscription.consumer;
|
|
10928
|
+
const property = effectSubscription.property;
|
|
10929
|
+
isDev && assertDefined(container, 'Container must be defined.');
|
|
10495
10930
|
if (isTask(consumer)) {
|
|
10496
10931
|
consumer.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
10497
|
-
|
|
10498
|
-
markVNodeDirty(container, consumer.$el$, 1 /* ChoreBits.TASKS */);
|
|
10499
|
-
}
|
|
10500
|
-
else {
|
|
10501
|
-
// for server we run tasks sync, so they can change currently running effects
|
|
10502
|
-
// in this case we could have infinite loop if we trigger tasks here
|
|
10503
|
-
// so instead we collect them and trigger them after the effects are scheduled
|
|
10504
|
-
(tasksToTrigger ||= []).push(consumer);
|
|
10505
|
-
}
|
|
10932
|
+
markVNodeDirty(container, consumer.$el$, 1 /* ChoreBits.TASKS */);
|
|
10506
10933
|
}
|
|
10507
10934
|
else if (consumer instanceof SignalImpl) {
|
|
10508
10935
|
consumer.invalidate();
|
|
@@ -10517,7 +10944,7 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
10517
10944
|
}
|
|
10518
10945
|
}
|
|
10519
10946
|
else {
|
|
10520
|
-
const effectData = effectSubscription
|
|
10947
|
+
const effectData = effectSubscription.data;
|
|
10521
10948
|
if (effectData instanceof SubscriptionData) {
|
|
10522
10949
|
const data = effectData.data;
|
|
10523
10950
|
const payload = {
|
|
@@ -10541,14 +10968,10 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
10541
10968
|
}
|
|
10542
10969
|
}
|
|
10543
10970
|
};
|
|
10544
|
-
|
|
10971
|
+
const effectsSnapshot = Array.from(effects);
|
|
10972
|
+
for (const effect of effectsSnapshot) {
|
|
10545
10973
|
scheduleEffect(effect);
|
|
10546
10974
|
}
|
|
10547
|
-
if (!isBrowser && container && tasksToTrigger) {
|
|
10548
|
-
for (const task of tasksToTrigger) {
|
|
10549
|
-
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
10550
|
-
}
|
|
10551
|
-
}
|
|
10552
10975
|
}
|
|
10553
10976
|
};
|
|
10554
10977
|
/** @internal */
|
|
@@ -10779,7 +11202,8 @@ class StoreHandler {
|
|
|
10779
11202
|
this.$container$ = ctx.$container$;
|
|
10780
11203
|
}
|
|
10781
11204
|
else {
|
|
10782
|
-
|
|
11205
|
+
isDev &&
|
|
11206
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === this.$container$, 'Do not use signals across containers');
|
|
10783
11207
|
}
|
|
10784
11208
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
10785
11209
|
if (effectSubscriber) {
|
|
@@ -10881,7 +11305,8 @@ function addStoreEffect(target, prop, store, effectSubscription) {
|
|
|
10881
11305
|
// to this signal.
|
|
10882
11306
|
ensureContainsBackRef(effectSubscription, target);
|
|
10883
11307
|
// TODO is this needed with the preloader?
|
|
10884
|
-
|
|
11308
|
+
(import.meta.env.TEST ? !isDomContainer(store.$container$) : isServer) &&
|
|
11309
|
+
addQrlToSerializationCtx(effectSubscription, store.$container$);
|
|
10885
11310
|
}
|
|
10886
11311
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
10887
11312
|
target[prop] = value;
|
|
@@ -11267,7 +11692,7 @@ function getObjectById(id, stateData) {
|
|
|
11267
11692
|
if (typeof id === 'string') {
|
|
11268
11693
|
id = parseInt(id, 10);
|
|
11269
11694
|
}
|
|
11270
|
-
assertTrue(id < stateData.length, `Invalid reference ${id} >= ${stateData.length}`);
|
|
11695
|
+
isDev && assertTrue(id < stateData.length, `Invalid reference ${id} >= ${stateData.length}`);
|
|
11271
11696
|
return stateData[id];
|
|
11272
11697
|
}
|
|
11273
11698
|
function _createDeserializeContainer(stateData, element) {
|
|
@@ -11526,7 +11951,7 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
|
|
|
11526
11951
|
}
|
|
11527
11952
|
if (chunk === '') {
|
|
11528
11953
|
// Sync QRL
|
|
11529
|
-
assertDefined(_containerEl, 'Sync QRL must have container element');
|
|
11954
|
+
isDev && assertDefined(_containerEl, 'Sync QRL must have container element');
|
|
11530
11955
|
const hash = _containerEl.getAttribute(QInstanceAttr);
|
|
11531
11956
|
const doc = _containerEl.ownerDocument;
|
|
11532
11957
|
const qFuncs = getQFuncs(doc, hash);
|
|
@@ -11768,8 +12193,8 @@ const _qrlSync = function (fn, serializedFn) {
|
|
|
11768
12193
|
const componentQrl = (componentQrl) => {
|
|
11769
12194
|
// Return a QComponent Factory function.
|
|
11770
12195
|
function QwikComponent(props, key, flags = 0) {
|
|
11771
|
-
assertQrl(componentQrl);
|
|
11772
|
-
assertNumber(flags, 'The Qwik Component was not invoked correctly');
|
|
12196
|
+
isDev && assertQrl(componentQrl);
|
|
12197
|
+
isDev && assertNumber(flags, 'The Qwik Component was not invoked correctly');
|
|
11773
12198
|
const hash = qTest ? 'sX' : componentQrl.$hash$.slice(0, 4);
|
|
11774
12199
|
const finalKey = hash + ':' + (key ? key : '');
|
|
11775
12200
|
const InnerCmp = () => { };
|
|
@@ -12713,15 +13138,20 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
12713
13138
|
return;
|
|
12714
13139
|
}
|
|
12715
13140
|
assertQrl(qrl);
|
|
12716
|
-
|
|
12717
|
-
set(task);
|
|
12718
|
-
useRegisterTaskEvents(task, eagerness);
|
|
13141
|
+
let flags;
|
|
12719
13142
|
if (!isServerPlatform()) {
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
13143
|
+
// In DOM we immediately execute
|
|
13144
|
+
flags = 1 /* TaskFlags.VISIBLE_TASK */ | 8 /* TaskFlags.DIRTY */;
|
|
13145
|
+
qrl.resolve();
|
|
12723
13146
|
markVNodeDirty(iCtx.$container$, iCtx.$hostElement$, 1 /* ChoreBits.TASKS */);
|
|
12724
13147
|
}
|
|
13148
|
+
else {
|
|
13149
|
+
// In SSR we defer execution until triggered in DOM
|
|
13150
|
+
flags = 1 /* TaskFlags.VISIBLE_TASK */;
|
|
13151
|
+
}
|
|
13152
|
+
const task = new Task(flags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
13153
|
+
set(task);
|
|
13154
|
+
useRegisterTaskEvents(task, eagerness);
|
|
12725
13155
|
};
|
|
12726
13156
|
const useRegisterTaskEvents = (task, eagerness) => {
|
|
12727
13157
|
if (eagerness === 'intersection-observer') {
|