@qwik.dev/core 2.0.0-beta.17 → 2.0.0-beta.19
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 +32 -32
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +1234 -788
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +815 -553
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.mjs +1007 -1000
- package/dist/qwikloader.debug.js +1 -1
- package/dist/qwikloader.js +1 -1
- package/dist/server.mjs +65 -106
- package/dist/starters/adapters/cloudflare-workers/README.md +52 -0
- package/dist/starters/adapters/cloudflare-workers/adapters/cloudflare-workers/vite.config.ts +15 -0
- package/dist/starters/adapters/cloudflare-workers/gitignore +3 -0
- package/dist/starters/adapters/cloudflare-workers/package.json +31 -0
- package/dist/starters/adapters/cloudflare-workers/public/.assetsignore +4 -0
- package/dist/starters/adapters/cloudflare-workers/public/_headers +11 -0
- package/dist/starters/adapters/cloudflare-workers/public/_redirects +1 -0
- package/dist/starters/adapters/cloudflare-workers/src/entry.cloudflare-pages.tsx +23 -0
- package/dist/starters/adapters/cloudflare-workers/worker-configuration.d.ts +5 -0
- package/dist/starters/adapters/cloudflare-workers/wrangler.jsonc +41 -0
- package/dist/starters/adapters/express/package.json +1 -1
- package/dist/starters/features/compiled-i18n/package.json +37 -0
- package/dist/starters/features/compiled-i18n/src/components/locale-selector/locale-selector.tsx +30 -0
- package/dist/starters/features/{localize → compiled-i18n}/src/entry.ssr.tsx +7 -2
- package/dist/starters/features/compiled-i18n/src/routes/plugin@compiled-i18n.ts +28 -0
- package/dist/starters/features/csr/package.json +1 -1
- package/dist/starters/features/cypress/src/actions/example.action.ts +5 -0
- package/dist/starters/features/cypress/src/components/example/example.cy.tsx +50 -8
- package/dist/starters/features/cypress/src/components/example/example.tsx +13 -3
- package/dist/starters/features/cypress/src/loaders/example.loader.ts +5 -0
- package/dist/starters/features/playwright/playwright-report/index.html +0 -19
- package/dist/testing/index.d.ts +11 -11
- package/dist/testing/index.mjs +2966 -2498
- 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/starters/features/localize/package.json +0 -37
- package/dist/starters/features/localize/src/locales/message.en.json +0 -8
- package/dist/starters/features/localize/src/locales/message.it.json +0 -8
- package/dist/starters/features/localize/src/routes/[locale]/i18n-utils.ts +0 -94
- package/dist/starters/features/localize/src/routes/[locale]/index.tsx +0 -52
- package/dist/starters/features/localize/src/routes/[locale]/layout.tsx +0 -12
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.19-dev+0d046fb
|
|
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.19-dev+0d046fb";
|
|
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)
|
|
@@ -476,79 +468,6 @@ function assertNumber(value1, text, ...parts) {
|
|
|
476
468
|
}
|
|
477
469
|
}
|
|
478
470
|
|
|
479
|
-
let _locale = undefined;
|
|
480
|
-
let localAsyncStore;
|
|
481
|
-
if (isServer) {
|
|
482
|
-
import('node:async_hooks')
|
|
483
|
-
.then((module) => {
|
|
484
|
-
localAsyncStore = new module.AsyncLocalStorage();
|
|
485
|
-
})
|
|
486
|
-
.catch(() => {
|
|
487
|
-
// ignore if AsyncLocalStorage is not available
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Retrieve the current locale.
|
|
492
|
-
*
|
|
493
|
-
* If no current locale and there is no `defaultLocale` the function throws an error.
|
|
494
|
-
*
|
|
495
|
-
* @returns The locale.
|
|
496
|
-
* @public
|
|
497
|
-
*/
|
|
498
|
-
function getLocale(defaultLocale) {
|
|
499
|
-
// Prefer per-request locale from local AsyncLocalStorage if available (server-side)
|
|
500
|
-
if (localAsyncStore) {
|
|
501
|
-
const locale = localAsyncStore.getStore();
|
|
502
|
-
if (locale) {
|
|
503
|
-
return locale;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
if (_locale === undefined) {
|
|
507
|
-
const ctx = tryGetInvokeContext();
|
|
508
|
-
if (ctx && ctx.$locale$) {
|
|
509
|
-
return ctx.$locale$;
|
|
510
|
-
}
|
|
511
|
-
if (defaultLocale !== undefined) {
|
|
512
|
-
return defaultLocale;
|
|
513
|
-
}
|
|
514
|
-
throw new Error('Reading `locale` outside of context.');
|
|
515
|
-
}
|
|
516
|
-
return _locale;
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Override the `getLocale` with `lang` within the `fn` execution.
|
|
520
|
-
*
|
|
521
|
-
* @public
|
|
522
|
-
*/
|
|
523
|
-
function withLocale(locale, fn) {
|
|
524
|
-
if (localAsyncStore) {
|
|
525
|
-
return localAsyncStore.run(locale, fn);
|
|
526
|
-
}
|
|
527
|
-
const previousLang = _locale;
|
|
528
|
-
try {
|
|
529
|
-
_locale = locale;
|
|
530
|
-
return fn();
|
|
531
|
-
}
|
|
532
|
-
finally {
|
|
533
|
-
_locale = previousLang;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
* Globally set a lang.
|
|
538
|
-
*
|
|
539
|
-
* This can be used only in browser. Server execution requires that each request could potentially
|
|
540
|
-
* be a different lang, therefore setting a global lang would produce incorrect responses.
|
|
541
|
-
*
|
|
542
|
-
* @public
|
|
543
|
-
*/
|
|
544
|
-
function setLocale(locale) {
|
|
545
|
-
if (localAsyncStore) {
|
|
546
|
-
localAsyncStore.enterWith(locale);
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
_locale = locale;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
471
|
/**
|
|
553
472
|
* A friendly name tag for a VirtualVNode.
|
|
554
473
|
*
|
|
@@ -781,16 +700,11 @@ function vnode_cloneElementWithNamespace(elementVNode, parentVNode, namespace, n
|
|
|
781
700
|
}
|
|
782
701
|
return rootElement;
|
|
783
702
|
}
|
|
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
|
-
}
|
|
703
|
+
// reuse the same object to avoid creating new objects on every call
|
|
704
|
+
const NEW_NAMESPACE_DATA = {
|
|
705
|
+
elementNamespace: HTML_NS,
|
|
706
|
+
elementNamespaceFlag: 0 /* VNodeFlags.NS_html */,
|
|
707
|
+
};
|
|
794
708
|
function getNewElementNamespaceData(domParentVNode, tagOrVNode) {
|
|
795
709
|
const parentIsDefaultNamespace = domParentVNode
|
|
796
710
|
? !!vnode_getElementName(domParentVNode) && vnode_isDefaultNamespace(domParentVNode)
|
|
@@ -815,10 +729,28 @@ function getNewElementNamespaceData(domParentVNode, tagOrVNode) {
|
|
|
815
729
|
elementNamespace = isParentSvg ? SVG_NS : isParentMath ? MATH_NS : HTML_NS;
|
|
816
730
|
elementNamespaceFlag = domParentVNode.flags & 384 /* VNodeFlags.NAMESPACE_MASK */;
|
|
817
731
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
732
|
+
NEW_NAMESPACE_DATA.elementNamespace = elementNamespace;
|
|
733
|
+
NEW_NAMESPACE_DATA.elementNamespaceFlag = elementNamespaceFlag;
|
|
734
|
+
return NEW_NAMESPACE_DATA;
|
|
735
|
+
}
|
|
736
|
+
function isSvg(tagOrVNode) {
|
|
737
|
+
if (typeof tagOrVNode === 'string') {
|
|
738
|
+
return isSvgElement(tagOrVNode);
|
|
739
|
+
}
|
|
740
|
+
if (vnode_isElementVNode(tagOrVNode)) {
|
|
741
|
+
return (isSvgElement(vnode_getElementName(tagOrVNode)) || (tagOrVNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0);
|
|
742
|
+
}
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
function isMath(tagOrVNode) {
|
|
746
|
+
if (typeof tagOrVNode === 'string') {
|
|
747
|
+
return isMathElement(tagOrVNode);
|
|
748
|
+
}
|
|
749
|
+
if (vnode_isElementVNode(tagOrVNode)) {
|
|
750
|
+
return (isMathElement(vnode_getElementName(tagOrVNode)) ||
|
|
751
|
+
(tagOrVNode.flags & 256 /* VNodeFlags.NS_math */) !== 0);
|
|
752
|
+
}
|
|
753
|
+
return false;
|
|
822
754
|
}
|
|
823
755
|
function getAttributeNamespace(attributeName) {
|
|
824
756
|
switch (attributeName) {
|
|
@@ -854,18 +786,18 @@ class BackRef {
|
|
|
854
786
|
}
|
|
855
787
|
|
|
856
788
|
/** @internal */
|
|
857
|
-
class VNode
|
|
789
|
+
class VNode {
|
|
858
790
|
flags;
|
|
859
791
|
parent;
|
|
860
792
|
previousSibling;
|
|
861
793
|
nextSibling;
|
|
862
794
|
props;
|
|
795
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
863
796
|
slotParent = null;
|
|
864
797
|
dirty = 0 /* ChoreBits.NONE */;
|
|
865
798
|
dirtyChildren = null;
|
|
866
799
|
nextDirtyChildIndex = 0;
|
|
867
800
|
constructor(flags, parent, previousSibling, nextSibling, props) {
|
|
868
|
-
super();
|
|
869
801
|
this.flags = flags;
|
|
870
802
|
this.parent = parent;
|
|
871
803
|
this.previousSibling = previousSibling;
|
|
@@ -877,22 +809,29 @@ class VNode extends BackRef {
|
|
|
877
809
|
if (isDev) {
|
|
878
810
|
return vnode_toString.call(this);
|
|
879
811
|
}
|
|
880
|
-
return
|
|
812
|
+
return Object.prototype.toString.call(this);
|
|
881
813
|
}
|
|
882
814
|
}
|
|
883
815
|
|
|
884
816
|
/** @internal */
|
|
885
|
-
class
|
|
817
|
+
class VirtualVNode extends VNode {
|
|
886
818
|
key;
|
|
887
819
|
firstChild;
|
|
888
820
|
lastChild;
|
|
889
|
-
|
|
890
|
-
elementName;
|
|
891
|
-
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild, node, elementName) {
|
|
821
|
+
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild) {
|
|
892
822
|
super(flags, parent, previousSibling, nextSibling, props);
|
|
893
823
|
this.key = key;
|
|
894
824
|
this.firstChild = firstChild;
|
|
895
825
|
this.lastChild = lastChild;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/** @internal */
|
|
830
|
+
class ElementVNode extends VirtualVNode {
|
|
831
|
+
node;
|
|
832
|
+
elementName;
|
|
833
|
+
constructor(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild, node, elementName) {
|
|
834
|
+
super(key, flags, parent, previousSibling, nextSibling, props, firstChild, lastChild);
|
|
896
835
|
this.node = node;
|
|
897
836
|
this.elementName = elementName;
|
|
898
837
|
}
|
|
@@ -911,19 +850,6 @@ class TextVNode extends VNode {
|
|
|
911
850
|
}
|
|
912
851
|
}
|
|
913
852
|
|
|
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
853
|
/**
|
|
928
854
|
* @file Cursor queue management for cursor-based scheduling.
|
|
929
855
|
*
|
|
@@ -977,6 +903,7 @@ function getHighestPriorityCursor() {
|
|
|
977
903
|
function pauseCursor(cursor, container) {
|
|
978
904
|
pausedCursorQueue.push(cursor);
|
|
979
905
|
removeCursorFromQueue(cursor, container, true);
|
|
906
|
+
container.$pausedCursorCount$++;
|
|
980
907
|
}
|
|
981
908
|
function resumeCursor(cursor, container) {
|
|
982
909
|
const index = pausedCursorQueue.indexOf(cursor);
|
|
@@ -986,6 +913,7 @@ function resumeCursor(cursor, container) {
|
|
|
986
913
|
pausedCursorQueue[index] = pausedCursorQueue[lastIndex];
|
|
987
914
|
}
|
|
988
915
|
pausedCursorQueue.pop();
|
|
916
|
+
container.$pausedCursorCount$--;
|
|
989
917
|
}
|
|
990
918
|
addCursorToQueue(container, cursor);
|
|
991
919
|
}
|
|
@@ -995,9 +923,6 @@ function resumeCursor(cursor, container) {
|
|
|
995
923
|
* @param cursor - The cursor to remove
|
|
996
924
|
*/
|
|
997
925
|
function removeCursorFromQueue(cursor, container, keepCursorFlag) {
|
|
998
|
-
if (container.$cursorCount$ > 0) {
|
|
999
|
-
container.$cursorCount$--;
|
|
1000
|
-
}
|
|
1001
926
|
if (!keepCursorFlag) {
|
|
1002
927
|
cursor.flags &= -65 /* VNodeFlags.Cursor */;
|
|
1003
928
|
}
|
|
@@ -1011,6 +936,7 @@ function removeCursorFromQueue(cursor, container, keepCursorFlag) {
|
|
|
1011
936
|
// }
|
|
1012
937
|
// globalCursorQueue.pop();
|
|
1013
938
|
globalCursorQueue.splice(index, 1);
|
|
939
|
+
container.$cursorCount$--;
|
|
1014
940
|
}
|
|
1015
941
|
}
|
|
1016
942
|
|
|
@@ -1117,7 +1043,35 @@ class SignalImpl {
|
|
|
1117
1043
|
this.$untrackedValue$ = value;
|
|
1118
1044
|
}
|
|
1119
1045
|
get value() {
|
|
1120
|
-
|
|
1046
|
+
const ctx = tryGetInvokeContext();
|
|
1047
|
+
if (!ctx) {
|
|
1048
|
+
return this.untrackedValue;
|
|
1049
|
+
}
|
|
1050
|
+
if (this.$container$ === null) {
|
|
1051
|
+
if (!ctx.$container$) {
|
|
1052
|
+
return this.untrackedValue;
|
|
1053
|
+
}
|
|
1054
|
+
// Grab the container now we have access to it
|
|
1055
|
+
this.$container$ = ctx.$container$;
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
isDev &&
|
|
1059
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === this.$container$, 'Do not use signals across containers');
|
|
1060
|
+
}
|
|
1061
|
+
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1062
|
+
if (effectSubscriber) {
|
|
1063
|
+
// Let's make sure that we have a reference to this effect.
|
|
1064
|
+
// Adding reference is essentially adding a subscription, so if the signal
|
|
1065
|
+
// changes we know who to notify.
|
|
1066
|
+
ensureContainsSubscription((this.$effects$ ||= new Set()), effectSubscriber);
|
|
1067
|
+
// But when effect is scheduled in needs to be able to know which signals
|
|
1068
|
+
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1069
|
+
// to this signal.
|
|
1070
|
+
ensureContainsBackRef(effectSubscriber, this);
|
|
1071
|
+
(import.meta.env.TEST ? !isDomContainer(this.$container$) : isServer) &&
|
|
1072
|
+
addQrlToSerializationCtx(effectSubscriber, this.$container$);
|
|
1073
|
+
}
|
|
1074
|
+
return this.untrackedValue;
|
|
1121
1075
|
}
|
|
1122
1076
|
set value(value) {
|
|
1123
1077
|
if (value !== this.$untrackedValue$) {
|
|
@@ -1135,7 +1089,7 @@ class SignalImpl {
|
|
|
1135
1089
|
if (isDev) {
|
|
1136
1090
|
return (`[${this.constructor.name}${this.$flags$ & 1 /* SignalFlags.INVALID */ ? ' INVALID' : ''} ${String(this.$untrackedValue$)}]` +
|
|
1137
1091
|
(Array.from(this.$effects$ || [])
|
|
1138
|
-
.map((e) => '\n -> ' + pad(qwikDebugToString(e
|
|
1092
|
+
.map((e) => '\n -> ' + pad(qwikDebugToString(e.consumer), ' '))
|
|
1139
1093
|
.join('\n') || ''));
|
|
1140
1094
|
}
|
|
1141
1095
|
else {
|
|
@@ -1146,34 +1100,33 @@ class SignalImpl {
|
|
|
1146
1100
|
return { value: this.$untrackedValue$ };
|
|
1147
1101
|
}
|
|
1148
1102
|
}
|
|
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
1103
|
const setupSignalValueAccess = (target, effectsFn, returnValueFn) => {
|
|
1161
1104
|
const ctx = tryGetInvokeContext();
|
|
1162
|
-
if (ctx) {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
target.$container$ = ctx.$container$;
|
|
1105
|
+
if (!ctx) {
|
|
1106
|
+
return returnValueFn();
|
|
1107
|
+
}
|
|
1108
|
+
if (target.$container$ === null) {
|
|
1109
|
+
if (!ctx.$container$) {
|
|
1110
|
+
return returnValueFn();
|
|
1169
1111
|
}
|
|
1170
|
-
|
|
1112
|
+
// Grab the container now we have access to it
|
|
1113
|
+
target.$container$ = ctx.$container$;
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
isDev &&
|
|
1171
1117
|
assertTrue(!ctx.$container$ || ctx.$container$ === target.$container$, 'Do not use signals across containers');
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1118
|
+
}
|
|
1119
|
+
const effectSubscriber = ctx.$effectSubscriber$;
|
|
1120
|
+
if (effectSubscriber) {
|
|
1121
|
+
// Let's make sure that we have a reference to this effect.
|
|
1122
|
+
// Adding reference is essentially adding a subscription, so if the signal
|
|
1123
|
+
// changes we know who to notify.
|
|
1124
|
+
ensureContainsSubscription(effectsFn(), effectSubscriber);
|
|
1125
|
+
// But when effect is scheduled in needs to be able to know which signals
|
|
1126
|
+
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1127
|
+
// to this signal.
|
|
1128
|
+
ensureContainsBackRef(effectSubscriber, target);
|
|
1129
|
+
addQrlToSerializationCtx(effectSubscriber, target.$container$);
|
|
1177
1130
|
}
|
|
1178
1131
|
return returnValueFn();
|
|
1179
1132
|
};
|
|
@@ -1203,9 +1156,13 @@ const _UNINITIALIZED = Symbol('UNINITIALIZED');
|
|
|
1203
1156
|
*/
|
|
1204
1157
|
const EVENT_SUFFIX = '$';
|
|
1205
1158
|
const isHtmlAttributeAnEventName = (name) => {
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1159
|
+
if (name.charCodeAt(0) !== 111 /* o */ || name.charCodeAt(1) !== 110 /* n */) {
|
|
1160
|
+
return false;
|
|
1161
|
+
}
|
|
1162
|
+
if (name.charCodeAt(2) === 58 /* : */) {
|
|
1163
|
+
return true; // on:
|
|
1164
|
+
}
|
|
1165
|
+
return name.startsWith("on-window:" /* EventNameHtmlScope.window */) || name.startsWith("on-document:" /* EventNameHtmlScope.document */);
|
|
1209
1166
|
};
|
|
1210
1167
|
function jsxEventToHtmlAttribute(jsxEvent) {
|
|
1211
1168
|
if (jsxEvent.endsWith(EVENT_SUFFIX)) {
|
|
@@ -1431,7 +1388,8 @@ const addPropsProxyEffect = (propsProxy, prop) => {
|
|
|
1431
1388
|
}
|
|
1432
1389
|
}
|
|
1433
1390
|
else {
|
|
1434
|
-
|
|
1391
|
+
isDev &&
|
|
1392
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
1435
1393
|
}
|
|
1436
1394
|
}
|
|
1437
1395
|
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
@@ -1444,6 +1402,7 @@ const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
|
1444
1402
|
if (effects) {
|
|
1445
1403
|
scheduleEffects(propsProxy.$container$, propsProxy, effects);
|
|
1446
1404
|
}
|
|
1405
|
+
return !!effects;
|
|
1447
1406
|
};
|
|
1448
1407
|
function getEffects$1(effects, prop) {
|
|
1449
1408
|
// TODO: Handle STORE_ALL_PROPS
|
|
@@ -1493,30 +1452,6 @@ const cleanupDestroyable = (destroyable) => {
|
|
|
1493
1452
|
}
|
|
1494
1453
|
};
|
|
1495
1454
|
|
|
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
1455
|
/**
|
|
1521
1456
|
* # ================================
|
|
1522
1457
|
*
|
|
@@ -1529,6 +1464,54 @@ function isSsrNode(value) {
|
|
|
1529
1464
|
* "marked as dirty" flag.
|
|
1530
1465
|
*/
|
|
1531
1466
|
const NEEDS_COMPUTATION = Symbol('invalid');
|
|
1467
|
+
/**
|
|
1468
|
+
* An effect consumer plus type of effect, back references to producers and additional data
|
|
1469
|
+
*
|
|
1470
|
+
* An effect can be trigger by one or more of signal inputs. The first step of re-running an effect
|
|
1471
|
+
* is to clear its subscriptions so that the effect can re add new set of subscriptions. In order to
|
|
1472
|
+
* clear the subscriptions we need to store them here.
|
|
1473
|
+
*
|
|
1474
|
+
* Imagine you have effect such as:
|
|
1475
|
+
*
|
|
1476
|
+
* ```
|
|
1477
|
+
* function effect1() {
|
|
1478
|
+
* console.log(signalA.value ? signalB.value : 'default');
|
|
1479
|
+
* }
|
|
1480
|
+
* ```
|
|
1481
|
+
*
|
|
1482
|
+
* In the above case the `signalB` needs to be unsubscribed when `signalA` is falsy. We do this by
|
|
1483
|
+
* always clearing all of the subscriptions
|
|
1484
|
+
*
|
|
1485
|
+
* The `EffectSubscription` stores
|
|
1486
|
+
*
|
|
1487
|
+
* ```
|
|
1488
|
+
* subscription1 = [effectConsumer1, EffectProperty.COMPONENT, Set[(signalA, signalB)]];
|
|
1489
|
+
* ```
|
|
1490
|
+
*
|
|
1491
|
+
* The `signal1` and `signal2` back references are needed to "clear" existing subscriptions.
|
|
1492
|
+
*
|
|
1493
|
+
* Both `signalA` as well as `signalB` will have a reference to `subscription` to the so that the
|
|
1494
|
+
* effect can be scheduled if either `signalA` or `signalB` triggers. The `subscription1` is shared
|
|
1495
|
+
* between the signals.
|
|
1496
|
+
*
|
|
1497
|
+
* The second position `EffectProperty|string` store the property name of the effect.
|
|
1498
|
+
*
|
|
1499
|
+
* - Property name of the VNode
|
|
1500
|
+
* - `EffectProperty.COMPONENT` if component
|
|
1501
|
+
* - `EffectProperty.VNODE` if VNode
|
|
1502
|
+
*/
|
|
1503
|
+
class EffectSubscription {
|
|
1504
|
+
consumer;
|
|
1505
|
+
property;
|
|
1506
|
+
backRef;
|
|
1507
|
+
data;
|
|
1508
|
+
constructor(consumer, property, backRef = null, data = null) {
|
|
1509
|
+
this.consumer = consumer;
|
|
1510
|
+
this.property = property;
|
|
1511
|
+
this.backRef = backRef;
|
|
1512
|
+
this.data = data;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1532
1515
|
/**
|
|
1533
1516
|
* # ================================
|
|
1534
1517
|
*
|
|
@@ -1540,6 +1523,30 @@ const STORE_TARGET = Symbol('store.target');
|
|
|
1540
1523
|
const STORE_HANDLER = Symbol('store.handler');
|
|
1541
1524
|
const STORE_ALL_PROPS = Symbol('store.all');
|
|
1542
1525
|
|
|
1526
|
+
function getSubscriber(effect, prop, data) {
|
|
1527
|
+
if (!effect[_EFFECT_BACK_REF]) {
|
|
1528
|
+
if (isServer && isSsrNode(effect)) {
|
|
1529
|
+
effect.setProp(QBackRefs, new Map());
|
|
1530
|
+
}
|
|
1531
|
+
else {
|
|
1532
|
+
effect[_EFFECT_BACK_REF] = new Map();
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
const subMap = effect[_EFFECT_BACK_REF];
|
|
1536
|
+
let sub = subMap.get(prop);
|
|
1537
|
+
if (!sub) {
|
|
1538
|
+
sub = new EffectSubscription(effect, prop);
|
|
1539
|
+
subMap.set(prop, sub);
|
|
1540
|
+
}
|
|
1541
|
+
if (data) {
|
|
1542
|
+
sub.data = data;
|
|
1543
|
+
}
|
|
1544
|
+
return sub;
|
|
1545
|
+
}
|
|
1546
|
+
function isSsrNode(value) {
|
|
1547
|
+
return '__brand__' in value && value.__brand__ === 'SsrNode';
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1543
1550
|
const trackFn = (target, container) => (obj, prop) => {
|
|
1544
1551
|
const ctx = newInvokeContext();
|
|
1545
1552
|
ctx.$effectSubscriber$ = getSubscriber(target, ":" /* EffectProperty.COMPONENT */);
|
|
@@ -1639,7 +1646,7 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1639
1646
|
}
|
|
1640
1647
|
get untrackedValue() {
|
|
1641
1648
|
this.$computeIfNeeded$();
|
|
1642
|
-
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1649
|
+
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1643
1650
|
return this.$untrackedValue$;
|
|
1644
1651
|
}
|
|
1645
1652
|
$computeIfNeeded$() {
|
|
@@ -1650,7 +1657,11 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1650
1657
|
throwIfQRLNotResolved(computeQrl);
|
|
1651
1658
|
const ctx = tryGetInvokeContext();
|
|
1652
1659
|
const previousEffectSubscription = ctx?.$effectSubscriber$;
|
|
1653
|
-
|
|
1660
|
+
if (ctx) {
|
|
1661
|
+
const effectSubscriber = getSubscriber(this, "." /* EffectProperty.VNODE */);
|
|
1662
|
+
clearEffectSubscription(this.$container$, effectSubscriber);
|
|
1663
|
+
ctx.$effectSubscriber$ = effectSubscriber;
|
|
1664
|
+
}
|
|
1654
1665
|
try {
|
|
1655
1666
|
const untrackedValue = computeQrl.getFn(ctx)();
|
|
1656
1667
|
if (isPromise(untrackedValue)) {
|
|
@@ -1993,7 +2004,7 @@ const _wrapProp = (...args) => {
|
|
|
1993
2004
|
}
|
|
1994
2005
|
if (isSignal(obj)) {
|
|
1995
2006
|
if (!(obj instanceof AsyncComputedSignalImpl)) {
|
|
1996
|
-
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
2007
|
+
isDev && assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
1997
2008
|
}
|
|
1998
2009
|
if (obj instanceof WrappedSignalImpl && obj.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
1999
2010
|
return obj;
|
|
@@ -2003,11 +2014,11 @@ const _wrapProp = (...args) => {
|
|
|
2003
2014
|
if (isPropsProxy(obj)) {
|
|
2004
2015
|
const constProps = obj[_CONST_PROPS];
|
|
2005
2016
|
const varProps = obj[_VAR_PROPS];
|
|
2006
|
-
if (constProps && prop
|
|
2017
|
+
if (constProps && Object.prototype.hasOwnProperty.call(constProps, prop)) {
|
|
2007
2018
|
// Const props don't need wrapping
|
|
2008
2019
|
return constProps[prop];
|
|
2009
2020
|
}
|
|
2010
|
-
else if (prop
|
|
2021
|
+
else if (Object.prototype.hasOwnProperty.call(varProps, prop)) {
|
|
2011
2022
|
const value = varProps[prop];
|
|
2012
2023
|
return wrapIfNotSignal(value, args);
|
|
2013
2024
|
}
|
|
@@ -2086,7 +2097,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
2086
2097
|
}
|
|
2087
2098
|
get untrackedValue() {
|
|
2088
2099
|
this.$computeIfNeeded$();
|
|
2089
|
-
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2100
|
+
isDev && assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
2090
2101
|
return this.$untrackedValue$;
|
|
2091
2102
|
}
|
|
2092
2103
|
$computeIfNeeded$() {
|
|
@@ -2137,17 +2148,18 @@ function clearAllEffects(container, consumer) {
|
|
|
2137
2148
|
effects.clear();
|
|
2138
2149
|
}
|
|
2139
2150
|
function clearEffectSubscription(container, effect) {
|
|
2140
|
-
const backRefs = effect
|
|
2151
|
+
const backRefs = effect.backRef;
|
|
2141
2152
|
if (!backRefs) {
|
|
2142
2153
|
return;
|
|
2143
2154
|
}
|
|
2144
2155
|
for (const producer of backRefs) {
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
}
|
|
2148
|
-
else if (producer instanceof AsyncComputedSignalImpl) {
|
|
2156
|
+
// Check AsyncComputedSignalImpl before SignalImpl since it extends SignalImpl
|
|
2157
|
+
if (producer instanceof AsyncComputedSignalImpl) {
|
|
2149
2158
|
clearAsyncComputedSignal(producer, effect);
|
|
2150
2159
|
}
|
|
2160
|
+
else if (producer instanceof SignalImpl) {
|
|
2161
|
+
clearSignal(container, producer, effect);
|
|
2162
|
+
}
|
|
2151
2163
|
else if (isPropsProxy(producer)) {
|
|
2152
2164
|
const propsHandler = producer[_PROPS_HANDLER];
|
|
2153
2165
|
clearStoreOrProps(propsHandler, effect);
|
|
@@ -2165,7 +2177,8 @@ function clearSignal(container, producer, effect) {
|
|
|
2165
2177
|
if (effects && effects.has(effect)) {
|
|
2166
2178
|
effects.delete(effect);
|
|
2167
2179
|
}
|
|
2168
|
-
if (producer instanceof WrappedSignalImpl) {
|
|
2180
|
+
if (producer instanceof WrappedSignalImpl && !effects?.size) {
|
|
2181
|
+
// Only clear if there are no more subscribers
|
|
2169
2182
|
producer.$hostElement$ = undefined;
|
|
2170
2183
|
clearAllEffects(container, producer);
|
|
2171
2184
|
}
|
|
@@ -2221,15 +2234,17 @@ const useLexicalScope = () => {
|
|
|
2221
2234
|
let qrl = context.$qrl$;
|
|
2222
2235
|
if (!qrl) {
|
|
2223
2236
|
const el = context.$hostElement$ instanceof ElementVNode ? context.$hostElement$.node : undefined;
|
|
2224
|
-
assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
2237
|
+
isDev && assertDefined(el, 'invoke: element must be defined inside useLexicalScope()', context);
|
|
2225
2238
|
const containerElement = _getQContainerElement(el);
|
|
2226
|
-
assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
2239
|
+
isDev && assertDefined(containerElement, `invoke: cant find parent q:container of`, el);
|
|
2227
2240
|
const container = getDomContainer(containerElement);
|
|
2241
|
+
context.$container$ ||= container;
|
|
2228
2242
|
qrl = container.parseQRL(decodeURIComponent(String(context.$url$)));
|
|
2229
2243
|
}
|
|
2230
2244
|
else {
|
|
2231
|
-
assertQrl(qrl);
|
|
2232
|
-
|
|
2245
|
+
isDev && assertQrl(qrl);
|
|
2246
|
+
isDev &&
|
|
2247
|
+
assertDefined(qrl.$captureRef$, 'invoke: qrl $captureRef$ must be defined inside useLexicalScope()', qrl);
|
|
2233
2248
|
}
|
|
2234
2249
|
return qrl.$captureRef$;
|
|
2235
2250
|
};
|
|
@@ -2253,85 +2268,30 @@ const _chk = (_, element) => {
|
|
|
2253
2268
|
signal.value = element.checked;
|
|
2254
2269
|
};
|
|
2255
2270
|
|
|
2256
|
-
const _hasOwnProperty$
|
|
2257
|
-
const BIND_VALUE = 'bind:value';
|
|
2258
|
-
const BIND_CHECKED = 'bind:checked';
|
|
2271
|
+
const _hasOwnProperty$2 = Object.prototype.hasOwnProperty;
|
|
2259
2272
|
// TODO store props as the arrays the vnodes also use?
|
|
2260
2273
|
class JSXNodeImpl {
|
|
2261
2274
|
type;
|
|
2275
|
+
children;
|
|
2262
2276
|
toSort;
|
|
2263
2277
|
key;
|
|
2264
2278
|
varProps;
|
|
2265
2279
|
constProps;
|
|
2266
|
-
children;
|
|
2267
2280
|
dev;
|
|
2268
2281
|
_proxy = null;
|
|
2269
2282
|
constructor(type, varProps, constProps, children, key, toSort, dev) {
|
|
2270
2283
|
this.type = type;
|
|
2284
|
+
this.children = children;
|
|
2271
2285
|
this.toSort = !!toSort;
|
|
2272
|
-
this.key = key
|
|
2286
|
+
this.key = key === null || key === undefined ? null : typeof key === 'string' ? key : '' + key;
|
|
2273
2287
|
this.varProps = !varProps || isEmpty(varProps) ? EMPTY_OBJ : varProps;
|
|
2274
2288
|
this.constProps = !constProps || isEmpty(constProps) ? null : constProps;
|
|
2275
|
-
this.children = children;
|
|
2276
2289
|
if (qDev && dev) {
|
|
2277
2290
|
this.dev = {
|
|
2278
2291
|
...dev,
|
|
2279
2292
|
stack: new Error().stack?.split('\n').slice(2).join('\n'),
|
|
2280
2293
|
};
|
|
2281
2294
|
}
|
|
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
2295
|
seal(this);
|
|
2336
2296
|
}
|
|
2337
2297
|
get props() {
|
|
@@ -2362,9 +2322,9 @@ const isJSXNode = (n) => {
|
|
|
2362
2322
|
return true;
|
|
2363
2323
|
}
|
|
2364
2324
|
if (isObject(n) &&
|
|
2365
|
-
_hasOwnProperty$
|
|
2366
|
-
_hasOwnProperty$
|
|
2367
|
-
_hasOwnProperty$
|
|
2325
|
+
_hasOwnProperty$2.call(n, 'key') &&
|
|
2326
|
+
_hasOwnProperty$2.call(n, 'props') &&
|
|
2327
|
+
_hasOwnProperty$2.call(n, 'type')) {
|
|
2368
2328
|
logWarn(`Duplicate implementations of "JSXNode" found`);
|
|
2369
2329
|
return true;
|
|
2370
2330
|
}
|
|
@@ -2375,29 +2335,12 @@ const isJSXNode = (n) => {
|
|
|
2375
2335
|
}
|
|
2376
2336
|
};
|
|
2377
2337
|
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
|
-
}
|
|
2338
|
+
return Object.keys(obj).length === 0;
|
|
2399
2339
|
};
|
|
2400
2340
|
|
|
2341
|
+
const BIND_VALUE = 'bind:value';
|
|
2342
|
+
const BIND_CHECKED = 'bind:checked';
|
|
2343
|
+
const _hasOwnProperty$1 = Object.prototype.hasOwnProperty;
|
|
2401
2344
|
/**
|
|
2402
2345
|
* Create a JSXNode with the properties fully split into variable and constant parts, and children
|
|
2403
2346
|
* separated out. Furthermore, the varProps must be a sorted object, that is, the keys must be
|
|
@@ -2415,7 +2358,7 @@ const handleBindProp = (props, prop) => {
|
|
|
2415
2358
|
* @internal
|
|
2416
2359
|
*/
|
|
2417
2360
|
const _jsxSorted = (type, varProps, constProps, children, flags, key, dev) => {
|
|
2418
|
-
return
|
|
2361
|
+
return new JSXNodeImpl(type, varProps, constProps, children, key, false, dev);
|
|
2419
2362
|
};
|
|
2420
2363
|
/**
|
|
2421
2364
|
* Create a JSXNode, with the properties split into variable and constant parts, but the variable
|
|
@@ -2434,24 +2377,158 @@ const _jsxSorted = (type, varProps, constProps, children, flags, key, dev) => {
|
|
|
2434
2377
|
* @internal
|
|
2435
2378
|
*/
|
|
2436
2379
|
const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
|
|
2437
|
-
|
|
2380
|
+
let toSort = false;
|
|
2381
|
+
let constPropsCopied = false;
|
|
2382
|
+
let varPropsCopied = false;
|
|
2383
|
+
let bindValueSignal = null;
|
|
2384
|
+
let bindCheckedSignal = null;
|
|
2385
|
+
// Apply transformations for native HTML elements only
|
|
2386
|
+
if (typeof type === 'string') {
|
|
2387
|
+
// Transform event names (onClick$ -> on:click)
|
|
2388
|
+
if (constProps) {
|
|
2389
|
+
const processedKeys = new Set();
|
|
2390
|
+
for (const k in constProps) {
|
|
2391
|
+
const attr = jsxEventToHtmlAttribute(k);
|
|
2392
|
+
if (attr) {
|
|
2393
|
+
if (!constPropsCopied) {
|
|
2394
|
+
constProps = { ...constProps };
|
|
2395
|
+
constPropsCopied = true;
|
|
2396
|
+
}
|
|
2397
|
+
if (!_hasOwnProperty$1.call(constProps, attr) || processedKeys.has(attr)) {
|
|
2398
|
+
constProps[attr] = constProps[k];
|
|
2399
|
+
}
|
|
2400
|
+
delete constProps[k];
|
|
2401
|
+
}
|
|
2402
|
+
processedKeys.add(k);
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2438
2405
|
if (varProps) {
|
|
2406
|
+
const processedKeys = new Set();
|
|
2439
2407
|
for (const k in varProps) {
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2408
|
+
const attr = jsxEventToHtmlAttribute(k);
|
|
2409
|
+
if (attr) {
|
|
2410
|
+
if (!varPropsCopied) {
|
|
2411
|
+
varProps = { ...varProps };
|
|
2412
|
+
varPropsCopied = true;
|
|
2413
|
+
}
|
|
2414
|
+
// Transform event name in place
|
|
2415
|
+
if (!_hasOwnProperty$1.call(varProps, attr) || processedKeys.has(attr)) {
|
|
2416
|
+
varProps[attr] = varProps[k];
|
|
2417
|
+
}
|
|
2418
|
+
delete varProps[k];
|
|
2419
|
+
toSort = true;
|
|
2420
|
+
}
|
|
2421
|
+
else if (k === BIND_CHECKED) {
|
|
2422
|
+
// Set flag, will process after walk
|
|
2423
|
+
bindCheckedSignal = varProps[k];
|
|
2424
|
+
}
|
|
2425
|
+
else if (k === BIND_VALUE) {
|
|
2426
|
+
// Set flag, will process after walk
|
|
2427
|
+
bindValueSignal = varProps[k];
|
|
2428
|
+
}
|
|
2429
|
+
processedKeys.add(k);
|
|
2430
|
+
}
|
|
2431
|
+
// Handle bind:* - only in varProps, bind:* should be moved to varProps
|
|
2432
|
+
if (bindCheckedSignal || bindValueSignal) {
|
|
2433
|
+
if (!varPropsCopied) {
|
|
2434
|
+
varProps = { ...varProps };
|
|
2435
|
+
varPropsCopied = true;
|
|
2436
|
+
}
|
|
2437
|
+
if (bindCheckedSignal) {
|
|
2438
|
+
delete varProps[BIND_CHECKED];
|
|
2439
|
+
varProps.checked = bindCheckedSignal;
|
|
2440
|
+
const handler = createQRL(null, '_chk', _chk, null, null, [bindCheckedSignal]);
|
|
2441
|
+
// Move on:input from constProps if it exists
|
|
2442
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'on:input')) {
|
|
2443
|
+
if (!constPropsCopied) {
|
|
2444
|
+
constProps = { ...constProps };
|
|
2445
|
+
constPropsCopied = true;
|
|
2446
|
+
}
|
|
2447
|
+
const existingHandler = constProps['on:input'];
|
|
2448
|
+
delete constProps['on:input'];
|
|
2449
|
+
toSort = mergeHandlers(varProps, 'on:input', existingHandler) || toSort;
|
|
2450
|
+
}
|
|
2451
|
+
toSort = mergeHandlers(varProps, 'on:input', handler) || toSort;
|
|
2452
|
+
}
|
|
2453
|
+
else if (bindValueSignal) {
|
|
2454
|
+
delete varProps[BIND_VALUE];
|
|
2455
|
+
varProps.value = bindValueSignal;
|
|
2456
|
+
const handler = createQRL(null, '_val', _val, null, null, [bindValueSignal]);
|
|
2457
|
+
// Move on:input from constProps if it exists
|
|
2458
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'on:input')) {
|
|
2459
|
+
if (!constPropsCopied) {
|
|
2460
|
+
constProps = { ...constProps };
|
|
2461
|
+
constPropsCopied = true;
|
|
2462
|
+
}
|
|
2463
|
+
const existingHandler = constProps['on:input'];
|
|
2464
|
+
delete constProps['on:input'];
|
|
2465
|
+
toSort = mergeHandlers(varProps, 'on:input', existingHandler) || toSort;
|
|
2466
|
+
}
|
|
2467
|
+
toSort = mergeHandlers(varProps, 'on:input', handler) || toSort;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
// Transform className -> class
|
|
2472
|
+
if (varProps && _hasOwnProperty$1.call(varProps, 'className')) {
|
|
2473
|
+
if (!varPropsCopied) {
|
|
2474
|
+
varProps = { ...varProps };
|
|
2475
|
+
varPropsCopied = true;
|
|
2476
|
+
}
|
|
2477
|
+
varProps.class = varProps.className;
|
|
2478
|
+
varProps.className = undefined;
|
|
2479
|
+
toSort = true;
|
|
2480
|
+
if (qDev) {
|
|
2481
|
+
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'className')) {
|
|
2485
|
+
if (!constPropsCopied) {
|
|
2486
|
+
constProps = { ...constProps };
|
|
2487
|
+
constPropsCopied = true;
|
|
2488
|
+
}
|
|
2489
|
+
constProps.class = constProps.className;
|
|
2490
|
+
constProps.className = undefined;
|
|
2491
|
+
if (qDev) {
|
|
2492
|
+
logOnceWarn(`jsx${dev ? ` ${dev.fileName}${dev?.lineNumber ? `:${dev.lineNumber}` : ''}` : ''}: \`className\` is deprecated. Use \`class\` instead.`);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
if (varProps) {
|
|
2497
|
+
for (const k in varProps) {
|
|
2498
|
+
if (k === 'children') {
|
|
2499
|
+
if (!varPropsCopied) {
|
|
2500
|
+
varProps = { ...varProps };
|
|
2501
|
+
varPropsCopied = true;
|
|
2443
2502
|
}
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2503
|
+
children ||= varProps.children;
|
|
2504
|
+
delete varProps.children;
|
|
2505
|
+
}
|
|
2506
|
+
else if (k === 'key') {
|
|
2507
|
+
if (!varPropsCopied) {
|
|
2508
|
+
varProps = { ...varProps };
|
|
2509
|
+
varPropsCopied = true;
|
|
2447
2510
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2511
|
+
key ||= varProps.key;
|
|
2512
|
+
delete varProps.key;
|
|
2513
|
+
}
|
|
2514
|
+
else if (constProps && k in constProps) {
|
|
2515
|
+
if (!varPropsCopied) {
|
|
2516
|
+
varProps = { ...varProps };
|
|
2517
|
+
varPropsCopied = true;
|
|
2518
|
+
}
|
|
2519
|
+
delete varProps[k];
|
|
2520
|
+
}
|
|
2521
|
+
else if (varProps[k] === null) {
|
|
2522
|
+
if (!varPropsCopied) {
|
|
2523
|
+
varProps = { ...varProps };
|
|
2524
|
+
varPropsCopied = true;
|
|
2450
2525
|
}
|
|
2526
|
+
// Clean up null markers (from event conversions)
|
|
2527
|
+
delete varProps[k];
|
|
2451
2528
|
}
|
|
2452
2529
|
}
|
|
2453
|
-
|
|
2454
|
-
|
|
2530
|
+
}
|
|
2531
|
+
return new JSXNodeImpl(type, varProps, constProps, children, key, toSort || true, dev);
|
|
2455
2532
|
};
|
|
2456
2533
|
/** @internal @deprecated v1 compat */
|
|
2457
2534
|
const _jsxC = (type, mutable, _flags, key) => jsx(type, mutable, key);
|
|
@@ -2547,7 +2624,7 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2547
2624
|
let isInlineComponent = false;
|
|
2548
2625
|
if (componentQRL === null) {
|
|
2549
2626
|
componentQRL = container.getHostProp(renderHost, OnRenderProp);
|
|
2550
|
-
assertDefined(componentQRL, 'No Component found at this location');
|
|
2627
|
+
isDev && assertDefined(componentQRL, 'No Component found at this location');
|
|
2551
2628
|
}
|
|
2552
2629
|
if (isQrl(componentQRL)) {
|
|
2553
2630
|
props = props || container.getHostProp(renderHost, ELEMENT_PROPS) || EMPTY_OBJ;
|
|
@@ -2566,6 +2643,7 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2566
2643
|
const inlineComponent = componentQRL;
|
|
2567
2644
|
componentFn = () => invokeApply(iCtx, inlineComponent, [props || EMPTY_OBJ]);
|
|
2568
2645
|
}
|
|
2646
|
+
const isSsr = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
2569
2647
|
const executeComponentWithPromiseExceptionRetry = (retryCount = 0) => safeCall(() => {
|
|
2570
2648
|
if (!isInlineComponent) {
|
|
2571
2649
|
container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
|
|
@@ -2576,6 +2654,19 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
2576
2654
|
}
|
|
2577
2655
|
return maybeThen(componentFn(props), (jsx) => maybeThen(iCtx.$waitOn$, () => jsx));
|
|
2578
2656
|
}, (jsx) => {
|
|
2657
|
+
// In SSR, check if the component was marked dirty (COMPONENT bit) during execution.
|
|
2658
|
+
// This happens when something completes and updates reactive primitives
|
|
2659
|
+
// while we're waiting on $waitOn$. If so, we need to re-execute the component
|
|
2660
|
+
// to get fresh JSX with updated values.
|
|
2661
|
+
if (isSsr && !isInlineComponent) {
|
|
2662
|
+
const ssrNode = renderHost;
|
|
2663
|
+
if (ssrNode.dirty & 4 /* ChoreBits.COMPONENT */) {
|
|
2664
|
+
ssrNode.dirty &= ~4 /* ChoreBits.COMPONENT */;
|
|
2665
|
+
if (retryCount < MAX_RETRY_ON_PROMISE_COUNT) {
|
|
2666
|
+
return executeComponentWithPromiseExceptionRetry(retryCount + 1);
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2579
2670
|
const useOnEvents = container.getHostProp(renderHost, USE_ON_LOCAL);
|
|
2580
2671
|
if (useOnEvents) {
|
|
2581
2672
|
return addUseOnEvents(jsx, useOnEvents);
|
|
@@ -2744,7 +2835,7 @@ function injectPlaceholderElement(jsx) {
|
|
|
2744
2835
|
return [placeholder, jsx];
|
|
2745
2836
|
}
|
|
2746
2837
|
// For primitives, we can't add children, so we wrap them in a fragment.
|
|
2747
|
-
if (
|
|
2838
|
+
if (isPrimitiveOrNullUndefined(jsx)) {
|
|
2748
2839
|
const placeholder = createPlaceholderScriptNode();
|
|
2749
2840
|
return [placeholder, _jsxSorted(Fragment, null, null, [jsx, placeholder], 0, null)];
|
|
2750
2841
|
}
|
|
@@ -2758,7 +2849,7 @@ function injectPlaceholderElement(jsx) {
|
|
|
2758
2849
|
}
|
|
2759
2850
|
/** @returns An empty <script> element for adding qwik metadata attributes to */
|
|
2760
2851
|
function createPlaceholderScriptNode() {
|
|
2761
|
-
return new JSXNodeImpl('script', null, { hidden: '' });
|
|
2852
|
+
return new JSXNodeImpl('script', null, { hidden: '' }, null, null);
|
|
2762
2853
|
}
|
|
2763
2854
|
|
|
2764
2855
|
/**
|
|
@@ -2874,15 +2965,12 @@ const _restProps = (props, omit = [], target = {}) => {
|
|
|
2874
2965
|
varPropsTarget[key] = varProps[key];
|
|
2875
2966
|
}
|
|
2876
2967
|
}
|
|
2877
|
-
return createPropsProxy(new JSXNodeImpl(null, varPropsTarget, constPropsTarget));
|
|
2968
|
+
return createPropsProxy(new JSXNodeImpl(null, varPropsTarget, constPropsTarget, null, null));
|
|
2878
2969
|
};
|
|
2879
2970
|
|
|
2880
2971
|
const styleContent = (styleId) => {
|
|
2881
2972
|
return ComponentStylesPrefixContent + styleId;
|
|
2882
2973
|
};
|
|
2883
|
-
function hasClassAttr(props) {
|
|
2884
|
-
return 'class' in props;
|
|
2885
|
-
}
|
|
2886
2974
|
function isClassAttr(key) {
|
|
2887
2975
|
return key === 'class';
|
|
2888
2976
|
}
|
|
@@ -3048,132 +3136,22 @@ function isEnumeratedBooleanAttribute(key) {
|
|
|
3048
3136
|
return isAriaAttribute(key) || ['spellcheck', 'draggable', 'contenteditable'].includes(key);
|
|
3049
3137
|
}
|
|
3050
3138
|
const setValueForStyle = (styleName, value) => {
|
|
3051
|
-
if (typeof value === 'number' && value !== 0 && !isUnitlessNumber(styleName)) {
|
|
3052
|
-
return value + 'px';
|
|
3053
|
-
}
|
|
3054
|
-
return value;
|
|
3055
|
-
};
|
|
3056
|
-
function isAriaAttribute(prop) {
|
|
3057
|
-
return prop.startsWith('aria-');
|
|
3058
|
-
}
|
|
3059
|
-
const styleKey = (qStyles, index) => {
|
|
3060
|
-
assertQrl(qStyles);
|
|
3061
|
-
return `${hashCode(qStyles.$hash$)}-${index}`;
|
|
3062
|
-
};
|
|
3063
|
-
|
|
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$;
|
|
3139
|
+
if (typeof value === 'number' && value !== 0 && !isUnitlessNumber(styleName)) {
|
|
3140
|
+
return value + 'px';
|
|
3156
3141
|
}
|
|
3157
|
-
|
|
3158
|
-
/** @internal */
|
|
3159
|
-
const isTask = (value) => {
|
|
3160
|
-
return value instanceof Task;
|
|
3142
|
+
return value;
|
|
3161
3143
|
};
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
const [task] = useLexicalScope();
|
|
3169
|
-
const container = getDomContainer(element);
|
|
3170
|
-
task.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
3171
|
-
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
3144
|
+
function isAriaAttribute(prop) {
|
|
3145
|
+
return prop.startsWith('aria-');
|
|
3146
|
+
}
|
|
3147
|
+
const styleKey = (qStyles, index) => {
|
|
3148
|
+
assertQrl(qStyles);
|
|
3149
|
+
return `${hashCode(qStyles.$hash$)}-${index}`;
|
|
3172
3150
|
};
|
|
3173
3151
|
|
|
3174
3152
|
/** @internal */
|
|
3175
3153
|
const mapApp_findIndx = (array, key, start) => {
|
|
3176
|
-
assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
3154
|
+
isDev && assertTrue(start % 2 === 0, 'Expecting even number.');
|
|
3177
3155
|
let bottom = start >> 1;
|
|
3178
3156
|
let top = (array.length - 2) >> 1;
|
|
3179
3157
|
while (bottom <= top) {
|
|
@@ -3220,6 +3198,127 @@ const mapArray_has = (array, key, start) => {
|
|
|
3220
3198
|
return mapApp_findIndx(array, key, start) >= 0;
|
|
3221
3199
|
};
|
|
3222
3200
|
|
|
3201
|
+
class DeleteOperation {
|
|
3202
|
+
target;
|
|
3203
|
+
constructor(target) {
|
|
3204
|
+
this.target = target;
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
class RemoveAllChildrenOperation {
|
|
3208
|
+
target;
|
|
3209
|
+
constructor(target) {
|
|
3210
|
+
this.target = target;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
class SetTextOperation {
|
|
3214
|
+
target;
|
|
3215
|
+
text;
|
|
3216
|
+
operationType = 16 /* VNodeOperationType.SetText */;
|
|
3217
|
+
constructor(target, text) {
|
|
3218
|
+
this.target = target;
|
|
3219
|
+
this.text = text;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
class InsertOrMoveOperation {
|
|
3223
|
+
target;
|
|
3224
|
+
parent;
|
|
3225
|
+
beforeTarget;
|
|
3226
|
+
constructor(target, parent, beforeTarget) {
|
|
3227
|
+
this.target = target;
|
|
3228
|
+
this.parent = parent;
|
|
3229
|
+
this.beforeTarget = beforeTarget;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
class SetAttributeOperation {
|
|
3233
|
+
target;
|
|
3234
|
+
attrName;
|
|
3235
|
+
attrValue;
|
|
3236
|
+
scopedStyleIdPrefix;
|
|
3237
|
+
isSvg;
|
|
3238
|
+
constructor(target, attrName, attrValue, scopedStyleIdPrefix, isSvg) {
|
|
3239
|
+
this.target = target;
|
|
3240
|
+
this.attrName = attrName;
|
|
3241
|
+
this.attrValue = attrValue;
|
|
3242
|
+
this.scopedStyleIdPrefix = scopedStyleIdPrefix;
|
|
3243
|
+
this.isSvg = isSvg;
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
/** Factory functions to create operations with consistent hidden classes. */
|
|
3247
|
+
const createDeleteOperation = (target) => new DeleteOperation(target);
|
|
3248
|
+
const createRemoveAllChildrenOperation = (target) => new RemoveAllChildrenOperation(target);
|
|
3249
|
+
const createSetTextOperation = (target, text) => new SetTextOperation(target, text);
|
|
3250
|
+
const createInsertOrMoveOperation = (target, parent, beforeTarget) => new InsertOrMoveOperation(target, parent, beforeTarget);
|
|
3251
|
+
const createSetAttributeOperation = (target, attrName, attrValue, scopedStyleIdPrefix = null, isSvg = false) => new SetAttributeOperation(target, attrName, attrValue, scopedStyleIdPrefix, isSvg);
|
|
3252
|
+
|
|
3253
|
+
function callQrl(container, host, qrl, event, element, useGetObjectById) {
|
|
3254
|
+
const getObjectById = useGetObjectById ? container?.$getObjectById$ || null : null;
|
|
3255
|
+
const singleItem = vnode_getProp(host, ITERATION_ITEM_SINGLE, getObjectById);
|
|
3256
|
+
if (singleItem !== null) {
|
|
3257
|
+
return qrl(event, element, singleItem);
|
|
3258
|
+
}
|
|
3259
|
+
const multiItems = vnode_getProp(host, ITERATION_ITEM_MULTI, getObjectById);
|
|
3260
|
+
if (multiItems !== null) {
|
|
3261
|
+
return qrl(event, element, ...multiItems);
|
|
3262
|
+
}
|
|
3263
|
+
return qrl(event, element);
|
|
3264
|
+
}
|
|
3265
|
+
/**
|
|
3266
|
+
* This is called by qwik-loader to run a QRL. It has to be synchronous.
|
|
3267
|
+
*
|
|
3268
|
+
* @internal
|
|
3269
|
+
*/
|
|
3270
|
+
const _run = (...args) => {
|
|
3271
|
+
// This will already check container
|
|
3272
|
+
const [qrl] = useLexicalScope();
|
|
3273
|
+
const context = getInvokeContext();
|
|
3274
|
+
const hostElement = context.$hostElement$;
|
|
3275
|
+
if (hostElement) {
|
|
3276
|
+
context.$container$ ||= getDomContainer(hostElement.node);
|
|
3277
|
+
vnode_ensureElementInflated(hostElement);
|
|
3278
|
+
return retryOnPromise(() => {
|
|
3279
|
+
if (!(hostElement.flags & 32 /* VNodeFlags.Deleted */)) {
|
|
3280
|
+
return callQrl(context.$container$, hostElement, qrl, args[0], args[1], true).catch((err) => {
|
|
3281
|
+
const container = context.$container$;
|
|
3282
|
+
if (container) {
|
|
3283
|
+
container.handleError(err, hostElement);
|
|
3284
|
+
}
|
|
3285
|
+
else {
|
|
3286
|
+
throw err;
|
|
3287
|
+
}
|
|
3288
|
+
});
|
|
3289
|
+
}
|
|
3290
|
+
});
|
|
3291
|
+
}
|
|
3292
|
+
};
|
|
3293
|
+
|
|
3294
|
+
let _setAttribute = null;
|
|
3295
|
+
const fastSetAttribute = (target, name, value) => {
|
|
3296
|
+
if (!_setAttribute) {
|
|
3297
|
+
_setAttribute = target.setAttribute;
|
|
3298
|
+
}
|
|
3299
|
+
_setAttribute.call(target, name, value);
|
|
3300
|
+
};
|
|
3301
|
+
let _setAttributeNS = null;
|
|
3302
|
+
const fastSetAttributeNS = (target, namespace, name, value) => {
|
|
3303
|
+
if (!_setAttributeNS) {
|
|
3304
|
+
_setAttributeNS = target.setAttributeNS;
|
|
3305
|
+
}
|
|
3306
|
+
_setAttributeNS.call(target, namespace, name, value);
|
|
3307
|
+
};
|
|
3308
|
+
function directSetAttribute(element, attrName, attrValue, isSvg) {
|
|
3309
|
+
if (attrValue != null) {
|
|
3310
|
+
if (isSvg) {
|
|
3311
|
+
// only svg elements can have namespace attributes
|
|
3312
|
+
const namespace = getAttributeNamespace(attrName);
|
|
3313
|
+
if (namespace) {
|
|
3314
|
+
fastSetAttributeNS(element, namespace, attrName, attrValue);
|
|
3315
|
+
return;
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
fastSetAttribute(element, attrName, attrValue);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3223
3322
|
/**
|
|
3224
3323
|
* Helper to get the next sibling of a VNode. Extracted to module scope to help V8 inline it
|
|
3225
3324
|
* reliably.
|
|
@@ -3229,9 +3328,12 @@ function peekNextSibling(vCurrent) {
|
|
|
3229
3328
|
}
|
|
3230
3329
|
const _hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
3231
3330
|
/** 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
|
-
|
|
3331
|
+
function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix, originalValue) {
|
|
3332
|
+
import.meta.env.TEST &&
|
|
3333
|
+
scopedStyleIdPrefix &&
|
|
3334
|
+
vnode_setProp(vnode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
3335
|
+
vnode_setProp(vnode, key, originalValue);
|
|
3336
|
+
addVNodeOperation(journal, createSetAttributeOperation(vnode.node, key, value, scopedStyleIdPrefix, (vnode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
3235
3337
|
}
|
|
3236
3338
|
const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyleIdPrefix) => {
|
|
3237
3339
|
const diffContext = {
|
|
@@ -3253,6 +3355,7 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3253
3355
|
jsxIdx: 0,
|
|
3254
3356
|
jsxCount: 0,
|
|
3255
3357
|
shouldAdvance: true,
|
|
3358
|
+
isCreationMode: false,
|
|
3256
3359
|
subscriptionData: {
|
|
3257
3360
|
const: new SubscriptionData({
|
|
3258
3361
|
$scopedStyleIdPrefix$: scopedStyleIdPrefix,
|
|
@@ -3281,8 +3384,8 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3281
3384
|
//////////////////////////////////////////////
|
|
3282
3385
|
//////////////////////////////////////////////
|
|
3283
3386
|
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');
|
|
3387
|
+
isDev && assertFalse(vnode_isVNode(jsxNode), 'JSXNode should not be a VNode');
|
|
3388
|
+
isDev && assertTrue(vnode_isVNode(vStartNode), 'vStartNode should be a VNode');
|
|
3286
3389
|
diffContext.vParent = vStartNode;
|
|
3287
3390
|
diffContext.vNewNode = null;
|
|
3288
3391
|
diffContext.vCurrent = vnode_getFirstChild(vStartNode);
|
|
@@ -3293,7 +3396,8 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3293
3396
|
}
|
|
3294
3397
|
while (diffContext.stack.length) {
|
|
3295
3398
|
while (diffContext.jsxIdx < diffContext.jsxCount) {
|
|
3296
|
-
|
|
3399
|
+
isDev &&
|
|
3400
|
+
assertFalse(diffContext.vParent === diffContext.vCurrent, "Parent and current can't be the same");
|
|
3297
3401
|
if (typeof diffContext.jsxValue === 'string') {
|
|
3298
3402
|
expectText(diffContext, diffContext.jsxValue);
|
|
3299
3403
|
}
|
|
@@ -3301,26 +3405,7 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3301
3405
|
expectText(diffContext, String(diffContext.jsxValue));
|
|
3302
3406
|
}
|
|
3303
3407
|
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)) {
|
|
3408
|
+
if (isJSXNode(diffContext.jsxValue)) {
|
|
3324
3409
|
const type = diffContext.jsxValue.type;
|
|
3325
3410
|
if (typeof type === 'string') {
|
|
3326
3411
|
expectNoMoreTextNodes(diffContext);
|
|
@@ -3368,6 +3453,28 @@ function diff(diffContext, jsxNode, vStartNode) {
|
|
|
3368
3453
|
}
|
|
3369
3454
|
}
|
|
3370
3455
|
}
|
|
3456
|
+
else if (Array.isArray(diffContext.jsxValue)) {
|
|
3457
|
+
descend(diffContext, diffContext.jsxValue, false);
|
|
3458
|
+
}
|
|
3459
|
+
else if (isSignal(diffContext.jsxValue)) {
|
|
3460
|
+
expectVirtual(diffContext, "S" /* VirtualType.WrappedSignal */, null);
|
|
3461
|
+
const unwrappedSignal = diffContext.jsxValue instanceof WrappedSignalImpl
|
|
3462
|
+
? diffContext.jsxValue.$unwrapIfSignal$()
|
|
3463
|
+
: diffContext.jsxValue;
|
|
3464
|
+
const signals = diffContext.vCurrent?.[_EFFECT_BACK_REF]?.get("." /* EffectProperty.VNODE */)?.backRef;
|
|
3465
|
+
let hasUnwrappedSignal = signals?.has(unwrappedSignal);
|
|
3466
|
+
if (signals && unwrappedSignal instanceof WrappedSignalImpl) {
|
|
3467
|
+
hasUnwrappedSignal = containsWrappedSignal(signals, unwrappedSignal);
|
|
3468
|
+
}
|
|
3469
|
+
if (!hasUnwrappedSignal) {
|
|
3470
|
+
const vHost = (diffContext.vNewNode || diffContext.vCurrent);
|
|
3471
|
+
descend(diffContext, resolveSignalAndDescend(diffContext, () => trackSignalAndAssignHost(unwrappedSignal, vHost, "." /* EffectProperty.VNODE */, diffContext.container)), true);
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
else if (isPromise(diffContext.jsxValue)) {
|
|
3475
|
+
expectVirtual(diffContext, "A" /* VirtualType.Awaited */, null);
|
|
3476
|
+
diffContext.asyncQueue.push(diffContext.jsxValue, diffContext.vNewNode || diffContext.vCurrent);
|
|
3477
|
+
}
|
|
3371
3478
|
}
|
|
3372
3479
|
else if (diffContext.jsxValue === SkipRender) ;
|
|
3373
3480
|
else {
|
|
@@ -3447,7 +3554,12 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
3447
3554
|
}
|
|
3448
3555
|
stackPush(diffContext, children, descendVNode);
|
|
3449
3556
|
if (descendVNode) {
|
|
3450
|
-
|
|
3557
|
+
isDev &&
|
|
3558
|
+
assertDefined(diffContext.vCurrent || diffContext.vNewNode, 'Expecting vCurrent to be defined.');
|
|
3559
|
+
const creationMode = diffContext.isCreationMode ||
|
|
3560
|
+
!!diffContext.vNewNode ||
|
|
3561
|
+
!vnode_getFirstChild(diffContext.vCurrent);
|
|
3562
|
+
diffContext.isCreationMode = creationMode;
|
|
3451
3563
|
diffContext.vSideBuffer = null;
|
|
3452
3564
|
diffContext.vSiblings = null;
|
|
3453
3565
|
diffContext.vSiblingsArray = null;
|
|
@@ -3460,6 +3572,7 @@ function descend(diffContext, children, descendVNode, shouldExpectNoChildren = t
|
|
|
3460
3572
|
function ascend(diffContext) {
|
|
3461
3573
|
const descendVNode = diffContext.stack.pop(); // boolean: descendVNode
|
|
3462
3574
|
if (descendVNode) {
|
|
3575
|
+
diffContext.isCreationMode = diffContext.stack.pop();
|
|
3463
3576
|
diffContext.vSideBuffer = diffContext.stack.pop();
|
|
3464
3577
|
diffContext.vSiblings = diffContext.stack.pop();
|
|
3465
3578
|
diffContext.vSiblingsArray = diffContext.stack.pop();
|
|
@@ -3476,7 +3589,7 @@ function ascend(diffContext) {
|
|
|
3476
3589
|
function stackPush(diffContext, children, descendVNode) {
|
|
3477
3590
|
diffContext.stack.push(diffContext.jsxChildren, diffContext.jsxIdx, diffContext.jsxCount, diffContext.jsxValue);
|
|
3478
3591
|
if (descendVNode) {
|
|
3479
|
-
diffContext.stack.push(diffContext.vParent, diffContext.vCurrent, diffContext.vNewNode, diffContext.vSiblingsArray, diffContext.vSiblings, diffContext.vSideBuffer);
|
|
3592
|
+
diffContext.stack.push(diffContext.vParent, diffContext.vCurrent, diffContext.vNewNode, diffContext.vSiblingsArray, diffContext.vSiblings, diffContext.vSideBuffer, diffContext.isCreationMode);
|
|
3480
3593
|
}
|
|
3481
3594
|
diffContext.stack.push(descendVNode);
|
|
3482
3595
|
if (Array.isArray(children)) {
|
|
@@ -3604,12 +3717,20 @@ function expectSlot(diffContext) {
|
|
|
3604
3717
|
else if (vProjectedNode === diffContext.vCurrent) ;
|
|
3605
3718
|
else {
|
|
3606
3719
|
// move from q:template to the target node
|
|
3720
|
+
const oldParent = vProjectedNode.parent;
|
|
3607
3721
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vProjectedNode), diffContext.vCurrent && getInsertBefore(diffContext));
|
|
3608
3722
|
vnode_setProp(diffContext.vNewNode, QSlot, slotNameKey);
|
|
3609
3723
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.vNewNode);
|
|
3610
3724
|
isDev &&
|
|
3611
3725
|
vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
3612
3726
|
isDev && vnode_setProp(diffContext.vNewNode, 'q:code', 'expectSlot' + count++);
|
|
3727
|
+
// If we moved from a q:template and it's now empty, remove it
|
|
3728
|
+
if (oldParent &&
|
|
3729
|
+
vnode_isElementVNode(oldParent) &&
|
|
3730
|
+
!oldParent.firstChild &&
|
|
3731
|
+
vnode_getElementName(oldParent) === QTemplate) {
|
|
3732
|
+
vnode_remove(diffContext.journal, oldParent.parent, oldParent, true);
|
|
3733
|
+
}
|
|
3613
3734
|
}
|
|
3614
3735
|
return true;
|
|
3615
3736
|
}
|
|
@@ -3684,7 +3805,8 @@ function expectNoChildren(diffContext, removeDOM = true) {
|
|
|
3684
3805
|
}
|
|
3685
3806
|
/** Expect no more nodes - Any nodes which are still at cursor, need to be removed. */
|
|
3686
3807
|
function expectNoMore(diffContext) {
|
|
3687
|
-
|
|
3808
|
+
isDev &&
|
|
3809
|
+
assertFalse(diffContext.vParent === diffContext.vCurrent, "Parent and current can't be the same");
|
|
3688
3810
|
if (diffContext.vCurrent !== null) {
|
|
3689
3811
|
while (diffContext.vCurrent) {
|
|
3690
3812
|
const toRemove = diffContext.vCurrent;
|
|
@@ -3714,20 +3836,6 @@ function expectNoMoreTextNodes(diffContext) {
|
|
|
3714
3836
|
*/
|
|
3715
3837
|
function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
3716
3838
|
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
3839
|
const { constProps } = jsx;
|
|
3732
3840
|
let needsQDispatchEventPatch = false;
|
|
3733
3841
|
if (constProps) {
|
|
@@ -3778,7 +3886,7 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3778
3886
|
}
|
|
3779
3887
|
if (isPromise(value)) {
|
|
3780
3888
|
const vHost = diffContext.vNewNode;
|
|
3781
|
-
const attributePromise = value.then((resolvedValue) =>
|
|
3889
|
+
const attributePromise = value.then((resolvedValue) => directSetAttribute(element, key, serializeAttribute(key, resolvedValue, diffContext.scopedStyleIdPrefix), (vHost.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
3782
3890
|
diffContext.asyncAttributePromises.push(attributePromise);
|
|
3783
3891
|
continue;
|
|
3784
3892
|
}
|
|
@@ -3799,7 +3907,7 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3799
3907
|
element.value = escapeHTML(value || '');
|
|
3800
3908
|
continue;
|
|
3801
3909
|
}
|
|
3802
|
-
|
|
3910
|
+
directSetAttribute(element, key, serializeAttribute(key, value, diffContext.scopedStyleIdPrefix), (diffContext.vNewNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0);
|
|
3803
3911
|
}
|
|
3804
3912
|
}
|
|
3805
3913
|
const key = jsx.key;
|
|
@@ -3808,7 +3916,8 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3808
3916
|
}
|
|
3809
3917
|
// append class attribute if styleScopedId exists and there is no class attribute
|
|
3810
3918
|
if (diffContext.scopedStyleIdPrefix) {
|
|
3811
|
-
const classAttributeExists =
|
|
3919
|
+
const classAttributeExists = _hasOwnProperty.call(jsx.varProps, 'class') ||
|
|
3920
|
+
(jsx.constProps && _hasOwnProperty.call(jsx.constProps, 'class'));
|
|
3812
3921
|
if (!classAttributeExists) {
|
|
3813
3922
|
element.setAttribute('class', diffContext.scopedStyleIdPrefix);
|
|
3814
3923
|
}
|
|
@@ -3818,28 +3927,35 @@ function createNewElement(diffContext, jsx, elementName, currentFile) {
|
|
|
3818
3927
|
}
|
|
3819
3928
|
function createElementWithNamespace(diffContext, elementName) {
|
|
3820
3929
|
const domParentVNode = vnode_getDomParentVNode(diffContext.vParent, true);
|
|
3821
|
-
const
|
|
3822
|
-
const
|
|
3930
|
+
const namespaceData = getNewElementNamespaceData(domParentVNode, elementName);
|
|
3931
|
+
const currentDocument = import.meta.env.TEST ? diffContext.container.document : document;
|
|
3932
|
+
const element = namespaceData.elementNamespaceFlag === 0 /* VNodeFlags.NS_html */
|
|
3933
|
+
? currentDocument.createElement(elementName)
|
|
3934
|
+
: currentDocument.createElementNS(namespaceData.elementNamespace, elementName);
|
|
3823
3935
|
diffContext.vNewNode = vnode_newElement(element, elementName);
|
|
3824
|
-
diffContext.vNewNode.flags |= elementNamespaceFlag;
|
|
3936
|
+
diffContext.vNewNode.flags |= namespaceData.elementNamespaceFlag;
|
|
3825
3937
|
return element;
|
|
3826
3938
|
}
|
|
3827
3939
|
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
3940
|
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
|
-
}
|
|
3941
|
+
if (diffContext.isCreationMode) {
|
|
3942
|
+
needsQDispatchEventPatch = createNewElement(diffContext, jsx, elementName, null);
|
|
3839
3943
|
}
|
|
3840
3944
|
else {
|
|
3841
|
-
|
|
3842
|
-
|
|
3945
|
+
const isElementVNode = diffContext.vCurrent && vnode_isElementVNode(diffContext.vCurrent);
|
|
3946
|
+
const isSameElementName = isElementVNode && elementName === vnode_getElementName(diffContext.vCurrent);
|
|
3947
|
+
const jsxKey = jsx.key;
|
|
3948
|
+
const currentKey = isElementVNode && diffContext.vCurrent.key;
|
|
3949
|
+
if (!isSameElementName || jsxKey !== currentKey) {
|
|
3950
|
+
const sideBufferKey = getSideBufferKey(elementName, jsxKey);
|
|
3951
|
+
if (moveOrCreateKeyedNode(diffContext, elementName, jsxKey, sideBufferKey, diffContext.vParent)) {
|
|
3952
|
+
needsQDispatchEventPatch = createNewElement(diffContext, jsx, elementName, null);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
else {
|
|
3956
|
+
// delete the key from the side buffer if it is the same element
|
|
3957
|
+
deleteFromSideBuffer(diffContext, elementName, jsxKey);
|
|
3958
|
+
}
|
|
3843
3959
|
}
|
|
3844
3960
|
// reconcile attributes
|
|
3845
3961
|
const jsxProps = jsx.varProps;
|
|
@@ -3847,7 +3963,8 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3847
3963
|
const element = vNode.node;
|
|
3848
3964
|
if (jsxProps) {
|
|
3849
3965
|
needsQDispatchEventPatch =
|
|
3850
|
-
diffProps(diffContext, vNode, jsxProps, (
|
|
3966
|
+
diffProps(diffContext, vNode, jsxProps, (isDev && getFileLocationFromJsx(jsx.dev)) || null) ||
|
|
3967
|
+
needsQDispatchEventPatch;
|
|
3851
3968
|
}
|
|
3852
3969
|
if (needsQDispatchEventPatch) {
|
|
3853
3970
|
// Event handler needs to be patched onto the element.
|
|
@@ -3864,7 +3981,7 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3864
3981
|
];
|
|
3865
3982
|
for (const qrl of qrls.flat(2)) {
|
|
3866
3983
|
if (qrl) {
|
|
3867
|
-
|
|
3984
|
+
callQrl(diffContext.container, vNode, qrl, event, vNode.node, false).catch((e) => {
|
|
3868
3985
|
diffContext.container.handleError(e, vNode);
|
|
3869
3986
|
});
|
|
3870
3987
|
}
|
|
@@ -3873,92 +3990,127 @@ function expectElement(diffContext, jsx, elementName) {
|
|
|
3873
3990
|
}
|
|
3874
3991
|
}
|
|
3875
3992
|
}
|
|
3876
|
-
function diffProps(diffContext, vnode, newAttrs,
|
|
3877
|
-
|
|
3993
|
+
function diffProps(diffContext, vnode, newAttrs, currentFile) {
|
|
3994
|
+
if (!diffContext.isCreationMode) {
|
|
3995
|
+
// inflate only resumed vnodes
|
|
3996
|
+
vnode_ensureElementInflated(vnode);
|
|
3997
|
+
}
|
|
3998
|
+
const oldAttrs = vnode.props;
|
|
3878
3999
|
let patchEventDispatch = false;
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
4000
|
+
// Actual diffing logic
|
|
4001
|
+
// Apply all new attributes
|
|
4002
|
+
for (const key in newAttrs) {
|
|
4003
|
+
const newValue = newAttrs[key];
|
|
4004
|
+
const isEvent = isHtmlAttributeAnEventName(key);
|
|
4005
|
+
if (oldAttrs && _hasOwnProperty.call(oldAttrs, key)) {
|
|
4006
|
+
const oldValue = oldAttrs[key];
|
|
4007
|
+
if (newValue !== oldValue) {
|
|
4008
|
+
if (newValue instanceof WrappedSignalImpl &&
|
|
4009
|
+
oldValue instanceof WrappedSignalImpl &&
|
|
4010
|
+
areWrappedSignalsEqual(newValue, oldValue)) {
|
|
4011
|
+
continue;
|
|
4012
|
+
}
|
|
4013
|
+
if (isEvent) {
|
|
4014
|
+
const result = recordJsxEvent(diffContext, vnode, key, newValue, currentFile);
|
|
4015
|
+
patchEventDispatch ||= result;
|
|
4016
|
+
}
|
|
4017
|
+
else {
|
|
4018
|
+
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
4019
|
+
}
|
|
3891
4020
|
}
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
4021
|
+
}
|
|
4022
|
+
else if (newValue != null) {
|
|
4023
|
+
if (isEvent) {
|
|
4024
|
+
const result = recordJsxEvent(diffContext, vnode, key, newValue, currentFile);
|
|
4025
|
+
patchEventDispatch ||= result;
|
|
3895
4026
|
}
|
|
3896
4027
|
else {
|
|
3897
|
-
|
|
4028
|
+
patchProperty(diffContext, vnode, key, newValue, currentFile);
|
|
3898
4029
|
}
|
|
3899
4030
|
}
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
4031
|
+
}
|
|
4032
|
+
if (oldAttrs) {
|
|
4033
|
+
// Remove attributes that no longer exist in new props
|
|
4034
|
+
for (const key in oldAttrs) {
|
|
4035
|
+
if (!_hasOwnProperty.call(newAttrs, key) &&
|
|
4036
|
+
!key.startsWith(HANDLER_PREFIX) &&
|
|
4037
|
+
!isHtmlAttributeAnEventName(key)) {
|
|
4038
|
+
patchProperty(diffContext, vnode, key, null, currentFile);
|
|
3908
4039
|
}
|
|
3909
|
-
const vHost = vnode;
|
|
3910
|
-
value = retryOnPromise(() => trackSignalAndAssignHost(unwrappedSignal, vHost, key, diffContext.container, diffContext.subscriptionData.var));
|
|
3911
4040
|
}
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
4041
|
+
}
|
|
4042
|
+
return patchEventDispatch;
|
|
4043
|
+
}
|
|
4044
|
+
const patchProperty = (diffContext, vnode, key, value, currentFile) => {
|
|
4045
|
+
if (
|
|
4046
|
+
// set only property for iteration item, not an attribute
|
|
4047
|
+
key === ITERATION_ITEM_SINGLE ||
|
|
4048
|
+
key === ITERATION_ITEM_MULTI ||
|
|
4049
|
+
key.charAt(0) === HANDLER_PREFIX) {
|
|
4050
|
+
// TODO: there is a potential deoptimization here, because we are setting different keys on props.
|
|
4051
|
+
// Eager bailout - Insufficient type feedback for generic keyed access
|
|
4052
|
+
vnode_setProp(vnode, key, value);
|
|
4053
|
+
return;
|
|
4054
|
+
}
|
|
4055
|
+
const originalValue = value;
|
|
4056
|
+
if (key === 'ref') {
|
|
4057
|
+
const element = vnode.node;
|
|
4058
|
+
if (isSignal(value)) {
|
|
4059
|
+
value.value = element;
|
|
4060
|
+
return;
|
|
3916
4061
|
}
|
|
3917
|
-
if (
|
|
3918
|
-
|
|
3919
|
-
const attributePromise = value.then((resolvedValue) => {
|
|
3920
|
-
setAttribute(diffContext.journal, vHost, key, resolvedValue, diffContext.scopedStyleIdPrefix);
|
|
3921
|
-
});
|
|
3922
|
-
diffContext.asyncAttributePromises.push(attributePromise);
|
|
4062
|
+
else if (typeof value === 'function') {
|
|
4063
|
+
value(element);
|
|
3923
4064
|
return;
|
|
3924
4065
|
}
|
|
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;
|
|
4066
|
+
else {
|
|
4067
|
+
throw qError(15 /* QError.invalidRefValue */, [currentFile]);
|
|
3936
4068
|
}
|
|
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
|
-
}
|
|
4069
|
+
}
|
|
4070
|
+
const currentEffect = vnode[_EFFECT_BACK_REF]?.get(key);
|
|
4071
|
+
if (isSignal(value)) {
|
|
4072
|
+
const unwrappedSignal = value instanceof WrappedSignalImpl ? value.$unwrapIfSignal$() : value;
|
|
4073
|
+
if (currentEffect?.backRef?.has(unwrappedSignal)) {
|
|
4074
|
+
return;
|
|
3947
4075
|
}
|
|
3948
|
-
|
|
3949
|
-
|
|
4076
|
+
if (currentEffect) {
|
|
4077
|
+
clearEffectSubscription(diffContext.container, currentEffect);
|
|
3950
4078
|
}
|
|
4079
|
+
const vHost = vnode;
|
|
4080
|
+
value = retryOnPromise(() => trackSignalAndAssignHost(unwrappedSignal, vHost, key, diffContext.container, diffContext.subscriptionData.var));
|
|
3951
4081
|
}
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
!key.startsWith(HANDLER_PREFIX) &&
|
|
3956
|
-
!isHtmlAttributeAnEventName(key)) {
|
|
3957
|
-
record(key, null);
|
|
4082
|
+
else {
|
|
4083
|
+
if (currentEffect) {
|
|
4084
|
+
clearEffectSubscription(diffContext.container, currentEffect);
|
|
3958
4085
|
}
|
|
3959
4086
|
}
|
|
3960
|
-
|
|
3961
|
-
|
|
4087
|
+
if (isPromise(value)) {
|
|
4088
|
+
const vHost = vnode;
|
|
4089
|
+
const attributePromise = value.then((resolvedValue) => {
|
|
4090
|
+
setAttribute(diffContext.journal, vHost, key, resolvedValue, diffContext.scopedStyleIdPrefix, originalValue);
|
|
4091
|
+
});
|
|
4092
|
+
diffContext.asyncAttributePromises.push(attributePromise);
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
setAttribute(diffContext.journal, vnode, key, value, diffContext.scopedStyleIdPrefix, originalValue);
|
|
4096
|
+
};
|
|
4097
|
+
const recordJsxEvent = (diffContext, vnode, key, value, currentFile) => {
|
|
4098
|
+
const data = getEventDataFromHtmlAttribute(key);
|
|
4099
|
+
if (data) {
|
|
4100
|
+
const props = vnode.props;
|
|
4101
|
+
const [scope, eventName] = data;
|
|
4102
|
+
const scopedEvent = getScopedEventName(scope, eventName);
|
|
4103
|
+
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
4104
|
+
const scopedEventKey = ':' + scopedEvent;
|
|
4105
|
+
if (props && _hasOwnProperty.call(props, scopedEventKey)) {
|
|
4106
|
+
return false;
|
|
4107
|
+
}
|
|
4108
|
+
patchProperty(diffContext, vnode, scopedEventKey, value, currentFile);
|
|
4109
|
+
registerQwikLoaderEvent(diffContext, loaderScopedEvent);
|
|
4110
|
+
return true;
|
|
4111
|
+
}
|
|
4112
|
+
return false;
|
|
4113
|
+
};
|
|
3962
4114
|
function registerQwikLoaderEvent(diffContext, eventName) {
|
|
3963
4115
|
const qWindow = import.meta.env.TEST
|
|
3964
4116
|
? diffContext.container.document.defaultView
|
|
@@ -3970,6 +4122,16 @@ function registerQwikLoaderEvent(diffContext, eventName) {
|
|
|
3970
4122
|
function retrieveChildWithKey(diffContext, nodeName, key) {
|
|
3971
4123
|
let vNodeWithKey = null;
|
|
3972
4124
|
if (diffContext.vSiblings === null) {
|
|
4125
|
+
// check if the current node is the one we are looking for
|
|
4126
|
+
const vCurrent = diffContext.vCurrent;
|
|
4127
|
+
if (vCurrent) {
|
|
4128
|
+
const name = vnode_isElementVNode(vCurrent) ? vnode_getElementName(vCurrent) : null;
|
|
4129
|
+
const vKey = getKey(vCurrent) ||
|
|
4130
|
+
getComponentHash(vCurrent, diffContext.container.$getObjectById$);
|
|
4131
|
+
if (vKey === key && name === nodeName) {
|
|
4132
|
+
return vCurrent;
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
3973
4135
|
// it is not materialized; so materialize it.
|
|
3974
4136
|
diffContext.vSiblings = new Map();
|
|
3975
4137
|
diffContext.vSiblingsArray = [];
|
|
@@ -4005,8 +4167,9 @@ function retrieveChildWithKey(diffContext, nodeName, key) {
|
|
|
4005
4167
|
}
|
|
4006
4168
|
else {
|
|
4007
4169
|
const siblingsKey = getSideBufferKey(nodeName, key);
|
|
4008
|
-
|
|
4009
|
-
|
|
4170
|
+
const sibling = diffContext.vSiblings.get(siblingsKey);
|
|
4171
|
+
if (sibling) {
|
|
4172
|
+
vNodeWithKey = sibling;
|
|
4010
4173
|
diffContext.vSiblings.delete(siblingsKey);
|
|
4011
4174
|
}
|
|
4012
4175
|
}
|
|
@@ -4075,6 +4238,7 @@ function moveOrCreateKeyedNode(diffContext, nodeName, lookupKey, sideBufferKey,
|
|
|
4075
4238
|
// 1) Try to find the node among upcoming siblings
|
|
4076
4239
|
diffContext.vNewNode = retrieveChildWithKey(diffContext, nodeName, lookupKey);
|
|
4077
4240
|
if (diffContext.vNewNode) {
|
|
4241
|
+
vnode_insertBefore(diffContext.journal, parentForInsert, diffContext.vNewNode, diffContext.vCurrent);
|
|
4078
4242
|
diffContext.vCurrent = diffContext.vNewNode;
|
|
4079
4243
|
diffContext.vNewNode = null;
|
|
4080
4244
|
return false;
|
|
@@ -4118,7 +4282,7 @@ function expectVirtual(diffContext, type, jsxKey) {
|
|
|
4118
4282
|
return;
|
|
4119
4283
|
}
|
|
4120
4284
|
// For fragments without a key, always create a new virtual node (ensures rerender semantics)
|
|
4121
|
-
if (jsxKey === null) {
|
|
4285
|
+
if (jsxKey === null || diffContext.isCreationMode) {
|
|
4122
4286
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newVirtual()), diffContext.vCurrent && getInsertBefore(diffContext));
|
|
4123
4287
|
diffContext.vNewNode.key = jsxKey;
|
|
4124
4288
|
isDev && vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, type);
|
|
@@ -4247,7 +4411,7 @@ function expectText(diffContext, text) {
|
|
|
4247
4411
|
return;
|
|
4248
4412
|
}
|
|
4249
4413
|
}
|
|
4250
|
-
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newText(diffContext.container.document.createTextNode(text), text)), diffContext.vCurrent);
|
|
4414
|
+
vnode_insertBefore(diffContext.journal, diffContext.vParent, (diffContext.vNewNode = vnode_newText((import.meta.env.TEST ? diffContext.container.document : document).createTextNode(text), text)), diffContext.vCurrent);
|
|
4251
4415
|
}
|
|
4252
4416
|
/**
|
|
4253
4417
|
* Retrieve the key from the VNode.
|
|
@@ -4304,13 +4468,10 @@ function Projection() { }
|
|
|
4304
4468
|
function handleProps(host, jsxProps, vNodeProps, container) {
|
|
4305
4469
|
let shouldRender = false;
|
|
4306
4470
|
if (vNodeProps) {
|
|
4307
|
-
const effects = vNodeProps[_PROPS_HANDLER].$effects$;
|
|
4308
4471
|
const constPropsDifferent = handleChangedProps(jsxProps[_CONST_PROPS], vNodeProps[_CONST_PROPS], vNodeProps[_PROPS_HANDLER], container, false);
|
|
4309
4472
|
shouldRender ||= constPropsDifferent;
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
// don't mark as should render, effects will take care of it
|
|
4313
|
-
}
|
|
4473
|
+
const varPropsDifferent = handleChangedProps(jsxProps[_VAR_PROPS], vNodeProps[_VAR_PROPS], vNodeProps[_PROPS_HANDLER], container, true);
|
|
4474
|
+
shouldRender ||= varPropsDifferent;
|
|
4314
4475
|
// Update the owner after all props have been synced
|
|
4315
4476
|
vNodeProps[_OWNER] = jsxProps[_OWNER];
|
|
4316
4477
|
}
|
|
@@ -4335,7 +4496,6 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4335
4496
|
continue;
|
|
4336
4497
|
}
|
|
4337
4498
|
if (!dst || src[key] !== dst[key]) {
|
|
4338
|
-
changed = true;
|
|
4339
4499
|
if (triggerEffects) {
|
|
4340
4500
|
if (dst) {
|
|
4341
4501
|
// Update the value in dst BEFORE triggering effects
|
|
@@ -4343,7 +4503,11 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4343
4503
|
// Note: Value is not triggering effects, because we are modyfing direct VAR_PROPS object
|
|
4344
4504
|
dst[key] = src[key];
|
|
4345
4505
|
}
|
|
4346
|
-
triggerPropsProxyEffect(propsHandler, key);
|
|
4506
|
+
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
4507
|
+
if (!didTigger) {
|
|
4508
|
+
// If the effect was not triggered, then the prop has changed and we should rerender
|
|
4509
|
+
changed = true;
|
|
4510
|
+
}
|
|
4347
4511
|
}
|
|
4348
4512
|
else {
|
|
4349
4513
|
// Early return for const props (no effects)
|
|
@@ -4359,10 +4523,13 @@ function handleChangedProps(src, dst, propsHandler, container, triggerEffects =
|
|
|
4359
4523
|
continue;
|
|
4360
4524
|
}
|
|
4361
4525
|
if (!src || !_hasOwnProperty.call(src, key)) {
|
|
4362
|
-
changed = true;
|
|
4363
4526
|
if (triggerEffects) {
|
|
4364
4527
|
delete dst[key];
|
|
4365
|
-
triggerPropsProxyEffect(propsHandler, key);
|
|
4528
|
+
const didTigger = triggerPropsProxyEffect(propsHandler, key);
|
|
4529
|
+
if (!didTigger) {
|
|
4530
|
+
// If the effect was not triggered, then the prop has changed and we should rerender
|
|
4531
|
+
changed = true;
|
|
4532
|
+
}
|
|
4366
4533
|
}
|
|
4367
4534
|
}
|
|
4368
4535
|
}
|
|
@@ -4535,6 +4702,37 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
4535
4702
|
*/
|
|
4536
4703
|
vCursor.flags |= 32 /* VNodeFlags.Deleted */;
|
|
4537
4704
|
}
|
|
4705
|
+
function areWrappedSignalsEqual(oldSignal, newSignal) {
|
|
4706
|
+
if (oldSignal === newSignal) {
|
|
4707
|
+
return true;
|
|
4708
|
+
}
|
|
4709
|
+
return (newSignal.$func$ === oldSignal.$func$ && areArgumentsEqual(newSignal.$args$, oldSignal.$args$));
|
|
4710
|
+
}
|
|
4711
|
+
function areArgumentsEqual(oldArgs, newArgs) {
|
|
4712
|
+
if (oldArgs === newArgs) {
|
|
4713
|
+
return true;
|
|
4714
|
+
}
|
|
4715
|
+
if (!oldArgs || !newArgs || oldArgs.length !== newArgs.length) {
|
|
4716
|
+
return false;
|
|
4717
|
+
}
|
|
4718
|
+
for (let i = 0; i < oldArgs.length; i++) {
|
|
4719
|
+
if (oldArgs[i] !== newArgs[i]) {
|
|
4720
|
+
return false;
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
return true;
|
|
4724
|
+
}
|
|
4725
|
+
function containsWrappedSignal(data, signal) {
|
|
4726
|
+
if (!(signal instanceof WrappedSignalImpl)) {
|
|
4727
|
+
return false;
|
|
4728
|
+
}
|
|
4729
|
+
for (const item of data) {
|
|
4730
|
+
if (item instanceof WrappedSignalImpl && areWrappedSignalsEqual(item, signal)) {
|
|
4731
|
+
return true;
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
return false;
|
|
4735
|
+
}
|
|
4538
4736
|
/**
|
|
4539
4737
|
* This marks the property as immutable. It is needed for the QRLs so that QwikLoader can get a hold
|
|
4540
4738
|
* of them. This character must be `:` so that the `vnode_getAttr` can ignore them.
|
|
@@ -4542,6 +4740,41 @@ function markVNodeAsDeleted(vCursor) {
|
|
|
4542
4740
|
const HANDLER_PREFIX = ':';
|
|
4543
4741
|
let count = 0;
|
|
4544
4742
|
|
|
4743
|
+
/**
|
|
4744
|
+
* @internal
|
|
4745
|
+
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
4746
|
+
*/
|
|
4747
|
+
const useSequentialScope = () => {
|
|
4748
|
+
const iCtx = useInvokeContext();
|
|
4749
|
+
const hostElement = iCtx.$hostElement$;
|
|
4750
|
+
const host = hostElement;
|
|
4751
|
+
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
4752
|
+
if (seq === null) {
|
|
4753
|
+
seq = [];
|
|
4754
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
4755
|
+
}
|
|
4756
|
+
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
4757
|
+
if (seqIdx === null) {
|
|
4758
|
+
seqIdx = 0;
|
|
4759
|
+
}
|
|
4760
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
4761
|
+
while (seq.length <= seqIdx) {
|
|
4762
|
+
seq.push(undefined);
|
|
4763
|
+
}
|
|
4764
|
+
const set = (value) => {
|
|
4765
|
+
if (qDev && qSerialize) {
|
|
4766
|
+
verifySerializable(value);
|
|
4767
|
+
}
|
|
4768
|
+
return (seq[seqIdx] = value);
|
|
4769
|
+
};
|
|
4770
|
+
return {
|
|
4771
|
+
val: seq[seqIdx],
|
|
4772
|
+
set,
|
|
4773
|
+
i: seqIdx,
|
|
4774
|
+
iCtx,
|
|
4775
|
+
};
|
|
4776
|
+
};
|
|
4777
|
+
|
|
4545
4778
|
/** @internal */
|
|
4546
4779
|
const useResourceQrl = (qrl, opts) => {
|
|
4547
4780
|
const { val, set, i, iCtx } = useSequentialScope();
|
|
@@ -4627,6 +4860,7 @@ function getResourceValueAsPromise(props) {
|
|
|
4627
4860
|
const isBrowser = !isServerPlatform();
|
|
4628
4861
|
if (isBrowser) {
|
|
4629
4862
|
if (state === 'pending' && props.onPending) {
|
|
4863
|
+
resource.value.catch(() => { });
|
|
4630
4864
|
return Promise.resolve().then(useBindInvokeContext(props.onPending));
|
|
4631
4865
|
}
|
|
4632
4866
|
else if (state === 'rejected' && props.onRejected) {
|
|
@@ -4683,7 +4917,8 @@ const runResource = (task, container, host) => {
|
|
|
4683
4917
|
iCtx.$container$ = container;
|
|
4684
4918
|
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
4685
4919
|
const resource = task.$state$;
|
|
4686
|
-
|
|
4920
|
+
isDev &&
|
|
4921
|
+
assertDefined(resource, 'useResource: when running a resource, "task.resource" must be a defined.', task);
|
|
4687
4922
|
const track = trackFn(task, container);
|
|
4688
4923
|
const [cleanup, cleanups] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
4689
4924
|
const resourceTarget = unwrapStore(resource);
|
|
@@ -4776,33 +5011,6 @@ const runResource = (task, container, host) => {
|
|
|
4776
5011
|
return promise;
|
|
4777
5012
|
};
|
|
4778
5013
|
|
|
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
5014
|
/**
|
|
4807
5015
|
* Executes tasks for a vNode if the TASKS dirty bit is set. Tasks are stored in the ELEMENT_SEQ
|
|
4808
5016
|
* property and executed in order.
|
|
@@ -4947,8 +5155,8 @@ function clearNodePropData(vNode) {
|
|
|
4947
5155
|
const props = (vNode.props ||= {});
|
|
4948
5156
|
delete props[NODE_PROPS_DATA_KEY];
|
|
4949
5157
|
}
|
|
4950
|
-
function setNodeProp(domVNode, journal, property, value, isConst) {
|
|
4951
|
-
journal.push(createSetAttributeOperation(domVNode.node, property, value));
|
|
5158
|
+
function setNodeProp(domVNode, journal, property, value, isConst, scopedStyleIdPrefix = null) {
|
|
5159
|
+
journal.push(createSetAttributeOperation(domVNode.node, property, value, scopedStyleIdPrefix, (domVNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
4952
5160
|
if (!isConst) {
|
|
4953
5161
|
if (domVNode.props && value == null) {
|
|
4954
5162
|
delete domVNode.props[property];
|
|
@@ -4983,10 +5191,9 @@ function executeNodeProps(vNode, journal) {
|
|
|
4983
5191
|
// TODO: Handle async signals (promises) - need to track pending async prop data
|
|
4984
5192
|
value = value.value;
|
|
4985
5193
|
}
|
|
4986
|
-
//
|
|
4987
|
-
const serializedValue = serializeAttribute(property, value, nodeProp.scopedStyleIdPrefix);
|
|
5194
|
+
// Pass raw value and scopedStyleIdPrefix - serialization happens in flush
|
|
4988
5195
|
const isConst = nodeProp.isConst;
|
|
4989
|
-
setNodeProp(domVNode, journal, property,
|
|
5196
|
+
setNodeProp(domVNode, journal, property, value, isConst, nodeProp.scopedStyleIdPrefix);
|
|
4990
5197
|
}
|
|
4991
5198
|
// Clear pending prop data after processing
|
|
4992
5199
|
clearNodePropData(vNode);
|
|
@@ -5063,61 +5270,131 @@ const fastInsertBefore = (insertBeforeParent, target, insertBefore) => {
|
|
|
5063
5270
|
_insertBefore = insertBeforeParent.insertBefore;
|
|
5064
5271
|
}
|
|
5065
5272
|
_insertBefore.call(insertBeforeParent, target, insertBefore);
|
|
5066
|
-
};
|
|
5067
|
-
function _flushJournal(journal) {
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
}
|
|
5077
|
-
case 1 /* VNodeOperationType.Delete */: {
|
|
5078
|
-
operation.target.remove();
|
|
5079
|
-
break;
|
|
5080
|
-
}
|
|
5081
|
-
case 16 /* VNodeOperationType.SetText */: {
|
|
5082
|
-
operation.target.nodeValue = operation.text;
|
|
5083
|
-
break;
|
|
5273
|
+
};
|
|
5274
|
+
function _flushJournal(journal) {
|
|
5275
|
+
let batchParent = null;
|
|
5276
|
+
let batchBefore = null;
|
|
5277
|
+
let batchNodes = null;
|
|
5278
|
+
const batchSet = new Set();
|
|
5279
|
+
const flush = () => {
|
|
5280
|
+
if (batchNodes) {
|
|
5281
|
+
if (batchNodes.length === 1) {
|
|
5282
|
+
fastInsertBefore(batchParent, batchNodes[0], batchBefore);
|
|
5084
5283
|
}
|
|
5085
|
-
|
|
5086
|
-
const
|
|
5087
|
-
const
|
|
5088
|
-
const
|
|
5089
|
-
|
|
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 */);
|
|
5284
|
+
else {
|
|
5285
|
+
const doc = batchParent.ownerDocument || batchParent;
|
|
5286
|
+
const fragment = doc.createDocumentFragment();
|
|
5287
|
+
for (const node of batchNodes) {
|
|
5288
|
+
fragment.appendChild(node);
|
|
5096
5289
|
}
|
|
5097
|
-
|
|
5098
|
-
|
|
5290
|
+
fastInsertBefore(batchParent, fragment, batchBefore);
|
|
5291
|
+
}
|
|
5292
|
+
batchNodes = null;
|
|
5293
|
+
batchParent = null;
|
|
5294
|
+
batchBefore = null;
|
|
5295
|
+
batchSet.clear();
|
|
5296
|
+
}
|
|
5297
|
+
};
|
|
5298
|
+
for (const operation of journal) {
|
|
5299
|
+
if (operation instanceof InsertOrMoveOperation) {
|
|
5300
|
+
if (batchParent === operation.parent && batchBefore === operation.beforeTarget) {
|
|
5301
|
+
if (!batchNodes) {
|
|
5302
|
+
batchNodes = [];
|
|
5099
5303
|
}
|
|
5100
|
-
|
|
5101
|
-
|
|
5304
|
+
batchNodes.push(operation.target);
|
|
5305
|
+
batchSet.add(operation.target);
|
|
5306
|
+
continue;
|
|
5307
|
+
}
|
|
5308
|
+
if (batchNodes) {
|
|
5309
|
+
// If we have an existing batch, we need to check if the new operation conflicts with it.
|
|
5310
|
+
// 1. If we are inserting into the same parent but with a different "before" reference, we must flush.
|
|
5311
|
+
if (batchParent === operation.parent) {
|
|
5312
|
+
flush();
|
|
5313
|
+
batchParent = operation.parent;
|
|
5314
|
+
batchBefore = operation.beforeTarget;
|
|
5315
|
+
batchNodes = [operation.target];
|
|
5316
|
+
batchSet.add(operation.target);
|
|
5317
|
+
continue;
|
|
5102
5318
|
}
|
|
5103
|
-
|
|
5104
|
-
|
|
5319
|
+
// 2. If we are moving a node that is currently in the batch, or moving the node that is the reference for the batch.
|
|
5320
|
+
if (batchSet.has(operation.target) ||
|
|
5321
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5322
|
+
(batchParent && operation.target === batchParent)) {
|
|
5323
|
+
flush();
|
|
5324
|
+
batchParent = operation.parent;
|
|
5325
|
+
batchBefore = operation.beforeTarget;
|
|
5326
|
+
batchNodes = [operation.target];
|
|
5327
|
+
batchSet.add(operation.target);
|
|
5328
|
+
continue;
|
|
5105
5329
|
}
|
|
5106
|
-
|
|
5330
|
+
// 3. Otherwise, we can execute this operation immediately without flushing the current batch.
|
|
5331
|
+
// This is important for "interleaved" inserts, e.g. inserting <tr> into <tbody> (batched)
|
|
5332
|
+
// and then inserting <td> into that <tr> (immediate).
|
|
5333
|
+
// The <tr> is in memory, so inserting <td> into it is fine and doesn't require the <tr> to be in the DOM.
|
|
5107
5334
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5335
|
+
else {
|
|
5336
|
+
batchParent = operation.parent;
|
|
5337
|
+
batchBefore = operation.beforeTarget;
|
|
5338
|
+
batchNodes = [operation.target];
|
|
5339
|
+
batchSet.add(operation.target);
|
|
5340
|
+
continue;
|
|
5341
|
+
}
|
|
5342
|
+
fastInsertBefore(operation.parent, operation.target, operation.beforeTarget);
|
|
5343
|
+
continue;
|
|
5344
|
+
}
|
|
5345
|
+
if (operation instanceof DeleteOperation) {
|
|
5346
|
+
if (batchSet.has(operation.target) ||
|
|
5347
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5348
|
+
(batchParent && operation.target === batchParent)) {
|
|
5349
|
+
flush();
|
|
5350
|
+
}
|
|
5351
|
+
operation.target.remove();
|
|
5352
|
+
continue;
|
|
5353
|
+
}
|
|
5354
|
+
if (operation instanceof RemoveAllChildrenOperation) {
|
|
5355
|
+
if (batchSet.has(operation.target) ||
|
|
5356
|
+
(batchBefore && operation.target === batchBefore) ||
|
|
5357
|
+
(batchParent && operation.target === batchParent)) {
|
|
5358
|
+
flush();
|
|
5359
|
+
}
|
|
5360
|
+
// Removing children of a node in the batch is safe (clears detached node)
|
|
5361
|
+
const removeParent = operation.target;
|
|
5362
|
+
removeParent.textContent = '';
|
|
5363
|
+
continue;
|
|
5364
|
+
}
|
|
5365
|
+
if (operation instanceof SetTextOperation) {
|
|
5366
|
+
operation.target.nodeValue = operation.text;
|
|
5367
|
+
}
|
|
5368
|
+
else if (operation instanceof SetAttributeOperation) {
|
|
5369
|
+
const element = operation.target;
|
|
5370
|
+
const attrName = operation.attrName;
|
|
5371
|
+
const rawValue = operation.attrValue;
|
|
5372
|
+
const attrValue = rawValue != null
|
|
5373
|
+
? serializeAttribute(attrName, rawValue, operation.scopedStyleIdPrefix)
|
|
5374
|
+
: null;
|
|
5375
|
+
const shouldRemove = attrValue == null || attrValue === false;
|
|
5376
|
+
if (isBooleanAttr(element, attrName)) {
|
|
5377
|
+
element[attrName] = parseBoolean(attrValue);
|
|
5378
|
+
}
|
|
5379
|
+
else if (attrName === dangerouslySetInnerHTML) {
|
|
5380
|
+
if (batchParent === element) {
|
|
5381
|
+
flush();
|
|
5116
5382
|
}
|
|
5117
|
-
|
|
5383
|
+
element.innerHTML = attrValue;
|
|
5384
|
+
element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
|
|
5385
|
+
}
|
|
5386
|
+
else if (shouldRemove) {
|
|
5387
|
+
element.removeAttribute(attrName);
|
|
5388
|
+
}
|
|
5389
|
+
else if (attrName === 'value' && attrName in element) {
|
|
5390
|
+
element.value = attrValue;
|
|
5391
|
+
}
|
|
5392
|
+
else {
|
|
5393
|
+
directSetAttribute(element, attrName, attrValue, operation.isSvg);
|
|
5118
5394
|
}
|
|
5119
5395
|
}
|
|
5120
5396
|
}
|
|
5397
|
+
flush();
|
|
5121
5398
|
}
|
|
5122
5399
|
function executeAfterFlush(container, cursorData) {
|
|
5123
5400
|
const visibleTasks = cursorData.afterFlushTasks;
|
|
@@ -5253,7 +5530,7 @@ function processCursorQueue(options = {
|
|
|
5253
5530
|
*/
|
|
5254
5531
|
function walkCursor(cursor, options) {
|
|
5255
5532
|
const { timeBudget } = options;
|
|
5256
|
-
const
|
|
5533
|
+
const isRunningOnServer = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
5257
5534
|
const startTime = performance.now();
|
|
5258
5535
|
const cursorData = getCursorData(cursor);
|
|
5259
5536
|
// Check if cursor is blocked by a promise
|
|
@@ -5262,10 +5539,10 @@ function walkCursor(cursor, options) {
|
|
|
5262
5539
|
return;
|
|
5263
5540
|
}
|
|
5264
5541
|
const container = cursorData.container;
|
|
5265
|
-
assertDefined(container, 'Cursor container not found');
|
|
5542
|
+
isDev && assertDefined(container, 'Cursor container not found');
|
|
5266
5543
|
// Check if cursor is already complete
|
|
5267
5544
|
if (!cursor.dirty) {
|
|
5268
|
-
finishWalk(container, cursor, cursorData,
|
|
5545
|
+
finishWalk(container, cursor, cursorData, isRunningOnServer);
|
|
5269
5546
|
return;
|
|
5270
5547
|
}
|
|
5271
5548
|
const journal = (cursorData.journal ||= []);
|
|
@@ -5273,7 +5550,7 @@ function walkCursor(cursor, options) {
|
|
|
5273
5550
|
let currentVNode = null;
|
|
5274
5551
|
while ((currentVNode = cursorData.position)) {
|
|
5275
5552
|
// Check time budget (only for DOM, not SSR)
|
|
5276
|
-
if (!
|
|
5553
|
+
if (!isRunningOnServer && !import.meta.env.TEST) {
|
|
5277
5554
|
const elapsed = performance.now() - startTime;
|
|
5278
5555
|
if (elapsed >= timeBudget) {
|
|
5279
5556
|
// Schedule continuation as macrotask to actually yield to browser
|
|
@@ -5356,8 +5633,9 @@ function walkCursor(cursor, options) {
|
|
|
5356
5633
|
return;
|
|
5357
5634
|
}
|
|
5358
5635
|
}
|
|
5359
|
-
|
|
5360
|
-
|
|
5636
|
+
isDev &&
|
|
5637
|
+
assertFalse(!!(cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */ && !cursorData.position), 'Cursor is still dirty and position is not set after walking');
|
|
5638
|
+
finishWalk(container, cursor, cursorData, isRunningOnServer);
|
|
5361
5639
|
}
|
|
5362
5640
|
function finishWalk(container, cursor, cursorData, isServer) {
|
|
5363
5641
|
if (!(cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */)) {
|
|
@@ -5377,7 +5655,7 @@ function finishWalk(container, cursor, cursorData, isServer) {
|
|
|
5377
5655
|
function resolveCursor(container) {
|
|
5378
5656
|
// TODO streaming as a cursor? otherwise we need to wait separately for it
|
|
5379
5657
|
// or just ignore and resolve manually
|
|
5380
|
-
if (container.$cursorCount$ === 0) {
|
|
5658
|
+
if (container.$cursorCount$ === 0 && container.$pausedCursorCount$ === 0) {
|
|
5381
5659
|
container.$resolveRenderPromise$();
|
|
5382
5660
|
container.$renderPromise$ = null;
|
|
5383
5661
|
}
|
|
@@ -5441,6 +5719,7 @@ function getNextVNode(vNode, cursor) {
|
|
|
5441
5719
|
// all array items checked, children are no longer dirty
|
|
5442
5720
|
parent.dirty &= -33 /* ChoreBits.CHILDREN */;
|
|
5443
5721
|
parent.dirtyChildren = null;
|
|
5722
|
+
parent.nextDirtyChildIndex = 0;
|
|
5444
5723
|
return getNextVNode(parent, cursor);
|
|
5445
5724
|
}
|
|
5446
5725
|
|
|
@@ -5529,8 +5808,13 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
5529
5808
|
promise = result;
|
|
5530
5809
|
}
|
|
5531
5810
|
}
|
|
5532
|
-
|
|
5533
|
-
|
|
5811
|
+
// In SSR, we don't handle the COMPONENT bit here.
|
|
5812
|
+
// During initial render, if a task completes and marks the component dirty,
|
|
5813
|
+
// we want to leave the COMPONENT bit set so that executeComponent can detect
|
|
5814
|
+
// it after $waitOn$ completes and re-execute the component function.
|
|
5815
|
+
// executeComponent will clear the bit after re-executing.
|
|
5816
|
+
// Clear all dirty bits EXCEPT COMPONENT
|
|
5817
|
+
ssrNode.dirty &= -124;
|
|
5534
5818
|
if (promise) {
|
|
5535
5819
|
return promise;
|
|
5536
5820
|
}
|
|
@@ -5649,7 +5933,7 @@ function findAndPropagateToBlockingCursor(vNode) {
|
|
|
5649
5933
|
return false;
|
|
5650
5934
|
}
|
|
5651
5935
|
function isSsrNodeGuard(_vNode) {
|
|
5652
|
-
return isServerPlatform();
|
|
5936
|
+
return import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
5653
5937
|
}
|
|
5654
5938
|
/**
|
|
5655
5939
|
* Marks a vNode as dirty and propagates dirty bits up the tree.
|
|
@@ -5855,21 +6139,22 @@ const fastGetter = (prototype, name) => {
|
|
|
5855
6139
|
*/
|
|
5856
6140
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
5857
6141
|
const vnode_newElement = (element, elementName, key = null) => {
|
|
5858
|
-
assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
6142
|
+
isDev && assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
5859
6143
|
const vnode = new ElementVNode(key, 1 /* VNodeFlags.Element */ | 8 /* VNodeFlags.Inflated */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5860
6144
|
null, null, null, null, null, null, element, elementName);
|
|
5861
6145
|
element.vNode = vnode;
|
|
5862
6146
|
return vnode;
|
|
5863
6147
|
};
|
|
5864
6148
|
const vnode_newUnMaterializedElement = (element) => {
|
|
5865
|
-
assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
6149
|
+
isDev && assertEqual(fastNodeType(element), 1 /* ELEMENT_NODE */, 'Expecting element node.');
|
|
5866
6150
|
const vnode = new ElementVNode(null, 1 /* VNodeFlags.Element */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5867
6151
|
null, null, null, null, undefined, undefined, element, undefined);
|
|
5868
6152
|
element.vNode = vnode;
|
|
5869
6153
|
return vnode;
|
|
5870
6154
|
};
|
|
5871
6155
|
const vnode_newSharedText = (previousTextNode, sharedTextNode, textContent) => {
|
|
5872
|
-
|
|
6156
|
+
isDev &&
|
|
6157
|
+
sharedTextNode &&
|
|
5873
6158
|
assertEqual(fastNodeType(sharedTextNode), 3 /* TEXT_NODE */, 'Expecting text node.');
|
|
5874
6159
|
const vnode = new TextVNode(4 /* VNodeFlags.Text */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flag
|
|
5875
6160
|
null, // Parent
|
|
@@ -5886,18 +6171,18 @@ const vnode_newText = (textNode, textContent) => {
|
|
|
5886
6171
|
null, textNode, // TextNode
|
|
5887
6172
|
textContent // Text Content
|
|
5888
6173
|
);
|
|
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.');
|
|
6174
|
+
isDev && assertEqual(fastNodeType(textNode), 3 /* TEXT_NODE */, 'Expecting text node.');
|
|
6175
|
+
isDev && assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6176
|
+
isDev && assertTrue(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6177
|
+
isDev && assertFalse(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5893
6178
|
return vnode;
|
|
5894
6179
|
};
|
|
5895
6180
|
const vnode_newVirtual = () => {
|
|
5896
6181
|
const vnode = new VirtualVNode(null, 2 /* VNodeFlags.Virtual */ | (-1 << 9 /* VNodeFlagsIndex.shift */), // Flags
|
|
5897
6182
|
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.');
|
|
6183
|
+
isDev && assertFalse(vnode_isElementVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6184
|
+
isDev && assertFalse(vnode_isTextVNode(vnode), 'Incorrect format of TextVNode.');
|
|
6185
|
+
isDev && assertTrue(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
5901
6186
|
return vnode;
|
|
5902
6187
|
};
|
|
5903
6188
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -5905,16 +6190,16 @@ const vnode_isVNode = (vNode) => {
|
|
|
5905
6190
|
return vNode instanceof VNode;
|
|
5906
6191
|
};
|
|
5907
6192
|
const vnode_isElementVNode = (vNode) => {
|
|
5908
|
-
return vNode
|
|
6193
|
+
return (vNode.flags & 1 /* VNodeFlags.Element */) === 1 /* VNodeFlags.Element */;
|
|
5909
6194
|
};
|
|
5910
6195
|
const vnode_isElementOrTextVNode = (vNode) => {
|
|
5911
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6196
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5912
6197
|
const flag = vNode.flags;
|
|
5913
6198
|
return (flag & 5 /* VNodeFlags.ELEMENT_OR_TEXT_MASK */) !== 0;
|
|
5914
6199
|
};
|
|
5915
6200
|
/** @internal */
|
|
5916
6201
|
const vnode_isMaterialized = (vNode) => {
|
|
5917
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6202
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5918
6203
|
const flag = vNode.flags;
|
|
5919
6204
|
return ((flag & 1 /* VNodeFlags.Element */) === 1 /* VNodeFlags.Element */ &&
|
|
5920
6205
|
vNode.firstChild !== undefined &&
|
|
@@ -5922,27 +6207,30 @@ const vnode_isMaterialized = (vNode) => {
|
|
|
5922
6207
|
};
|
|
5923
6208
|
/** @internal */
|
|
5924
6209
|
const vnode_isTextVNode = (vNode) => {
|
|
5925
|
-
return vNode
|
|
6210
|
+
return (vNode.flags & 4 /* VNodeFlags.Text */) === 4 /* VNodeFlags.Text */;
|
|
5926
6211
|
};
|
|
5927
6212
|
/** @internal */
|
|
5928
6213
|
const vnode_isVirtualVNode = (vNode) => {
|
|
5929
|
-
return vNode
|
|
6214
|
+
return (vNode.flags & 2 /* VNodeFlags.Virtual */) === 2 /* VNodeFlags.Virtual */;
|
|
5930
6215
|
};
|
|
5931
6216
|
const vnode_isProjection = (vNode) => {
|
|
5932
|
-
assertDefined(vNode, 'Missing vNode');
|
|
6217
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
5933
6218
|
const flag = vNode.flags;
|
|
5934
6219
|
return ((flag & 2 /* VNodeFlags.Virtual */) === 2 /* VNodeFlags.Virtual */ && vnode_getProp(vNode, QSlot, null) !== null);
|
|
5935
6220
|
};
|
|
5936
6221
|
const ensureTextVNode = (vNode) => {
|
|
5937
|
-
|
|
6222
|
+
isDev &&
|
|
6223
|
+
assertTrue(vnode_isTextVNode(vNode), 'Expecting TextVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5938
6224
|
return vNode;
|
|
5939
6225
|
};
|
|
5940
6226
|
const ensureElementOrVirtualVNode = (vNode) => {
|
|
5941
|
-
assertDefined(vNode, 'Missing vNode');
|
|
5942
|
-
|
|
6227
|
+
isDev && assertDefined(vNode, 'Missing vNode');
|
|
6228
|
+
isDev &&
|
|
6229
|
+
assertTrue((vNode.flags & 3 /* VNodeFlags.ELEMENT_OR_VIRTUAL_MASK */) !== 0, 'Expecting ElementVNode or VirtualVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5943
6230
|
};
|
|
5944
6231
|
const ensureElementVNode = (vNode) => {
|
|
5945
|
-
|
|
6232
|
+
isDev &&
|
|
6233
|
+
assertTrue(vnode_isElementVNode(vNode), 'Expecting ElementVNode was: ' + vnode_getNodeTypeName(vNode));
|
|
5946
6234
|
return vNode;
|
|
5947
6235
|
};
|
|
5948
6236
|
const vnode_getNodeTypeName = (vNode) => {
|
|
@@ -5972,20 +6260,21 @@ const vnode_getProp = (vNode, key, getObject) => {
|
|
|
5972
6260
|
return null;
|
|
5973
6261
|
};
|
|
5974
6262
|
const vnode_setProp = (vNode, key, value) => {
|
|
5975
|
-
if (
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
vNode.props[key] = value;
|
|
5982
|
-
}
|
|
6263
|
+
if (value == null && vNode.props) {
|
|
6264
|
+
delete vNode.props[key];
|
|
6265
|
+
}
|
|
6266
|
+
else {
|
|
6267
|
+
vNode.props ||= {};
|
|
6268
|
+
vNode.props[key] = value;
|
|
5983
6269
|
}
|
|
5984
6270
|
};
|
|
5985
|
-
const vnode_setAttr = (journal, vNode, key, value) => {
|
|
6271
|
+
const vnode_setAttr = (journal, vNode, key, value, scopedStyleIdPrefix = null) => {
|
|
5986
6272
|
if (vnode_isElementVNode(vNode)) {
|
|
6273
|
+
import.meta.env.TEST &&
|
|
6274
|
+
scopedStyleIdPrefix &&
|
|
6275
|
+
vnode_setProp(vNode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
5987
6276
|
vnode_setProp(vNode, key, value);
|
|
5988
|
-
addVNodeOperation(journal, createSetAttributeOperation(vNode.node, key, value));
|
|
6277
|
+
addVNodeOperation(journal, createSetAttributeOperation(vNode.node, key, value, scopedStyleIdPrefix, (vNode.flags & 128 /* VNodeFlags.NS_svg */) !== 0));
|
|
5989
6278
|
}
|
|
5990
6279
|
};
|
|
5991
6280
|
const vnode_ensureElementKeyInflated = (vnode) => {
|
|
@@ -6218,7 +6507,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
|
|
|
6218
6507
|
const flags = textVNode.flags;
|
|
6219
6508
|
if ((flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
6220
6509
|
const parentNode = vnode_getDomParent(vnode, true);
|
|
6221
|
-
assertDefined(parentNode, 'Missing parent node.');
|
|
6510
|
+
isDev && assertDefined(parentNode, 'Missing parent node.');
|
|
6222
6511
|
const sharedTextNode = textVNode.node;
|
|
6223
6512
|
const doc = fastOwnerDocument(parentNode);
|
|
6224
6513
|
// Walk the previous siblings and inflate them.
|
|
@@ -6228,7 +6517,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
|
|
|
6228
6517
|
// case we know that the next node MUST be either NULL or an Element.
|
|
6229
6518
|
const node = vnode_getDomSibling(vnode, true, true);
|
|
6230
6519
|
const insertBeforeNode = sharedTextNode ||
|
|
6231
|
-
((node
|
|
6520
|
+
((node && vnode_isElementVNode(node) ? node.node : node?.node) || null);
|
|
6232
6521
|
let lastPreviousTextNode = insertBeforeNode;
|
|
6233
6522
|
while (vCursor && vnode_isTextVNode(vCursor)) {
|
|
6234
6523
|
if ((vCursor.flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
@@ -6268,7 +6557,7 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6268
6557
|
let elementOffset = -1;
|
|
6269
6558
|
let refElement;
|
|
6270
6559
|
if (typeof id === 'string') {
|
|
6271
|
-
assertDefined(qVNodeRefs, 'Missing qVNodeRefs.');
|
|
6560
|
+
isDev && assertDefined(qVNodeRefs, 'Missing qVNodeRefs.');
|
|
6272
6561
|
elementOffset = parseInt(id);
|
|
6273
6562
|
refElement = qVNodeRefs.get(elementOffset);
|
|
6274
6563
|
}
|
|
@@ -6279,9 +6568,10 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6279
6568
|
return vNode;
|
|
6280
6569
|
}
|
|
6281
6570
|
}
|
|
6282
|
-
assertDefined(refElement, 'Missing refElement.');
|
|
6571
|
+
isDev && assertDefined(refElement, 'Missing refElement.');
|
|
6283
6572
|
if (!vnode_isVNode(refElement)) {
|
|
6284
|
-
|
|
6573
|
+
isDev &&
|
|
6574
|
+
assertTrue(containerElement.contains(refElement), `Couldn't find the element inside the container while locating the VNode.`);
|
|
6285
6575
|
// We need to find the vnode.
|
|
6286
6576
|
let parent = refElement;
|
|
6287
6577
|
const elementPath = [refElement];
|
|
@@ -6329,10 +6619,10 @@ const vnode_locate = (rootVNode, id) => {
|
|
|
6329
6619
|
};
|
|
6330
6620
|
const vnode_getChildWithIdx = (vNode, childIdx) => {
|
|
6331
6621
|
let child = vnode_getFirstChild(vNode);
|
|
6332
|
-
assertDefined(child, 'Missing child.');
|
|
6622
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6333
6623
|
while (child.flags >>> 9 /* VNodeFlagsIndex.shift */ !== childIdx) {
|
|
6334
6624
|
child = child.nextSibling;
|
|
6335
|
-
assertDefined(child, 'Missing child.');
|
|
6625
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6336
6626
|
}
|
|
6337
6627
|
return child;
|
|
6338
6628
|
};
|
|
@@ -6340,7 +6630,7 @@ const vNodeStack = [];
|
|
|
6340
6630
|
const vnode_getVNodeForChildNode = (vNode, childElement) => {
|
|
6341
6631
|
ensureElementVNode(vNode);
|
|
6342
6632
|
let child = vnode_getFirstChild(vNode);
|
|
6343
|
-
assertDefined(child, 'Missing child.');
|
|
6633
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6344
6634
|
while (child && (child instanceof ElementVNode ? child.node !== childElement : true)) {
|
|
6345
6635
|
if (vnode_isVirtualVNode(child)) {
|
|
6346
6636
|
const next = child.nextSibling;
|
|
@@ -6362,13 +6652,13 @@ const vnode_getVNodeForChildNode = (vNode, childElement) => {
|
|
|
6362
6652
|
child = next || vNodeStack.pop();
|
|
6363
6653
|
}
|
|
6364
6654
|
}
|
|
6365
|
-
assertDefined(child, 'Missing child.');
|
|
6655
|
+
isDev && assertDefined(child, 'Missing child.');
|
|
6366
6656
|
}
|
|
6367
6657
|
while (vNodeStack.length) {
|
|
6368
6658
|
vNodeStack.pop();
|
|
6369
6659
|
}
|
|
6370
6660
|
ensureElementVNode(child);
|
|
6371
|
-
assertEqual(child.node, childElement, 'Child not found.');
|
|
6661
|
+
isDev && assertEqual(child.node, childElement, 'Child not found.');
|
|
6372
6662
|
// console.log('FOUND', child[VNodeProps.node]?.outerHTML);
|
|
6373
6663
|
return child;
|
|
6374
6664
|
};
|
|
@@ -6543,7 +6833,7 @@ const vnode_getDomParentVNode = (vnode, includeProjection) => {
|
|
|
6543
6833
|
return vnode;
|
|
6544
6834
|
};
|
|
6545
6835
|
const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
6546
|
-
assertEqual(vParent, vToRemove.parent, 'Parent mismatch.');
|
|
6836
|
+
isDev && assertEqual(vParent, vToRemove.parent, 'Parent mismatch.');
|
|
6547
6837
|
if (vnode_isTextVNode(vToRemove)) {
|
|
6548
6838
|
vnode_ensureTextInflated(journal, vToRemove);
|
|
6549
6839
|
}
|
|
@@ -6580,7 +6870,7 @@ const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
|
6580
6870
|
vToRemove.nextSibling = null;
|
|
6581
6871
|
};
|
|
6582
6872
|
const vnode_truncate = (journal, vParent, vDelete, removeDOM = true) => {
|
|
6583
|
-
assertDefined(vDelete, 'Missing vDelete.');
|
|
6873
|
+
isDev && assertDefined(vDelete, 'Missing vDelete.');
|
|
6584
6874
|
const parent = vnode_getDomParent(vParent, true);
|
|
6585
6875
|
if (parent && removeDOM) {
|
|
6586
6876
|
if (vnode_isElementVNode(vParent)) {
|
|
@@ -6699,8 +6989,8 @@ const ensureMaterialized = (vnode) => {
|
|
|
6699
6989
|
vFirstChild = vnode_materialize(vParent);
|
|
6700
6990
|
}
|
|
6701
6991
|
}
|
|
6702
|
-
assertTrue(vParent.firstChild !== undefined, 'Did not materialize.');
|
|
6703
|
-
assertTrue(vParent.lastChild !== undefined, 'Did not materialize.');
|
|
6992
|
+
isDev && assertTrue(vParent.firstChild !== undefined, 'Did not materialize.');
|
|
6993
|
+
isDev && assertTrue(vParent.lastChild !== undefined, 'Did not materialize.');
|
|
6704
6994
|
return vFirstChild;
|
|
6705
6995
|
};
|
|
6706
6996
|
let _fastHasAttribute = null;
|
|
@@ -7018,8 +7308,11 @@ function vnode_toString(depth = 20, offset = '', materialize = false, siblings =
|
|
|
7018
7308
|
else if (vnode_isVirtualVNode(vnode)) {
|
|
7019
7309
|
const idx = vnode.flags >>> 9 /* VNodeFlagsIndex.shift */;
|
|
7020
7310
|
const attrs = ['[' + String(idx) + ']'];
|
|
7311
|
+
if (vnode.dirty) {
|
|
7312
|
+
attrs.push(` dirty:${vnode.dirty}`);
|
|
7313
|
+
}
|
|
7021
7314
|
vnode_getAttrKeys(vnode).forEach((key) => {
|
|
7022
|
-
if (key !== DEBUG_TYPE) {
|
|
7315
|
+
if (key !== DEBUG_TYPE && key !== debugStyleScopeIdPrefixAttr) {
|
|
7023
7316
|
const value = vnode_getProp(vnode, key, null);
|
|
7024
7317
|
attrs.push(' ' + key + '=' + qwikDebugToString(value));
|
|
7025
7318
|
}
|
|
@@ -7309,6 +7602,79 @@ const vnode_getProjectionParentComponent = (vHost) => {
|
|
|
7309
7602
|
return vHost;
|
|
7310
7603
|
};
|
|
7311
7604
|
|
|
7605
|
+
let _locale = undefined;
|
|
7606
|
+
let localAsyncStore;
|
|
7607
|
+
if (isServer) {
|
|
7608
|
+
import('node:async_hooks')
|
|
7609
|
+
.then((module) => {
|
|
7610
|
+
localAsyncStore = new module.AsyncLocalStorage();
|
|
7611
|
+
})
|
|
7612
|
+
.catch(() => {
|
|
7613
|
+
// ignore if AsyncLocalStorage is not available
|
|
7614
|
+
});
|
|
7615
|
+
}
|
|
7616
|
+
/**
|
|
7617
|
+
* Retrieve the current locale.
|
|
7618
|
+
*
|
|
7619
|
+
* If no current locale and there is no `defaultLocale` the function throws an error.
|
|
7620
|
+
*
|
|
7621
|
+
* @returns The locale.
|
|
7622
|
+
* @public
|
|
7623
|
+
*/
|
|
7624
|
+
function getLocale(defaultLocale) {
|
|
7625
|
+
// Prefer per-request locale from local AsyncLocalStorage if available (server-side)
|
|
7626
|
+
if (localAsyncStore) {
|
|
7627
|
+
const locale = localAsyncStore.getStore();
|
|
7628
|
+
if (locale) {
|
|
7629
|
+
return locale;
|
|
7630
|
+
}
|
|
7631
|
+
}
|
|
7632
|
+
if (_locale === undefined) {
|
|
7633
|
+
const ctx = tryGetInvokeContext();
|
|
7634
|
+
if (ctx && ctx.$locale$) {
|
|
7635
|
+
return ctx.$locale$;
|
|
7636
|
+
}
|
|
7637
|
+
if (defaultLocale !== undefined) {
|
|
7638
|
+
return defaultLocale;
|
|
7639
|
+
}
|
|
7640
|
+
throw new Error('Reading `locale` outside of context.');
|
|
7641
|
+
}
|
|
7642
|
+
return _locale;
|
|
7643
|
+
}
|
|
7644
|
+
/**
|
|
7645
|
+
* Override the `getLocale` with `lang` within the `fn` execution.
|
|
7646
|
+
*
|
|
7647
|
+
* @public
|
|
7648
|
+
*/
|
|
7649
|
+
function withLocale(locale, fn) {
|
|
7650
|
+
if (localAsyncStore) {
|
|
7651
|
+
return localAsyncStore.run(locale, fn);
|
|
7652
|
+
}
|
|
7653
|
+
const previousLang = _locale;
|
|
7654
|
+
try {
|
|
7655
|
+
_locale = locale;
|
|
7656
|
+
return fn();
|
|
7657
|
+
}
|
|
7658
|
+
finally {
|
|
7659
|
+
_locale = previousLang;
|
|
7660
|
+
}
|
|
7661
|
+
}
|
|
7662
|
+
/**
|
|
7663
|
+
* Globally set a lang.
|
|
7664
|
+
*
|
|
7665
|
+
* This can be used only in browser. Server execution requires that each request could potentially
|
|
7666
|
+
* be a different lang, therefore setting a global lang would produce incorrect responses.
|
|
7667
|
+
*
|
|
7668
|
+
* @public
|
|
7669
|
+
*/
|
|
7670
|
+
function setLocale(locale) {
|
|
7671
|
+
if (localAsyncStore) {
|
|
7672
|
+
localAsyncStore.enterWith(locale);
|
|
7673
|
+
return;
|
|
7674
|
+
}
|
|
7675
|
+
_locale = locale;
|
|
7676
|
+
}
|
|
7677
|
+
|
|
7312
7678
|
let _context;
|
|
7313
7679
|
const tryGetInvokeContext = () => {
|
|
7314
7680
|
if (!_context) {
|
|
@@ -7336,8 +7702,8 @@ const useInvokeContext = () => {
|
|
|
7336
7702
|
if (!ctx || ctx.$event$ !== RenderEvent) {
|
|
7337
7703
|
throw qError(10 /* QError.useInvokeContext */);
|
|
7338
7704
|
}
|
|
7339
|
-
assertDefined(ctx.$hostElement$, `invoke: $hostElement$ must be defined`, ctx);
|
|
7340
|
-
assertDefined(ctx.$effectSubscriber$, `invoke: $effectSubscriber$ must be defined`, ctx);
|
|
7705
|
+
isDev && assertDefined(ctx.$hostElement$, `invoke: $hostElement$ must be defined`, ctx);
|
|
7706
|
+
isDev && assertDefined(ctx.$effectSubscriber$, `invoke: $effectSubscriber$ must be defined`, ctx);
|
|
7341
7707
|
return ctx;
|
|
7342
7708
|
};
|
|
7343
7709
|
function useBindInvokeContext(fn) {
|
|
@@ -7404,24 +7770,37 @@ function newInvokeContext(locale, hostElement, event, url) {
|
|
|
7404
7770
|
return ctx;
|
|
7405
7771
|
}
|
|
7406
7772
|
/**
|
|
7407
|
-
*
|
|
7773
|
+
* Get the value of the expression without tracking listeners. A function will be invoked, signals
|
|
7774
|
+
* will return their value, and stores will be unwrapped (they return the backing object).
|
|
7408
7775
|
*
|
|
7776
|
+
* When you pass a function, you can also pass additional arguments that the function will receive.
|
|
7777
|
+
*
|
|
7778
|
+
* Note that stores are not unwrapped recursively.
|
|
7779
|
+
*
|
|
7780
|
+
* @param expr - The function or object to evaluate without tracking.
|
|
7781
|
+
* @param args - Additional arguments to pass when `expr` is a function.
|
|
7409
7782
|
* @public
|
|
7410
7783
|
*/
|
|
7411
|
-
const untrack = (
|
|
7412
|
-
if (
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7784
|
+
const untrack = (expr, ...args) => {
|
|
7785
|
+
if (typeof expr === 'function') {
|
|
7786
|
+
if (_context) {
|
|
7787
|
+
const sub = _context.$effectSubscriber$;
|
|
7788
|
+
try {
|
|
7789
|
+
_context.$effectSubscriber$ = undefined;
|
|
7790
|
+
return expr(...args);
|
|
7791
|
+
}
|
|
7792
|
+
finally {
|
|
7793
|
+
_context.$effectSubscriber$ = sub;
|
|
7794
|
+
}
|
|
7417
7795
|
}
|
|
7418
|
-
|
|
7419
|
-
|
|
7796
|
+
else {
|
|
7797
|
+
return expr(...args);
|
|
7420
7798
|
}
|
|
7421
7799
|
}
|
|
7422
|
-
|
|
7423
|
-
return
|
|
7800
|
+
if (isSignal(expr)) {
|
|
7801
|
+
return expr.untrackedValue;
|
|
7424
7802
|
}
|
|
7803
|
+
return unwrapStore(expr);
|
|
7425
7804
|
};
|
|
7426
7805
|
const trackInvocation = /*#__PURE__*/ newRenderInvokeContext(undefined, undefined, undefined);
|
|
7427
7806
|
/**
|
|
@@ -7556,7 +7935,8 @@ const _waitUntilRendered = (elm) => {
|
|
|
7556
7935
|
*/
|
|
7557
7936
|
// </docs>
|
|
7558
7937
|
const createContextId = (name) => {
|
|
7559
|
-
|
|
7938
|
+
isDev &&
|
|
7939
|
+
assertTrue(/^[\w/.-]+$/.test(name), 'Context name must only contain A-Z,a-z,0-9,_,.,-', name);
|
|
7560
7940
|
return /*#__PURE__*/ Object.freeze({
|
|
7561
7941
|
id: fromCamelToKebabCase(name),
|
|
7562
7942
|
});
|
|
@@ -7803,6 +8183,7 @@ const _typeIdNames = [
|
|
|
7803
8183
|
'JSXNode',
|
|
7804
8184
|
'PropsProxy',
|
|
7805
8185
|
'SubscriptionData',
|
|
8186
|
+
'EffectSubscription',
|
|
7806
8187
|
];
|
|
7807
8188
|
|
|
7808
8189
|
function qrlToString(serializationContext, value, raw) {
|
|
@@ -7860,13 +8241,16 @@ function qrlToString(serializationContext, value, raw) {
|
|
|
7860
8241
|
return qrlStringInline;
|
|
7861
8242
|
}
|
|
7862
8243
|
function createQRLWithBackChannel(chunk, symbol, captureIds) {
|
|
7863
|
-
let
|
|
8244
|
+
let qrlImporter = null;
|
|
7864
8245
|
if (isDev && chunk === QRL_RUNTIME_CHUNK) {
|
|
7865
8246
|
const backChannel = globalThis.__qrl_back_channel__;
|
|
7866
|
-
assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
7867
|
-
|
|
8247
|
+
isDev && assertDefined(backChannel, 'Missing QRL_RUNTIME_CHUNK');
|
|
8248
|
+
const fn = backChannel.get(symbol);
|
|
8249
|
+
if (fn) {
|
|
8250
|
+
qrlImporter = () => Promise.resolve({ [symbol]: fn });
|
|
8251
|
+
}
|
|
7868
8252
|
}
|
|
7869
|
-
return createQRL(chunk, symbol,
|
|
8253
|
+
return createQRL(chunk, symbol, null, qrlImporter, captureIds, null);
|
|
7870
8254
|
}
|
|
7871
8255
|
/** Parses "chunk#hash[...rootRef]" */
|
|
7872
8256
|
function parseQRL(qrl) {
|
|
@@ -7978,7 +8362,7 @@ const allocate = (container, typeId, value) => {
|
|
|
7978
8362
|
case 30 /* TypeIds.FormData */:
|
|
7979
8363
|
return new FormData();
|
|
7980
8364
|
case 31 /* TypeIds.JSXNode */:
|
|
7981
|
-
return new JSXNodeImpl(null);
|
|
8365
|
+
return new JSXNodeImpl(null, null, null, null, null);
|
|
7982
8366
|
case 11 /* TypeIds.BigInt */:
|
|
7983
8367
|
return BigInt(value);
|
|
7984
8368
|
case 16 /* TypeIds.Set */:
|
|
@@ -8042,6 +8426,8 @@ const allocate = (container, typeId, value) => {
|
|
|
8042
8426
|
}
|
|
8043
8427
|
case 33 /* TypeIds.SubscriptionData */:
|
|
8044
8428
|
return new SubscriptionData({});
|
|
8429
|
+
case 34 /* TypeIds.EffectSubscription */:
|
|
8430
|
+
return new EffectSubscription(null, null, null, null);
|
|
8045
8431
|
default:
|
|
8046
8432
|
throw qError(18 /* QError.serializeErrorCannotAllocate */, [typeId]);
|
|
8047
8433
|
}
|
|
@@ -8164,33 +8550,6 @@ const _regSymbol = (symbol, hash) => {
|
|
|
8164
8550
|
return symbol;
|
|
8165
8551
|
};
|
|
8166
8552
|
|
|
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
8553
|
/** @file Shared types */
|
|
8195
8554
|
/** @internal */
|
|
8196
8555
|
function isStringifiable(value) {
|
|
@@ -8469,6 +8828,14 @@ async function serialize(serializationContext) {
|
|
|
8469
8828
|
else if (value instanceof SubscriptionData) {
|
|
8470
8829
|
output(33 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
|
|
8471
8830
|
}
|
|
8831
|
+
else if (value instanceof EffectSubscription) {
|
|
8832
|
+
output(34 /* TypeIds.EffectSubscription */, [
|
|
8833
|
+
value.consumer,
|
|
8834
|
+
value.property,
|
|
8835
|
+
value.backRef,
|
|
8836
|
+
value.data,
|
|
8837
|
+
]);
|
|
8838
|
+
}
|
|
8472
8839
|
else if (isStore(value)) {
|
|
8473
8840
|
if (isResource(value)) {
|
|
8474
8841
|
// let render know about the resource
|
|
@@ -8918,7 +9285,7 @@ function filterEffectBackRefs(effectBackRef) {
|
|
|
8918
9285
|
let effectBackRefToSerialize = undefined;
|
|
8919
9286
|
if (effectBackRef) {
|
|
8920
9287
|
for (const [effectProp, effect] of effectBackRef) {
|
|
8921
|
-
if (effect
|
|
9288
|
+
if (effect.backRef) {
|
|
8922
9289
|
effectBackRefToSerialize ||= new Map();
|
|
8923
9290
|
effectBackRefToSerialize.set(effectProp, effect);
|
|
8924
9291
|
}
|
|
@@ -9087,6 +9454,7 @@ class _SharedContainer {
|
|
|
9087
9454
|
$renderPromise$ = null;
|
|
9088
9455
|
$resolveRenderPromise$ = null;
|
|
9089
9456
|
$cursorCount$ = 0;
|
|
9457
|
+
$pausedCursorCount$ = 0;
|
|
9090
9458
|
constructor(serverData, locale) {
|
|
9091
9459
|
this.$serverData$ = serverData;
|
|
9092
9460
|
this.$locale$ = locale;
|
|
@@ -9125,8 +9493,6 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
|
|
|
9125
9493
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
9126
9494
|
}
|
|
9127
9495
|
return executeComponent(ssr, host, host, componentQrl, srcProps);
|
|
9128
|
-
// const componentChore = ssr.$scheduler$(ChoreType.COMPONENT, host, componentQrl, srcProps);
|
|
9129
|
-
// return getChorePromise(componentChore);
|
|
9130
9496
|
};
|
|
9131
9497
|
|
|
9132
9498
|
class ParentComponentData {
|
|
@@ -9276,7 +9642,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
9276
9642
|
children != null && enqueue(children);
|
|
9277
9643
|
}
|
|
9278
9644
|
else if (type === Slot) {
|
|
9279
|
-
const componentFrame = options.parentComponentFrame
|
|
9645
|
+
const componentFrame = options.parentComponentFrame;
|
|
9280
9646
|
if (componentFrame) {
|
|
9281
9647
|
const compId = componentFrame.componentNode.id || '';
|
|
9282
9648
|
const projectionAttrs = isDev ? [DEBUG_TYPE, "P" /* VirtualType.Projection */] : [];
|
|
@@ -9398,6 +9764,9 @@ function toSsrAttrs(record, options) {
|
|
|
9398
9764
|
if (isPreventDefault(key)) {
|
|
9399
9765
|
addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
|
|
9400
9766
|
}
|
|
9767
|
+
else if (key === ITERATION_ITEM_SINGLE || key === ITERATION_ITEM_MULTI) {
|
|
9768
|
+
value = options.serializationCtx.$addRoot$(value);
|
|
9769
|
+
}
|
|
9401
9770
|
value = serializeAttribute(key, value, options.styleScopedId);
|
|
9402
9771
|
ssrAttrs.push(key, value);
|
|
9403
9772
|
};
|
|
@@ -9714,7 +10083,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9714
10083
|
const d = data;
|
|
9715
10084
|
let owner = d[0];
|
|
9716
10085
|
if (owner === _UNINITIALIZED) {
|
|
9717
|
-
owner = new JSXNodeImpl(Fragment, d[1], d[2]);
|
|
10086
|
+
owner = new JSXNodeImpl(Fragment, d[1], d[2], null, null);
|
|
9718
10087
|
owner._proxy = propsProxy;
|
|
9719
10088
|
}
|
|
9720
10089
|
propsProxy[_OWNER] = owner;
|
|
@@ -9726,6 +10095,15 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9726
10095
|
effectData.data.$isConst$ = data[1];
|
|
9727
10096
|
break;
|
|
9728
10097
|
}
|
|
10098
|
+
case 34 /* TypeIds.EffectSubscription */: {
|
|
10099
|
+
const effectSub = target;
|
|
10100
|
+
const d = data;
|
|
10101
|
+
effectSub.consumer = d[0];
|
|
10102
|
+
effectSub.property = d[1];
|
|
10103
|
+
effectSub.backRef = d[2];
|
|
10104
|
+
effectSub.data = d[3];
|
|
10105
|
+
break;
|
|
10106
|
+
}
|
|
9729
10107
|
default:
|
|
9730
10108
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
9731
10109
|
}
|
|
@@ -9770,7 +10148,8 @@ function inflateWrappedSignalValue(signal) {
|
|
|
9770
10148
|
let hasAttrValue = false;
|
|
9771
10149
|
if (effects) {
|
|
9772
10150
|
// Find string keys (attribute names) in the effect back refs
|
|
9773
|
-
for (const
|
|
10151
|
+
for (const effect of effects) {
|
|
10152
|
+
const key = effect.property;
|
|
9774
10153
|
if (isString(key)) {
|
|
9775
10154
|
// This is an attribute name, try to read its value
|
|
9776
10155
|
const attrValue = vnode_getProp(hostVNode, key, null);
|
|
@@ -10399,7 +10778,7 @@ class DomContainer extends _SharedContainer {
|
|
|
10399
10778
|
};
|
|
10400
10779
|
getSyncFn(id) {
|
|
10401
10780
|
const fn = this.$qFuncs$[id];
|
|
10402
|
-
assertTrue(typeof fn === 'function', 'Invalid reference: ' + id);
|
|
10781
|
+
isDev && assertTrue(typeof fn === 'function', 'Invalid reference: ' + id);
|
|
10403
10782
|
return fn;
|
|
10404
10783
|
}
|
|
10405
10784
|
$appendStyle$(content, styleId, host, scoped) {
|
|
@@ -10441,6 +10820,81 @@ class DomContainer extends _SharedContainer {
|
|
|
10441
10820
|
}
|
|
10442
10821
|
}
|
|
10443
10822
|
|
|
10823
|
+
/** @internal */
|
|
10824
|
+
const useTaskQrl = (qrl, opts) => {
|
|
10825
|
+
const { val, set, iCtx, i } = useSequentialScope();
|
|
10826
|
+
if (val) {
|
|
10827
|
+
return;
|
|
10828
|
+
}
|
|
10829
|
+
assertQrl(qrl);
|
|
10830
|
+
set(1);
|
|
10831
|
+
const taskFlags =
|
|
10832
|
+
// enabled by default
|
|
10833
|
+
opts?.deferUpdates === false ? 0 : 16 /* TaskFlags.RENDER_BLOCKING */;
|
|
10834
|
+
const task = new Task(8 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
10835
|
+
// In V2 we add the task to the sequential scope. We need to do this
|
|
10836
|
+
// in order to be able to retrieve it later when the parent element is
|
|
10837
|
+
// deleted and we need to be able to release the task subscriptions.
|
|
10838
|
+
set(task);
|
|
10839
|
+
const container = iCtx.$container$;
|
|
10840
|
+
const { $waitOn$: waitOn } = iCtx;
|
|
10841
|
+
const result = maybeThen(waitOn, () => runTask(task, container, iCtx.$hostElement$));
|
|
10842
|
+
if (isPromise(result)) {
|
|
10843
|
+
iCtx.$waitOn$ = result;
|
|
10844
|
+
}
|
|
10845
|
+
};
|
|
10846
|
+
const runTask = (task, container, host) => {
|
|
10847
|
+
task.$flags$ &= -9 /* TaskFlags.DIRTY */;
|
|
10848
|
+
cleanupDestroyable(task);
|
|
10849
|
+
const iCtx = newInvokeContext(container.$locale$, host, TaskEvent);
|
|
10850
|
+
iCtx.$container$ = container;
|
|
10851
|
+
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
10852
|
+
const track = trackFn(task, container);
|
|
10853
|
+
const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
10854
|
+
const taskApi = { track, cleanup };
|
|
10855
|
+
return safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
10856
|
+
// If a Promise is thrown, that means we need to re-run the task.
|
|
10857
|
+
if (isPromise(err)) {
|
|
10858
|
+
return err.then(() => runTask(task, container, host));
|
|
10859
|
+
}
|
|
10860
|
+
else {
|
|
10861
|
+
container.handleError(err, host);
|
|
10862
|
+
}
|
|
10863
|
+
});
|
|
10864
|
+
};
|
|
10865
|
+
class Task extends BackRef {
|
|
10866
|
+
$flags$;
|
|
10867
|
+
$index$;
|
|
10868
|
+
$el$;
|
|
10869
|
+
$qrl$;
|
|
10870
|
+
$state$;
|
|
10871
|
+
$destroy$;
|
|
10872
|
+
constructor($flags$, $index$, $el$, $qrl$, $state$, $destroy$) {
|
|
10873
|
+
super();
|
|
10874
|
+
this.$flags$ = $flags$;
|
|
10875
|
+
this.$index$ = $index$;
|
|
10876
|
+
this.$el$ = $el$;
|
|
10877
|
+
this.$qrl$ = $qrl$;
|
|
10878
|
+
this.$state$ = $state$;
|
|
10879
|
+
this.$destroy$ = $destroy$;
|
|
10880
|
+
}
|
|
10881
|
+
}
|
|
10882
|
+
/** @internal */
|
|
10883
|
+
const isTask = (value) => {
|
|
10884
|
+
return value instanceof Task;
|
|
10885
|
+
};
|
|
10886
|
+
/**
|
|
10887
|
+
* Used internally as a qrl event handler to schedule a task.
|
|
10888
|
+
*
|
|
10889
|
+
* @internal
|
|
10890
|
+
*/
|
|
10891
|
+
const scheduleTask = (_event, element) => {
|
|
10892
|
+
const [task] = useLexicalScope();
|
|
10893
|
+
const container = getDomContainer(element);
|
|
10894
|
+
task.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
10895
|
+
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
10896
|
+
};
|
|
10897
|
+
|
|
10444
10898
|
const throwIfQRLNotResolved = (qrl) => {
|
|
10445
10899
|
const resolved = qrl.resolved;
|
|
10446
10900
|
if (!resolved) {
|
|
@@ -10457,18 +10911,16 @@ const isSignal = (value) => {
|
|
|
10457
10911
|
return value instanceof SignalImpl;
|
|
10458
10912
|
};
|
|
10459
10913
|
const ensureContainsSubscription = (array, effectSubscription) => {
|
|
10460
|
-
|
|
10914
|
+
array.add(effectSubscription);
|
|
10461
10915
|
};
|
|
10462
10916
|
/** Ensure the item is in back refs set */
|
|
10463
10917
|
const ensureContainsBackRef = (array, value) => {
|
|
10464
|
-
array
|
|
10465
|
-
!array[2 /* EffectSubscriptionProp.BACK_REF */].has(value) &&
|
|
10466
|
-
array[2 /* EffectSubscriptionProp.BACK_REF */].add(value);
|
|
10918
|
+
(array.backRef ||= new Set()).add(value);
|
|
10467
10919
|
};
|
|
10468
10920
|
const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
10469
|
-
if (
|
|
10470
|
-
const effect = effectSubscriber
|
|
10471
|
-
const property = effectSubscriber
|
|
10921
|
+
if (container) {
|
|
10922
|
+
const effect = effectSubscriber.consumer;
|
|
10923
|
+
const property = effectSubscriber.property;
|
|
10472
10924
|
let qrl = null;
|
|
10473
10925
|
if (isTask(effect)) {
|
|
10474
10926
|
qrl = effect.$qrl$;
|
|
@@ -10485,24 +10937,15 @@ const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
|
10485
10937
|
}
|
|
10486
10938
|
};
|
|
10487
10939
|
const scheduleEffects = (container, signal, effects) => {
|
|
10488
|
-
const isBrowser = !isServerPlatform();
|
|
10940
|
+
const isBrowser = import.meta.env.TEST ? !isServerPlatform() : !isServer;
|
|
10489
10941
|
if (effects) {
|
|
10490
|
-
let tasksToTrigger = null;
|
|
10491
10942
|
const scheduleEffect = (effectSubscription) => {
|
|
10492
|
-
const consumer = effectSubscription
|
|
10493
|
-
const property = effectSubscription
|
|
10494
|
-
assertDefined(container, 'Container must be defined.');
|
|
10943
|
+
const consumer = effectSubscription.consumer;
|
|
10944
|
+
const property = effectSubscription.property;
|
|
10945
|
+
isDev && assertDefined(container, 'Container must be defined.');
|
|
10495
10946
|
if (isTask(consumer)) {
|
|
10496
10947
|
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
|
-
}
|
|
10948
|
+
markVNodeDirty(container, consumer.$el$, 1 /* ChoreBits.TASKS */);
|
|
10506
10949
|
}
|
|
10507
10950
|
else if (consumer instanceof SignalImpl) {
|
|
10508
10951
|
consumer.invalidate();
|
|
@@ -10517,7 +10960,7 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
10517
10960
|
}
|
|
10518
10961
|
}
|
|
10519
10962
|
else {
|
|
10520
|
-
const effectData = effectSubscription
|
|
10963
|
+
const effectData = effectSubscription.data;
|
|
10521
10964
|
if (effectData instanceof SubscriptionData) {
|
|
10522
10965
|
const data = effectData.data;
|
|
10523
10966
|
const payload = {
|
|
@@ -10541,14 +10984,10 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
10541
10984
|
}
|
|
10542
10985
|
}
|
|
10543
10986
|
};
|
|
10544
|
-
|
|
10987
|
+
const effectsSnapshot = Array.from(effects);
|
|
10988
|
+
for (const effect of effectsSnapshot) {
|
|
10545
10989
|
scheduleEffect(effect);
|
|
10546
10990
|
}
|
|
10547
|
-
if (!isBrowser && container && tasksToTrigger) {
|
|
10548
|
-
for (const task of tasksToTrigger) {
|
|
10549
|
-
markVNodeDirty(container, task.$el$, 1 /* ChoreBits.TASKS */);
|
|
10550
|
-
}
|
|
10551
|
-
}
|
|
10552
10991
|
}
|
|
10553
10992
|
};
|
|
10554
10993
|
/** @internal */
|
|
@@ -10779,7 +11218,8 @@ class StoreHandler {
|
|
|
10779
11218
|
this.$container$ = ctx.$container$;
|
|
10780
11219
|
}
|
|
10781
11220
|
else {
|
|
10782
|
-
|
|
11221
|
+
isDev &&
|
|
11222
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === this.$container$, 'Do not use signals across containers');
|
|
10783
11223
|
}
|
|
10784
11224
|
const effectSubscriber = ctx.$effectSubscriber$;
|
|
10785
11225
|
if (effectSubscriber) {
|
|
@@ -10881,7 +11321,8 @@ function addStoreEffect(target, prop, store, effectSubscription) {
|
|
|
10881
11321
|
// to this signal.
|
|
10882
11322
|
ensureContainsBackRef(effectSubscription, target);
|
|
10883
11323
|
// TODO is this needed with the preloader?
|
|
10884
|
-
|
|
11324
|
+
(import.meta.env.TEST ? !isDomContainer(store.$container$) : isServer) &&
|
|
11325
|
+
addQrlToSerializationCtx(effectSubscription, store.$container$);
|
|
10885
11326
|
}
|
|
10886
11327
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
10887
11328
|
target[prop] = value;
|
|
@@ -11267,7 +11708,7 @@ function getObjectById(id, stateData) {
|
|
|
11267
11708
|
if (typeof id === 'string') {
|
|
11268
11709
|
id = parseInt(id, 10);
|
|
11269
11710
|
}
|
|
11270
|
-
assertTrue(id < stateData.length, `Invalid reference ${id} >= ${stateData.length}`);
|
|
11711
|
+
isDev && assertTrue(id < stateData.length, `Invalid reference ${id} >= ${stateData.length}`);
|
|
11271
11712
|
return stateData[id];
|
|
11272
11713
|
}
|
|
11273
11714
|
function _createDeserializeContainer(stateData, element) {
|
|
@@ -11526,7 +11967,7 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
|
|
|
11526
11967
|
}
|
|
11527
11968
|
if (chunk === '') {
|
|
11528
11969
|
// Sync QRL
|
|
11529
|
-
assertDefined(_containerEl, 'Sync QRL must have container element');
|
|
11970
|
+
isDev && assertDefined(_containerEl, 'Sync QRL must have container element');
|
|
11530
11971
|
const hash = _containerEl.getAttribute(QInstanceAttr);
|
|
11531
11972
|
const doc = _containerEl.ownerDocument;
|
|
11532
11973
|
const qFuncs = getQFuncs(doc, hash);
|
|
@@ -11768,8 +12209,8 @@ const _qrlSync = function (fn, serializedFn) {
|
|
|
11768
12209
|
const componentQrl = (componentQrl) => {
|
|
11769
12210
|
// Return a QComponent Factory function.
|
|
11770
12211
|
function QwikComponent(props, key, flags = 0) {
|
|
11771
|
-
assertQrl(componentQrl);
|
|
11772
|
-
assertNumber(flags, 'The Qwik Component was not invoked correctly');
|
|
12212
|
+
isDev && assertQrl(componentQrl);
|
|
12213
|
+
isDev && assertNumber(flags, 'The Qwik Component was not invoked correctly');
|
|
11773
12214
|
const hash = qTest ? 'sX' : componentQrl.$hash$.slice(0, 4);
|
|
11774
12215
|
const finalKey = hash + ':' + (key ? key : '');
|
|
11775
12216
|
const InnerCmp = () => { };
|
|
@@ -12713,15 +13154,20 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
12713
13154
|
return;
|
|
12714
13155
|
}
|
|
12715
13156
|
assertQrl(qrl);
|
|
12716
|
-
|
|
12717
|
-
set(task);
|
|
12718
|
-
useRegisterTaskEvents(task, eagerness);
|
|
13157
|
+
let flags;
|
|
12719
13158
|
if (!isServerPlatform()) {
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
13159
|
+
// In DOM we immediately execute
|
|
13160
|
+
flags = 1 /* TaskFlags.VISIBLE_TASK */ | 8 /* TaskFlags.DIRTY */;
|
|
13161
|
+
qrl.resolve();
|
|
12723
13162
|
markVNodeDirty(iCtx.$container$, iCtx.$hostElement$, 1 /* ChoreBits.TASKS */);
|
|
12724
13163
|
}
|
|
13164
|
+
else {
|
|
13165
|
+
// In SSR we defer execution until triggered in DOM
|
|
13166
|
+
flags = 1 /* TaskFlags.VISIBLE_TASK */;
|
|
13167
|
+
}
|
|
13168
|
+
const task = new Task(flags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
13169
|
+
set(task);
|
|
13170
|
+
useRegisterTaskEvents(task, eagerness);
|
|
12725
13171
|
};
|
|
12726
13172
|
const useRegisterTaskEvents = (task, eagerness) => {
|
|
12727
13173
|
if (eagerness === 'intersection-observer') {
|