35
enableFizzExternalRuntime,
36
enableSrcObject,
37
enableFizzBlockingRender,
38
+ enableViewTransition,
39
} from 'shared/ReactFeatureFlags';
40
41
import type {
742
743
type InsertionMode = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
744
744
-const NO_SCOPE = /* */ 0b000;
745
-const NOSCRIPT_SCOPE = /* */ 0b001;
746
-const PICTURE_SCOPE = /* */ 0b010;
747
-const FALLBACK_SCOPE = /* */ 0b100;
745
+const NO_SCOPE = /* */ 0b00000;
746
+const NOSCRIPT_SCOPE = /* */ 0b00001;
747
+const PICTURE_SCOPE = /* */ 0b00010;
748
+const FALLBACK_SCOPE = /* */ 0b00100;
749
+const EXIT_SCOPE = /* */ 0b01000; // A direct Instance below a Suspense fallback is the only thing that can "exit"
750
+const ENTER_SCOPE = /* */ 0b10000; // A direct Instance below Suspense content is the only thing that can "enter"
751
+
752
+// Everything not listed here are tracked for the whole subtree as opposed to just
753
+// until the next Instance.
754
+const SUBTREE_SCOPE = ~(ENTER_SCOPE | EXIT_SCOPE);
755
+
756
+type ViewTransitionContext = {
757
+ update: 'none' | 'auto' | string,
758
+ // null here means that this case can never trigger. Not "auto" like it does in props.
759
+ enter: null | 'none' | 'auto' | string,
760
+ exit: null | 'none' | 'auto' | string,
761
+ share: null | 'none' | 'auto' | string,
762
+ name: 'auto' | string,
763
+ autoName: string, // a name that can be used if an explicit one is not defined.
764
+ nameIdx: number, // keeps track of how many duplicates of this name we've emitted.
765
+};
766
767
// Lets us keep track of contextual state and pick it back up after suspending.
768
export type FormatContext = {
769
insertionMode: InsertionMode, // root/svg/html/mathml/table
770
selectedValue: null | string | Array<string>, // the selected value(s) inside a <select>, or null outside <select>
771
tagScope: number,
772
+ viewTransition: null | ViewTransitionContext, // tracks if we're inside a ViewTransition outside the first DOM node
773
};
774
775
function createFormatContext(
776
insertionMode: InsertionMode,
777
selectedValue: null | string | Array<string>,
778
tagScope: number,
779
+ viewTransition: null | ViewTransitionContext,
780
): FormatContext {
781
return {
782
insertionMode,
783
selectedValue,
784
tagScope,
785
+ viewTransition,
786
};
787
}
788
797
: namespaceURI === 'http://www.w3.org/1998/Math/MathML'
798
? MATHML_MODE
799
: ROOT_HTML_MODE;
779
- return createFormatContext(insertionMode, null, NO_SCOPE);
800
+ return createFormatContext(insertionMode, null, NO_SCOPE, null);
801
}
802
803
export function getChildFormatContext(
805
type: string,
806
props: Object,
807
): FormatContext {
808
+ const subtreeScope = parentContext.tagScope & SUBTREE_SCOPE;
809
switch (type) {
810
case 'noscript':
811
return createFormatContext(
812
HTML_MODE,
813
null,
792
- parentContext.tagScope | NOSCRIPT_SCOPE,
814
+ subtreeScope | NOSCRIPT_SCOPE,
815
+ null,
816
);
817
case 'select':
818
return createFormatContext(
819
HTML_MODE,
820
props.value != null ? props.value : props.defaultValue,
798
- parentContext.tagScope,
821
+ subtreeScope,
822
+ null,
823
);
824
case 'svg':
801
- return createFormatContext(SVG_MODE, null, parentContext.tagScope);
825
+ return createFormatContext(SVG_MODE, null, subtreeScope, null);
826
case 'picture':
827
return createFormatContext(
828
HTML_MODE,
829
null,
806
- parentContext.tagScope | PICTURE_SCOPE,
830
+ subtreeScope | PICTURE_SCOPE,
831
+ null,
832
);
833
case 'math':
809
- return createFormatContext(MATHML_MODE, null, parentContext.tagScope);
834
+ return createFormatContext(MATHML_MODE, null, subtreeScope, null);
835
case 'foreignObject':
811
- return createFormatContext(HTML_MODE, null, parentContext.tagScope);
836
+ return createFormatContext(HTML_MODE, null, subtreeScope, null);
837
// Table parents are special in that their children can only be created at all if they're
838
// wrapped in a table parent. So we need to encode that we're entering this mode.
839
case 'table':
815
- return createFormatContext(HTML_TABLE_MODE, null, parentContext.tagScope);
840
+ return createFormatContext(HTML_TABLE_MODE, null, subtreeScope, null);
841
case 'thead':
842
case 'tbody':
843
case 'tfoot':
844
return createFormatContext(
845
HTML_TABLE_BODY_MODE,
846
null,
822
- parentContext.tagScope,
823
- );
824
- case 'colgroup':
825
- return createFormatContext(
826
- HTML_COLGROUP_MODE,
847
+ subtreeScope,
848
null,
828
- parentContext.tagScope,
849
);
850
+ case 'colgroup':
851
+ return createFormatContext(HTML_COLGROUP_MODE, null, subtreeScope, null);
852
case 'tr':
831
- return createFormatContext(
832
- HTML_TABLE_ROW_MODE,
833
- null,
834
- parentContext.tagScope,
835
- );
853
+ return createFormatContext(HTML_TABLE_ROW_MODE, null, subtreeScope, null);
854
case 'head':
855
if (parentContext.insertionMode < HTML_MODE) {
856
// We are either at the root or inside the <html> tag and can enter
857
// the <head> scope
840
- return createFormatContext(
841
- HTML_HEAD_MODE,
842
- null,
843
- parentContext.tagScope,
844
- );
858
+ return createFormatContext(HTML_HEAD_MODE, null, subtreeScope, null);
859
}
860
break;
861
case 'html':
862
if (parentContext.insertionMode === ROOT_HTML_MODE) {
849
- return createFormatContext(
850
- HTML_HTML_MODE,
851
- null,
852
- parentContext.tagScope,
853
- );
863
+ return createFormatContext(HTML_HTML_MODE, null, subtreeScope, null);
864
}
865
break;
866
}
867
if (parentContext.insertionMode >= HTML_TABLE_MODE) {
868
// Whatever tag this was, it wasn't a table parent or other special parent, so we must have
869
// entered plain HTML again.
860
- return createFormatContext(HTML_MODE, null, parentContext.tagScope);
870
+ return createFormatContext(HTML_MODE, null, subtreeScope, null);
871
}
872
if (parentContext.insertionMode < HTML_MODE) {
863
- return createFormatContext(HTML_MODE, null, parentContext.tagScope);
873
+ return createFormatContext(HTML_MODE, null, subtreeScope, null);
874
+ }
875
+ if (enableViewTransition) {
876
+ if (parentContext.viewTransition !== null) {
877
+ // If we're inside a view transition, regardless what element we were in, it consumes
878
+ // the view transition context.
879
+ return createFormatContext(
880
+ parentContext.insertionMode,
881
+ parentContext.selectedValue,
882
+ subtreeScope,
883
+ null,
884
+ );
885
+ }
886
+ }
887
+ if (parentContext.tagScope !== subtreeScope) {
888
+ return createFormatContext(
889
+ parentContext.insertionMode,
890
+ parentContext.selectedValue,
891
+ subtreeScope,
892
+ null,
893
+ );
894
}
895
return parentContext;
896
}
897
898
+function getSuspenseViewTransition(
899
+ parentViewTransition: null | ViewTransitionContext,
900
+): null | ViewTransitionContext {
901
+ if (parentViewTransition === null) {
902
+ return null;
903
+ }
904
+ // If a ViewTransition wraps a Suspense boundary it applies to the children Instances
905
+ // in both the fallback and the content.
906
+ // Since we only have a representation of ViewTransitions on the Instances themselves
907
+ // we cannot model the parent ViewTransition activating "enter", "exit" or "share"
908
+ // since those would be ambiguous with the Suspense boundary changing states and
909
+ // affecting the same Instances.
910
+ // We also can't model an "update" when that update is fallback nodes swapping for
911
+ // content nodes. However, we can model is as a "share" from the fallback nodes to
912
+ // the content nodes using the same name. We just have to assign the same name that
913
+ // we would've used (the parent ViewTransition name or auto-assign one).
914
+ const viewTransition: ViewTransitionContext = {
915
+ update: parentViewTransition.update, // For deep updates.
916
+ enter: null,
917
+ exit: null,
918
+ share: parentViewTransition.update, // For exit or enter of reveals.
919
+ name: parentViewTransition.autoName,
920
+ autoName: parentViewTransition.autoName,
921
+ // TOOD: If we have more than just this Suspense boundary as a child of the ViewTransition
922
+ // then the parent needs to isolate the names so that they don't conflict.
923
+ nameIdx: 0,
924
+ };
925
+ return viewTransition;
926
+}
927
+
928
export function getSuspenseFallbackFormatContext(
929
parentContext: FormatContext,
930
): FormatContext {
931
return createFormatContext(
932
parentContext.insertionMode,
933
parentContext.selectedValue,
874
- parentContext.tagScope | FALLBACK_SCOPE,
934
+ parentContext.tagScope | FALLBACK_SCOPE | EXIT_SCOPE,
935
+ getSuspenseViewTransition(parentContext.viewTransition),
936
);
937
}
938
939
export function getSuspenseContentFormatContext(
940
parentContext: FormatContext,
941
): FormatContext {
881
- return parentContext;
942
+ return createFormatContext(
943
+ parentContext.insertionMode,
944
+ parentContext.selectedValue,
945
+ parentContext.tagScope | ENTER_SCOPE,
946
+ getSuspenseViewTransition(parentContext.viewTransition),
947
+ );
948
+}
949
+
950
+export function getViewTransitionFormatContext(
951
+ parentContext: FormatContext,
952
+ update: ?string,
953
+ enter: ?string,
954
+ exit: ?string,
955
+ share: ?string,
956
+ name: ?string,
957
+ autoName: string, // name or an autogenerated unique name
958
+): FormatContext {
959
+ // We're entering a <ViewTransition>. Normalize props.
960
+ if (update == null) {
961
+ update = 'auto';
962
+ }
963
+ if (enter == null) {
964
+ enter = 'auto';
965
+ }
966
+ if (exit == null) {
967
+ exit = 'auto';
968
+ }
969
+ if (name == null) {
970
+ const parentViewTransition = parentContext.viewTransition;
971
+ if (parentViewTransition !== null) {
972
+ // If we have multiple nested ViewTransition and the parent has a "share"
973
+ // but the child doesn't, then the parent ViewTransition can still activate
974
+ // a share scenario so we reuse the name and share from the parent.
975
+ name = parentViewTransition.name;
976
+ share = parentViewTransition.share;
977
+ } else {
978
+ name = 'auto';
979
+ share = null; // share is only relevant if there's an explicit name
980
+ }
981
+ } else if (share === 'none') {
982
+ // I believe if share is disabled, it means the same thing as if it doesn't
983
+ // exit because enter/exit will take precedence and if it's deeply nested
984
+ // it just animates along whatever the parent does when disabled.
985
+ share = null;
986
+ } else if (share == null) {
987
+ share = 'auto';
988
+ }
989
+ if (!(parentContext.tagScope & EXIT_SCOPE)) {
990
+ exit = null; // exit is only relevant for the first ViewTransition inside fallback
991
+ }
992
+ if (!(parentContext.tagScope & ENTER_SCOPE)) {
993
+ enter = null; // enter is only relevant for the first ViewTransition inside content
994
+ }
995
+ const viewTransition: ViewTransitionContext = {
996
+ update,
997
+ enter,
998
+ exit,
999
+ share,
1000
+ name,
1001
+ autoName,
1002
+ nameIdx: 0,
1003
+ };
1004
+ const subtreeScope = parentContext.tagScope & SUBTREE_SCOPE;
1005
+ return createFormatContext(
1006
+ parentContext.insertionMode,
1007
+ parentContext.selectedValue,
1008
+ subtreeScope,
1009
+ viewTransition,
1010
+ );
1011
}
1012
1013
export function isPreambleContext(formatContext: FormatContext): boolean {
1069
}
1070
}
1071
1072
+function pushViewTransitionAttributes(
1073
+ target: Array<Chunk | PrecomputedChunk>,
1074
+ formatContext: FormatContext,
1075
+): void {
1076
+ if (!enableViewTransition) {
1077
+ return;
1078
+ }
1079
+ const viewTransition = formatContext.viewTransition;
1080
+ if (viewTransition === null) {
1081
+ return;
1082
+ }
1083
+ if (viewTransition.name !== 'auto') {
1084
+ pushStringAttribute(
1085
+ target,
1086
+ 'vt-name',
1087
+ viewTransition.nameIdx === 0
1088
+ ? viewTransition.name
1089
+ : viewTransition.name + '_' + viewTransition.nameIdx,
1090
+ );
1091
+ // Increment the index in case we have multiple children to the same ViewTransition.
1092
+ // Because this is a side-effect in render, we should ideally call pushViewTransitionAttributes
1093
+ // after we've suspended (like forms do), so that we don't increment each attempt.
1094
+ // TODO: Make this deterministic.
1095
+ viewTransition.nameIdx++;
1096
+ }
1097
+ pushStringAttribute(target, 'vt-update', viewTransition.update);
1098
+ if (viewTransition.enter !== null) {
1099
+ pushStringAttribute(target, 'vt-enter', viewTransition.enter);
1100
+ }
1101
+ if (viewTransition.exit !== null) {
1102
+ pushStringAttribute(target, 'vt-exit', viewTransition.exit);
1103
+ }
1104
+ if (viewTransition.share !== null) {
1105
+ pushStringAttribute(target, 'vt-share', viewTransition.share);
1106
+ }
1107
+}
1108
+
1109
const styleNameCache: Map<string, PrecomputedChunk> = new Map();
1110
function processStyleName(styleName: string): PrecomputedChunk {
1111
const chunk = styleNameCache.get(styleName);
1238
}
1239
1240
function makeFormFieldPrefix(resumableState: ResumableState): string {
1241
+ // TODO: Make this deterministic.
1242
const id = resumableState.nextFormID++;
1243
return resumableState.idPrefix + id;
1244
}
1845
function pushStartAnchor(
1846
target: Array<Chunk | PrecomputedChunk>,
1847
props: Object,
1848
+ formatContext: FormatContext,
1849
): ReactNodeList {
1850
target.push(startChunkForTag('a'));
1851
1880
}
1881
}
1882
1883
+ pushViewTransitionAttributes(target, formatContext);
1884
+
1885
target.push(endOfStartTag);
1886
pushInnerHTML(target, innerHTML, children);
1887
if (typeof children === 'string') {
1896
function pushStartObject(
1897
target: Array<Chunk | PrecomputedChunk>,
1898
props: Object,
1899
+ formatContext: FormatContext,
1900
): ReactNodeList {
1901
target.push(startChunkForTag('object'));
1902
1948
}
1949
}
1950
1951
+ pushViewTransitionAttributes(target, formatContext);
1952
+
1953
target.push(endOfStartTag);
1954
pushInnerHTML(target, innerHTML, children);
1955
if (typeof children === 'string') {
1964
function pushStartSelect(
1965
target: Array<Chunk | PrecomputedChunk>,
1966
props: Object,
1967
+ formatContext: FormatContext,
1968
): ReactNodeList {
1969
if (__DEV__) {
1970
checkControlledValueProps('select', props);
2018
}
2019
}
2020
2021
+ pushViewTransitionAttributes(target, formatContext);
2022
+
2023
target.push(endOfStartTag);
2024
pushInnerHTML(target, innerHTML, children);
2025
return children;
2149
target.push(selectedMarkerAttribute);
2150
}
2151
2152
+ // Options never participate as ViewTransitions.
2153
target.push(endOfStartTag);
2154
pushInnerHTML(target, innerHTML, children);
2155
return children;
2219
props: Object,
2220
resumableState: ResumableState,
2221
renderState: RenderState,
2222
+ formatContext: FormatContext,
2223
): ReactNodeList {
2224
target.push(startChunkForTag('form'));
2225
2329
pushAttribute(target, 'target', formTarget);
2330
}
2331
2332
+ pushViewTransitionAttributes(target, formatContext);
2333
+
2334
target.push(endOfStartTag);
2335
2336
if (formActionName !== null) {
2355
props: Object,
2356
resumableState: ResumableState,
2357
renderState: RenderState,
2358
+ formatContext: FormatContext,
2359
): ReactNodeList {
2360
if (__DEV__) {
2361
checkControlledValueProps('input', props);
2485
pushAttribute(target, 'value', defaultValue);
2486
}
2487
2488
+ pushViewTransitionAttributes(target, formatContext);
2489
+
2490
target.push(endOfStartTagSelfClosing);
2491
2492
// We place any additional hidden form fields after the input.
2500
props: Object,
2501
resumableState: ResumableState,
2502
renderState: RenderState,
2503
+ formatContext: FormatContext,
2504
): ReactNodeList {
2505
target.push(startChunkForTag('button'));
2506
2572
name,
2573
);
2574
2575
+ pushViewTransitionAttributes(target, formatContext);
2576
+
2577
target.push(endOfStartTag);
2578
2579
// We place any additional hidden form fields we need to include inside the button itself.
2593
function pushStartTextArea(
2594
target: Array<Chunk | PrecomputedChunk>,
2595
props: Object,
2596
+ formatContext: FormatContext,
2597
): ReactNodeList {
2598
if (__DEV__) {
2599
checkControlledValueProps('textarea', props);
2648
value = defaultValue;
2649
}
2650
2651
+ pushViewTransitionAttributes(target, formatContext);
2652
+
2653
target.push(endOfStartTag);
2654
2655
// TODO (yungsters): Remove support for children content in <textarea>.
2726
noscriptTagInScope ||
2727
props.itemProp != null
2728
) {
2540
- return pushSelfClosing(target, props, 'meta');
2729
+ return pushSelfClosing(target, props, 'meta', formatContext);
2730
} else {
2731
if (textEmbedded) {
2732
// This link follows text but we aren't writing a tag. while not as efficient as possible we need
2745
// the only way to embed the tag today we flush it on a special queue on the Request so it
2746
// can go before everything else. Like viewport this means that the tag will escape it's
2747
// parent container.
2559
- return pushSelfClosing(renderState.charsetChunks, props, 'meta');
2748
+ return pushSelfClosing(
2749
+ renderState.charsetChunks,
2750
+ props,
2751
+ 'meta',
2752
+ formatContext,
2753
+ );
2754
} else if (props.name === 'viewport') {
2755
// "viewport" is flushed on the Request so it can go earlier that Float resources that
2756
// might be affected by it. This means it can escape the boundary it is rendered within.
2757
// This is a pragmatic solution to viewport being incredibly sensitive to document order
2758
// without requiring all hoistables to be flushed too early.
2565
- return pushSelfClosing(renderState.viewportChunks, props, 'meta');
2759
+ return pushSelfClosing(
2760
+ renderState.viewportChunks,
2761
+ props,
2762
+ 'meta',
2763
+ formatContext,
2764
+ );
2765
} else {
2567
- return pushSelfClosing(renderState.hoistableChunks, props, 'meta');
2766
+ return pushSelfClosing(
2767
+ renderState.hoistableChunks,
2768
+ props,
2769
+ 'meta',
2770
+ formatContext,
2771
+ );
2772
}
2773
}
2774
}
2975
}
2976
}
2977
2978
+ // Link never participate as a ViewTransition
2979
+
2980
target.push(endOfStartTagSelfClosing);
2981
return null;
2982
}
3142
}
3143
}
3144
}
3145
+
3146
+ // Style never participate as a ViewTransition.
3147
target.push(endOfStartTag);
3148
3149
const child = Array.isArray(children)
3350
}
3351
}
3352
}
3145
- return pushSelfClosing(target, props, 'img');
3353
+ return pushSelfClosing(target, props, 'img', formatContext);
3354
}
3355
3356
function pushSelfClosing(
3357
target: Array<Chunk | PrecomputedChunk>,
3358
props: Object,
3359
tag: string,
3360
+ formatContext: FormatContext,
3361
): null {
3362
target.push(startChunkForTag(tag));
3363
3381
}
3382
}
3383
3384
+ pushViewTransitionAttributes(target, formatContext);
3385
+
3386
target.push(endOfStartTagSelfClosing);
3387
return null;
3388
}
3390
function pushStartMenuItem(
3391
target: Array<Chunk | PrecomputedChunk>,
3392
props: Object,
3393
+ formatContext: FormatContext,
3394
): ReactNodeList {
3395
target.push(startChunkForTag('menuitem'));
3396
3413
}
3414
}
3415
3416
+ pushViewTransitionAttributes(target, formatContext);
3417
+
3418
target.push(endOfStartTag);
3419
return null;
3420
}
3521
}
3522
}
3523
}
3524
+ // Title never participate as a ViewTransition
3525
target.push(endOfStartTag);
3526
3527
const child = Array.isArray(children)
3570
}
3571
3572
preamble.headChunks = [];
3358
- return pushStartSingletonElement(preamble.headChunks, props, 'head');
3573
+ return pushStartSingletonElement(
3574
+ preamble.headChunks,
3575
+ props,
3576
+ 'head',
3577
+ formatContext,
3578
+ );
3579
} else {
3580
// This <head> is deep and is likely just an error. we emit it inline though.
3581
// Validation should warn that this tag is the the wrong spot.
3362
- return pushStartGenericElement(target, props, 'head');
3582
+ return pushStartGenericElement(target, props, 'head', formatContext);
3583
}
3584
}
3585
3604
}
3605
3606
preamble.bodyChunks = [];
3387
- return pushStartSingletonElement(preamble.bodyChunks, props, 'body');
3607
+ return pushStartSingletonElement(
3608
+ preamble.bodyChunks,
3609
+ props,
3610
+ 'body',
3611
+ formatContext,
3612
+ );
3613
} else {
3614
// This <head> is deep and is likely just an error. we emit it inline though.
3615
// Validation should warn that this tag is the the wrong spot.
3391
- return pushStartGenericElement(target, props, 'body');
3616
+ return pushStartGenericElement(target, props, 'body', formatContext);
3617
}
3618
}
3619
3638
}
3639
3640
preamble.htmlChunks = [DOCTYPE];
3416
- return pushStartSingletonElement(preamble.htmlChunks, props, 'html');
3641
+ return pushStartSingletonElement(
3642
+ preamble.htmlChunks,
3643
+ props,
3644
+ 'html',
3645
+ formatContext,
3646
+ );
3647
} else {
3648
// This <html> is deep and is likely just an error. we emit it inline though.
3649
// Validation should warn that this tag is the the wrong spot.
3420
- return pushStartGenericElement(target, props, 'html');
3650
+ return pushStartGenericElement(target, props, 'html', formatContext);
3651
}
3652
}
3653
3758
}
3759
}
3760
}
3761
+ // Scripts never participate as a ViewTransition
3762
target.push(endOfStartTag);
3763
3764
if (__DEV__) {
3792
target: Array<Chunk | PrecomputedChunk>,
3793
props: Object,
3794
tag: string,
3795
+ formatContext: FormatContext,
3796
): ReactNodeList {
3797
target.push(startChunkForTag(tag));
3798
3818
}
3819
}
3820
3821
+ pushViewTransitionAttributes(target, formatContext);
3822
+
3823
target.push(endOfStartTag);
3824
pushInnerHTML(target, innerHTML, children);
3825
return children;
3829
target: Array<Chunk | PrecomputedChunk>,
3830
props: Object,
3831
tag: string,
3832
+ formatContext: FormatContext,
3833
): ReactNodeList {
3834
target.push(startChunkForTag(tag));
3835
3855
}
3856
}
3857
3858
+ pushViewTransitionAttributes(target, formatContext);
3859
+
3860
target.push(endOfStartTag);
3861
pushInnerHTML(target, innerHTML, children);
3862
if (typeof children === 'string') {
3872
target: Array<Chunk | PrecomputedChunk>,
3873
props: Object,
3874
tag: string,
3875
+ formatContext: FormatContext,
3876
): ReactNodeList {
3877
target.push(startChunkForTag(tag));
3878
3931
}
3932
}
3933
3934
+ // TODO: ViewTransition attributes gets observed by the Custom Element which is a bit sketchy.
3935
+ pushViewTransitionAttributes(target, formatContext);
3936
+
3937
target.push(endOfStartTag);
3938
pushInnerHTML(target, innerHTML, children);
3939
return children;
3945
target: Array<Chunk | PrecomputedChunk>,
3946
props: Object,
3947
tag: string,
3948
+ formatContext: FormatContext,
3949
): ReactNodeList {
3950
target.push(startChunkForTag(tag));
3951
3971
}
3972
}
3973
3974
+ pushViewTransitionAttributes(target, formatContext);
3975
+
3976
target.push(endOfStartTag);
3977
3978
// text/html ignores the first character in these tags if it's a newline
4095
// Fast track very common tags
4096
break;
4097
case 'a':
3854
- return pushStartAnchor(target, props);
4098
+ return pushStartAnchor(target, props, formatContext);
4099
case 'g':
4100
case 'p':
4101
case 'li':
4103
break;
4104
// Special tags
4105
case 'select':
3862
- return pushStartSelect(target, props);
4106
+ return pushStartSelect(target, props, formatContext);
4107
case 'option':
4108
return pushStartOption(target, props, formatContext);
4109
case 'textarea':
3866
- return pushStartTextArea(target, props);
4110
+ return pushStartTextArea(target, props, formatContext);
4111
case 'input':
3868
- return pushInput(target, props, resumableState, renderState);
4112
+ return pushInput(
4113
+ target,
4114
+ props,
4115
+ resumableState,
4116
+ renderState,
4117
+ formatContext,
4118
+ );
4119
case 'button':
3870
- return pushStartButton(target, props, resumableState, renderState);
4120
+ return pushStartButton(
4121
+ target,
4122
+ props,
4123
+ resumableState,
4124
+ renderState,
4125
+ formatContext,
4126
+ );
4127
case 'form':
3872
- return pushStartForm(target, props, resumableState, renderState);
4128
+ return pushStartForm(
4129
+ target,
4130
+ props,
4131
+ resumableState,
4132
+ renderState,
4133
+ formatContext,
4134
+ );
4135
case 'menuitem':
3874
- return pushStartMenuItem(target, props);
4136
+ return pushStartMenuItem(target, props, formatContext);
4137
case 'object':
3876
- return pushStartObject(target, props);
4138
+ return pushStartObject(target, props, formatContext);
4139
case 'title':
4140
return pushTitle(target, props, renderState, formatContext);
4141
case 'link':
4172
// Newline eating tags
4173
case 'listing':
4174
case 'pre': {
3913
- return pushStartPreformattedElement(target, props, type);
4175
+ return pushStartPreformattedElement(target, props, type, formatContext);
4176
}
4177
case 'img': {
4178
return pushImg(target, props, resumableState, renderState, formatContext);
4189
case 'source':
4190
case 'track':
4191
case 'wbr': {
3930
- return pushSelfClosing(target, props, type);
4192
+ return pushSelfClosing(target, props, type, formatContext);
4193
}
4194
// These are reserved SVG and MathML elements, that are never custom elements.
4195
// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-core-concepts
4232
default: {
4233
if (type.indexOf('-') !== -1) {
4234
// Custom element
3973
- return pushStartCustomElement(target, props, type);
4235
+ return pushStartCustomElement(target, props, type, formatContext);
4236
}
4237
}
4238
}
4239
// Generic element
3978
- return pushStartGenericElement(target, props, type);
4240
+ return pushStartGenericElement(target, props, type, formatContext);
4241
}
4242
4243
const endTagCache = new Map<string, PrecomputedChunk>();