@tamagui/static 3.0.0-beta.765.1 → 3.0.0-beta.804.1
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/dist/cjs/compiler.cjs +12 -1
- package/dist/cjs/compilerHost.cjs +642 -315
- package/dist/cjs/extractor/bundle.cjs +41 -17
- package/dist/cjs/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +6 -1
- package/dist/cjs/extractor/loadTamagui.cjs +115 -64
- package/dist/esm/compiler.mjs +12 -1
- package/dist/esm/compiler.mjs.map +1 -1
- package/dist/esm/compilerHost.mjs +644 -316
- package/dist/esm/compilerHost.mjs.map +1 -1
- package/dist/esm/extractor/bundle.mjs +39 -16
- package/dist/esm/extractor/bundle.mjs.map +1 -1
- package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs +6 -1
- package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs.map +1 -1
- package/dist/esm/extractor/loadTamagui.mjs +115 -64
- package/dist/esm/extractor/loadTamagui.mjs.map +1 -1
- package/package.json +19 -19
- package/src/compiler.ts +16 -1
- package/src/compilerHost.ts +282 -93
- package/src/extractor/bundle.ts +7 -1
- package/src/extractor/getTamaguiConfigPathFromOptionsConfig.ts +9 -2
- package/types/compiler.d.ts.map +1 -1
- package/types/compilerHost.d.ts.map +1 -1
- package/types/extractor/bundle.d.ts.map +1 -1
- package/types/extractor/getTamaguiConfigPathFromOptionsConfig.d.ts.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { zeroRuleMessage, zeroThemeBoundaryMessage } from "@tamagui/compiler-core";
|
|
1
|
+
import { collectLeaves, zeroRuleMessage, zeroThemeBoundaryMessage } from "@tamagui/compiler-core";
|
|
2
2
|
import { StyleObjectIdentifier, StyleObjectProperty, StyleObjectRules, StyleObjectValue, stylePropsAll, stylePropsText, validStyles } from "@tamagui/helpers";
|
|
3
3
|
import { ATTRIBUTES, DISPLAY_WEB_RESET, EVENTS, NATIVE_BACKING, NATIVE_BLOCK_DEFAULTS, NATIVE_ELEMENT_DEFAULTS, NATIVE_FLEX_DEFAULTS, NATIVE_INPUT_TYPES, NATIVE_PRIMITIVE_MODULE, TAGS, TAG_WEB_DEFAULTS } from "@tamagui/dom";
|
|
4
4
|
import { createModifierRegistry, parseTransition, parseValue } from "@tamagui/style-grammar/tooling";
|
|
@@ -80,7 +80,9 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
|
|
|
80
80
|
media: []
|
|
81
81
|
};
|
|
82
82
|
const classKeys = /* @__PURE__ */ new Map();
|
|
83
|
-
for (const [key, identifier] of Object.entries(split.classNames ?? {}))
|
|
83
|
+
for (const [key, identifier] of Object.entries(split.classNames ?? {})) {
|
|
84
|
+
if (typeof identifier === "string") classKeys.set(identifier, key);
|
|
85
|
+
}
|
|
84
86
|
const identifiers = /* @__PURE__ */ new Set([...classKeys.keys(), ...Object.values(rules).flatMap((styleObject) => {
|
|
85
87
|
const identifier = styleObject?.[StyleObjectIdentifier];
|
|
86
88
|
return typeof identifier === "string" ? [identifier] : [];
|
|
@@ -88,11 +90,17 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
|
|
|
88
90
|
for (const identifier of identifiers) {
|
|
89
91
|
const key = classKeys.get(identifier) ?? "";
|
|
90
92
|
const css2 = cssFromRules(Object.fromEntries(Object.entries(rules).filter(([, styleObject]) => styleObject?.[StyleObjectIdentifier] === identifier))).join("");
|
|
91
|
-
if (identifier.startsWith("t_group_"))
|
|
92
|
-
|
|
93
|
-
else if (
|
|
94
|
-
|
|
95
|
-
else
|
|
93
|
+
if (identifier.startsWith("t_group_")) {
|
|
94
|
+
buckets.group.push(identifier);
|
|
95
|
+
} else if (pseudoNames.some((name) => key.endsWith(`-${name}`))) {
|
|
96
|
+
buckets.pseudo.push(identifier);
|
|
97
|
+
} else if (css2.includes(".t_")) {
|
|
98
|
+
buckets.theme.push(identifier);
|
|
99
|
+
} else if ([...mediaNames].some((name) => key.endsWith(`-${name}`))) {
|
|
100
|
+
buckets.media.push(identifier);
|
|
101
|
+
} else {
|
|
102
|
+
buckets.normal.push(identifier);
|
|
103
|
+
}
|
|
96
104
|
}
|
|
97
105
|
const orderedIdentifiers = [
|
|
98
106
|
...buckets.group,
|
|
@@ -112,17 +120,28 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
|
|
|
112
120
|
css
|
|
113
121
|
};
|
|
114
122
|
}
|
|
115
|
-
function
|
|
123
|
+
function spreadNonStyleReplacement(form, entry, isPropIgnored, rewriteProp) {
|
|
124
|
+
if (entry.kind !== "spread" || entry.value.kind !== "static" || !staticObject(entry.value.value)) {
|
|
125
|
+
return "";
|
|
126
|
+
}
|
|
127
|
+
const nonStyleEntries = Object.entries(entry.value.value).filter(([key]) => !isPropIgnored(key)).map(([key, value]) => rewriteProp(key, value));
|
|
128
|
+
if (nonStyleEntries.length === 0) return "";
|
|
129
|
+
const objectSource = `{ ${nonStyleEntries.map(([key, value]) => `${JSON.stringify(key)}: ${JSON.stringify(value)}`).join(", ")} }`;
|
|
130
|
+
return form === "jsx" ? `{...${objectSource}}` : `...${objectSource}`;
|
|
131
|
+
}
|
|
132
|
+
function compiledPropsEdits(input, styleEntries, replacement, spreadReplacement) {
|
|
116
133
|
const propsSpan = input.element.propsSpan;
|
|
117
134
|
if (!propsSpan) return null;
|
|
118
135
|
const original = input.source.slice(propsSpan.start, propsSpan.end);
|
|
119
136
|
const trimmed = original.trim();
|
|
120
|
-
if (!trimmed.startsWith("{") || !trimmed.endsWith("}"))
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
138
|
+
return [{
|
|
139
|
+
start: propsSpan.start,
|
|
140
|
+
end: propsSpan.end,
|
|
141
|
+
content: `{ ${replacement} }`,
|
|
142
|
+
origin: propsSpan
|
|
143
|
+
}];
|
|
144
|
+
}
|
|
126
145
|
if (styleEntries.length === 0) {
|
|
127
146
|
const close = original.lastIndexOf("}");
|
|
128
147
|
const separator = original.slice(1, close).trim() ? ", " : " ";
|
|
@@ -138,19 +157,22 @@ function compiledPropsEdits(input, styleEntries, replacement) {
|
|
|
138
157
|
for (const [index, entry] of styleEntries.entries()) {
|
|
139
158
|
let start = entry.span.start;
|
|
140
159
|
let end = entry.span.end;
|
|
160
|
+
const nonStyle = spreadReplacement?.(entry) ?? "";
|
|
141
161
|
if (index === 0) {
|
|
162
|
+
const content = [replacement, nonStyle].filter(Boolean).join(", ");
|
|
142
163
|
edits.push({
|
|
143
164
|
start,
|
|
144
165
|
end,
|
|
145
|
-
content
|
|
166
|
+
content,
|
|
146
167
|
origin: entry.span
|
|
147
168
|
});
|
|
148
169
|
continue;
|
|
149
170
|
}
|
|
150
171
|
let cursor = end - propsSpan.start;
|
|
151
172
|
while (cursor < original.length - 1 && /\s/.test(original[cursor])) cursor++;
|
|
152
|
-
if (original[cursor] === ",")
|
|
153
|
-
|
|
173
|
+
if (original[cursor] === ",") {
|
|
174
|
+
end = propsSpan.start + cursor + 1;
|
|
175
|
+
} else {
|
|
154
176
|
cursor = start - propsSpan.start - 1;
|
|
155
177
|
while (cursor > 0 && /\s/.test(original[cursor])) cursor--;
|
|
156
178
|
if (original[cursor] === ",") start = propsSpan.start + cursor;
|
|
@@ -158,15 +180,18 @@ function compiledPropsEdits(input, styleEntries, replacement) {
|
|
|
158
180
|
edits.push({
|
|
159
181
|
start,
|
|
160
182
|
end,
|
|
161
|
-
content:
|
|
183
|
+
content: nonStyle,
|
|
162
184
|
origin: entry.span
|
|
163
185
|
});
|
|
164
186
|
}
|
|
165
187
|
const merged = [];
|
|
166
188
|
for (const edit of edits.sort((left, right) => left.start - right.start)) {
|
|
167
189
|
const previous = merged.at(-1);
|
|
168
|
-
if (previous && edit.start <= previous.end && !previous.content && !edit.content)
|
|
169
|
-
|
|
190
|
+
if (previous && edit.start <= previous.end && !previous.content && !edit.content) {
|
|
191
|
+
previous.end = Math.max(previous.end, edit.end);
|
|
192
|
+
} else {
|
|
193
|
+
merged.push(edit);
|
|
194
|
+
}
|
|
170
195
|
}
|
|
171
196
|
return merged;
|
|
172
197
|
}
|
|
@@ -421,7 +446,13 @@ const cssConflictFamilies = [
|
|
|
421
446
|
])
|
|
422
447
|
];
|
|
423
448
|
function cssOwnersConflict(left, right) {
|
|
424
|
-
for (const leftOwner of left)
|
|
449
|
+
for (const leftOwner of left) {
|
|
450
|
+
for (const rightOwner of right) {
|
|
451
|
+
if (leftOwner === rightOwner || cssShorthandConflicts[leftOwner]?.includes(rightOwner) || cssShorthandConflicts[rightOwner]?.includes(leftOwner) || cssConflictFamilies.some((family) => family.has(leftOwner) && family.has(rightOwner))) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
425
456
|
return false;
|
|
426
457
|
}
|
|
427
458
|
const runtimeEventProps = /* @__PURE__ */ new Set([
|
|
@@ -442,7 +473,9 @@ const nativePointerEventProps = /* @__PURE__ */ new Set([
|
|
|
442
473
|
"onPointerUp"
|
|
443
474
|
]);
|
|
444
475
|
function isSerializableNativeStyle(value) {
|
|
445
|
-
if (value == null || typeof value === "number" || typeof value === "boolean")
|
|
476
|
+
if (value == null || typeof value === "number" || typeof value === "boolean") {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
446
479
|
if (typeof value === "string") return true;
|
|
447
480
|
if (Array.isArray(value)) return value.every(isSerializableNativeStyle);
|
|
448
481
|
if (!staticObject(value)) return false;
|
|
@@ -453,7 +486,9 @@ function isSerializableNativeStyle(value) {
|
|
|
453
486
|
function unusedIdentifier(source, base) {
|
|
454
487
|
let candidate = base;
|
|
455
488
|
let suffix = 0;
|
|
456
|
-
while (new RegExp(`\\b${candidate}\\b`).test(source))
|
|
489
|
+
while (new RegExp(`\\b${candidate}\\b`).test(source)) {
|
|
490
|
+
candidate = `${base}${++suffix}`;
|
|
491
|
+
}
|
|
457
492
|
return candidate;
|
|
458
493
|
}
|
|
459
494
|
const VIEW_WRAPPER_PROPS = /^(aria-|accessibilityState$|accessibilityValue$|id$|tabIndex$|nativeID$)/;
|
|
@@ -487,7 +522,9 @@ function nativeDOMProps(input, tag) {
|
|
|
487
522
|
const entries = input.element.entries.filter((entry) => entry.kind === "prop");
|
|
488
523
|
const names = new Set(entries.map((entry) => entry.name));
|
|
489
524
|
if (names.has("ref") || tag === "br") additions.push(["__tag", JSON.stringify(tag)]);
|
|
490
|
-
if (TAGS[tag].backing === "text" || TAGS[tag].backing === "textinput")
|
|
525
|
+
if (TAGS[tag].backing === "text" || TAGS[tag].backing === "textinput") {
|
|
526
|
+
additions.push(["__inherit", "true"]);
|
|
527
|
+
}
|
|
491
528
|
const add = (name, value) => additions.push([name, value]);
|
|
492
529
|
const consume = (entry) => consumed.push(entry);
|
|
493
530
|
for (const entry of entries) {
|
|
@@ -495,20 +532,24 @@ function nativeDOMProps(input, tag) {
|
|
|
495
532
|
const attribute = (Object.hasOwn(ATTRIBUTES, entry.name) ? ATTRIBUTES[entry.name] : void 0) ?? (entry.name.startsWith("data-") ? ATTRIBUTES["data-*"] : void 0);
|
|
496
533
|
const event = Object.hasOwn(EVENTS, entry.name) ? EVENTS[entry.name] : void 0;
|
|
497
534
|
if (event) {
|
|
498
|
-
if (event.native === "none")
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
535
|
+
if (event.native === "none") {
|
|
536
|
+
return {
|
|
537
|
+
consumed,
|
|
538
|
+
edits,
|
|
539
|
+
additions,
|
|
540
|
+
diagnostic: `${entry.name} has no native DOM event equivalent`,
|
|
541
|
+
diagnosticSpan: entry.span
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
if (entry.name === "onKeyDown" && tag !== "input" && tag !== "textarea") {
|
|
545
|
+
return {
|
|
546
|
+
consumed,
|
|
547
|
+
edits,
|
|
548
|
+
additions,
|
|
549
|
+
diagnostic: `onKeyDown requires a native text-entry control`,
|
|
550
|
+
diagnosticSpan: entry.span
|
|
551
|
+
};
|
|
552
|
+
}
|
|
512
553
|
if ([
|
|
513
554
|
"onClick",
|
|
514
555
|
"onLoad",
|
|
@@ -516,7 +557,9 @@ function nativeDOMProps(input, tag) {
|
|
|
516
557
|
"onChange",
|
|
517
558
|
"onInput",
|
|
518
559
|
"onKeyDown"
|
|
519
|
-
].includes(entry.name))
|
|
560
|
+
].includes(entry.name)) {
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
520
563
|
if (event.nativeProp) {
|
|
521
564
|
const edit2 = renamedPropEdit(input, entry, event.nativeProp);
|
|
522
565
|
if (edit2) edits.push(edit2);
|
|
@@ -525,24 +568,28 @@ function nativeDOMProps(input, tag) {
|
|
|
525
568
|
}
|
|
526
569
|
if (!attribute || attribute.native === "none" || entry.name === "style") continue;
|
|
527
570
|
if (DOM_STYLE_ATTRIBUTES.has(entry.name)) {
|
|
528
|
-
if (entry.value.kind !== "static")
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
571
|
+
if (entry.value.kind !== "static") {
|
|
572
|
+
return {
|
|
573
|
+
consumed,
|
|
574
|
+
edits,
|
|
575
|
+
additions,
|
|
576
|
+
diagnostic: `html.${tag} ${entry.name} must be statically known for native lowering`,
|
|
577
|
+
diagnosticSpan: entry.span
|
|
578
|
+
};
|
|
579
|
+
}
|
|
535
580
|
consume(entry);
|
|
536
581
|
continue;
|
|
537
582
|
}
|
|
538
583
|
if (entry.name === "hidden") {
|
|
539
|
-
if (entry.value.kind !== "static")
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
584
|
+
if (entry.value.kind !== "static") {
|
|
585
|
+
return {
|
|
586
|
+
consumed,
|
|
587
|
+
edits,
|
|
588
|
+
additions,
|
|
589
|
+
diagnostic: `html.${tag} hidden must be statically known for native lowering`,
|
|
590
|
+
diagnosticSpan: entry.span
|
|
591
|
+
};
|
|
592
|
+
}
|
|
546
593
|
consume(entry);
|
|
547
594
|
continue;
|
|
548
595
|
}
|
|
@@ -568,18 +615,22 @@ function nativeDOMProps(input, tag) {
|
|
|
568
615
|
}
|
|
569
616
|
if (entry.name === "type") {
|
|
570
617
|
consume(entry);
|
|
571
|
-
if (tag === "input" && entry.value.kind !== "static")
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
618
|
+
if (tag === "input" && entry.value.kind !== "static") {
|
|
619
|
+
return {
|
|
620
|
+
consumed,
|
|
621
|
+
edits,
|
|
622
|
+
additions,
|
|
623
|
+
diagnostic: `html.input type must be statically known for native lowering`,
|
|
624
|
+
diagnosticSpan: entry.span
|
|
625
|
+
};
|
|
626
|
+
}
|
|
578
627
|
if (tag === "input" && entry.value.kind === "static") {
|
|
579
628
|
const type = entry.value.value;
|
|
580
629
|
if (type === "password") add("secureTextEntry", "true");
|
|
581
630
|
else if (typeof type === "string" && type !== "text" && NATIVE_INPUT_TYPES.includes(type)) {
|
|
582
|
-
if (!names.has("inputMode"))
|
|
631
|
+
if (!names.has("inputMode")) {
|
|
632
|
+
add("inputMode", JSON.stringify(type === "number" ? "numeric" : type));
|
|
633
|
+
}
|
|
583
634
|
}
|
|
584
635
|
}
|
|
585
636
|
continue;
|
|
@@ -608,7 +659,9 @@ function nativeDOMProps(input, tag) {
|
|
|
608
659
|
const edit = renamedPropEdit(input, entry, nativeProp);
|
|
609
660
|
if (edit) edits.push(edit);
|
|
610
661
|
}
|
|
611
|
-
for (const [name, values] of nested)
|
|
662
|
+
for (const [name, values] of nested) {
|
|
663
|
+
add(name, `{ ${values.map(([key, value]) => `${key}: ${value}`).join(", ")} }`);
|
|
664
|
+
}
|
|
612
665
|
if (!names.has("role") && TAGS[tag].role) add("role", JSON.stringify(TAGS[tag].role));
|
|
613
666
|
if (tag === "textarea") add("multiline", "true");
|
|
614
667
|
return {
|
|
@@ -627,15 +680,19 @@ function webDOMProps(input, tag) {
|
|
|
627
680
|
const edit = renamedPropEdit(input, entry, "htmlFor");
|
|
628
681
|
if (edit) edits.push(edit);
|
|
629
682
|
}
|
|
630
|
-
if (entry.name === "role" && entry.value.kind === "static" && entry.value.value === "none")
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
683
|
+
if (entry.name === "role" && entry.value.kind === "static" && entry.value.value === "none") {
|
|
684
|
+
edits.push({
|
|
685
|
+
start: entry.value.span.start,
|
|
686
|
+
end: entry.value.span.end,
|
|
687
|
+
content: JSON.stringify("presentation"),
|
|
688
|
+
origin: entry.value.span
|
|
689
|
+
});
|
|
690
|
+
}
|
|
636
691
|
}
|
|
637
692
|
if (tag === "button" && !names.has("type")) additions.push(["type", "\"button\""]);
|
|
638
|
-
if ((tag === "input" || tag === "textarea") && !names.has("dir"))
|
|
693
|
+
if ((tag === "input" || tag === "textarea") && !names.has("dir")) {
|
|
694
|
+
additions.push(["dir", "\"auto\""]);
|
|
695
|
+
}
|
|
639
696
|
return {
|
|
640
697
|
edits,
|
|
641
698
|
additions
|
|
@@ -645,7 +702,8 @@ function createTamaguiCompilerHost(options) {
|
|
|
645
702
|
const platform = options.target === "native" ? "native" : "web";
|
|
646
703
|
const core = requireTamaguiCore(platform);
|
|
647
704
|
const firstThemeName = Object.keys(options.tamaguiConfig.themes ?? {})[0] ?? "";
|
|
648
|
-
const
|
|
705
|
+
const firstTheme = options.tamaguiConfig.themes?.[firstThemeName] ?? {};
|
|
706
|
+
const theme = firstTheme;
|
|
649
707
|
const modifierRegistry = createModifierRegistry({
|
|
650
708
|
mediaNames: options.tamaguiConfig.media ?? {},
|
|
651
709
|
themeNames: options.tamaguiConfig.themes ?? {}
|
|
@@ -682,17 +740,25 @@ function createTamaguiCompilerHost(options) {
|
|
|
682
740
|
resolvedPayloads.push(payload);
|
|
683
741
|
continue;
|
|
684
742
|
}
|
|
685
|
-
if (transition.value.entries.length !== 1 || transition.value.entries[0].timing.type !== "preset")
|
|
743
|
+
if (transition.value.entries.length !== 1 || transition.value.entries[0].timing.type !== "preset") {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
686
746
|
const preset = transitionPresets[transition.value.entries[0].timing.name];
|
|
687
747
|
if (typeof preset !== "string") return null;
|
|
688
748
|
const parsedPreset = parseTransition(preset);
|
|
689
|
-
if (!parsedPreset.ok || parsedPreset.value.kind !== "transition" || parsedPreset.value.entries.length !== 1 || parsedPreset.value.entries[0].property !== "all" || parsedPreset.value.entries[0].timing.type !== "css")
|
|
749
|
+
if (!parsedPreset.ok || parsedPreset.value.kind !== "transition" || parsedPreset.value.entries.length !== 1 || parsedPreset.value.entries[0].property !== "all" || parsedPreset.value.entries[0].timing.type !== "css") {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
690
752
|
resolvedPayloads.push(`all ${preset}`);
|
|
691
753
|
}
|
|
692
754
|
let payloadIndex = 0;
|
|
693
755
|
const resolved = [];
|
|
694
|
-
if (program.value.base !== null)
|
|
695
|
-
|
|
756
|
+
if (program.value.base !== null) {
|
|
757
|
+
resolved.push(resolvedPayloads[payloadIndex++]);
|
|
758
|
+
}
|
|
759
|
+
for (const clause of program.value.clauses) {
|
|
760
|
+
resolved.push(`${clause.modifiers.join(":")}:${resolvedPayloads[payloadIndex++]}`);
|
|
761
|
+
}
|
|
696
762
|
return resolved.join(" ");
|
|
697
763
|
};
|
|
698
764
|
const modulesById = new Map(options.componentModules.map((module) => [module.resolvedId, module.moduleName]));
|
|
@@ -702,7 +768,8 @@ function createTamaguiCompilerHost(options) {
|
|
|
702
768
|
const identity = element.component.provenance;
|
|
703
769
|
if (!identity) return null;
|
|
704
770
|
const moduleName = modulesById.get(identity.resolvedId);
|
|
705
|
-
const
|
|
771
|
+
const component = moduleName ? componentsByModule.get(moduleName) : void 0;
|
|
772
|
+
const info = component?.nameToInfo[identity.importedName];
|
|
706
773
|
return info ? {
|
|
707
774
|
key: componentKey(identity.resolvedId, identity.importedName),
|
|
708
775
|
staticConfig: normalizeStaticConfig(info.staticConfig),
|
|
@@ -712,9 +779,12 @@ function createTamaguiCompilerHost(options) {
|
|
|
712
779
|
const domStaticConfig = (element) => {
|
|
713
780
|
const identity = element.component.provenance;
|
|
714
781
|
const tag = element.component.name;
|
|
715
|
-
if (identity?.importedName !== "html" || !DOM_FRONTENDS.has(identity.specifier) || !Object.hasOwn(TAGS, tag))
|
|
782
|
+
if (identity?.importedName !== "html" || !DOM_FRONTENDS.has(identity.specifier) || !Object.hasOwn(TAGS, tag)) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
716
785
|
const row = TAGS[tag];
|
|
717
|
-
const
|
|
786
|
+
const textLike = row.backing === "text" || row.backing === "textinput";
|
|
787
|
+
const base = (textLike ? core.Text : core.View)?.staticConfig;
|
|
718
788
|
if (!base) return null;
|
|
719
789
|
const platformDefaults = platform === "web" ? {
|
|
720
790
|
...DISPLAY_WEB_RESET[row.display],
|
|
@@ -818,7 +888,9 @@ function createTamaguiCompilerHost(options) {
|
|
|
818
888
|
return name in stylePropsAll && !isValidStyleKey(name, validStyles$1, staticConfig.accept);
|
|
819
889
|
};
|
|
820
890
|
const directStyleName = (name, component) => {
|
|
821
|
-
if (compilerStyleProps.has(name) || name === "style")
|
|
891
|
+
if (compilerStyleProps.has(name) || name === "style") {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
822
894
|
const staticConfig = component.staticConfig;
|
|
823
895
|
if (staticConfig.variants?.[name]) return null;
|
|
824
896
|
const expanded = options.tamaguiConfig.shorthands?.[name] ?? name;
|
|
@@ -826,11 +898,15 @@ function createTamaguiCompilerHost(options) {
|
|
|
826
898
|
};
|
|
827
899
|
const resolveSplitStyles = (props, staticConfig, animationDriver, displayName) => {
|
|
828
900
|
const previousStatic = process.env.IS_STATIC;
|
|
829
|
-
const previousTarget =
|
|
830
|
-
if (platform === "native")
|
|
831
|
-
|
|
901
|
+
const previousTarget = process.env.TAMAGUI_TARGET;
|
|
902
|
+
if (platform === "native") {
|
|
903
|
+
process.env.IS_STATIC = "is_static";
|
|
904
|
+
} else {
|
|
905
|
+
delete process.env.IS_STATIC;
|
|
906
|
+
}
|
|
832
907
|
process.env.TAMAGUI_TARGET = platform;
|
|
833
908
|
try {
|
|
909
|
+
core.prepareStyleStaticConfig(staticConfig);
|
|
834
910
|
return core.getSplitStyles(props, staticConfig, theme, firstThemeName, componentState, {
|
|
835
911
|
resolveValues: platform === "native" ? "except-theme" : "variable",
|
|
836
912
|
noClass: platform === "native",
|
|
@@ -840,7 +916,8 @@ function createTamaguiCompilerHost(options) {
|
|
|
840
916
|
} finally {
|
|
841
917
|
if (previousStatic === void 0) delete process.env.IS_STATIC;
|
|
842
918
|
else process.env.IS_STATIC = previousStatic;
|
|
843
|
-
process.env.TAMAGUI_TARGET
|
|
919
|
+
if (previousTarget === void 0) delete process.env.TAMAGUI_TARGET;
|
|
920
|
+
else process.env.TAMAGUI_TARGET = previousTarget;
|
|
844
921
|
}
|
|
845
922
|
};
|
|
846
923
|
const partialStaticConfig = (staticConfig) => ({
|
|
@@ -855,7 +932,9 @@ function createTamaguiCompilerHost(options) {
|
|
|
855
932
|
const split = resolveSplitStyles({ [name]: value }, partialStaticConfig(staticConfig));
|
|
856
933
|
if (!split) return null;
|
|
857
934
|
const inlineStyle = split.viewProps?.style;
|
|
858
|
-
if (staticObject(inlineStyle) &&
|
|
935
|
+
if (staticObject(inlineStyle) && Object.keys(inlineStyle).length > 0) {
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
859
938
|
const owners = new Set(Object.keys(split.classNames ?? {}));
|
|
860
939
|
for (const styleObject of Object.values(split.rulesToInsert ?? {})) {
|
|
861
940
|
const property = styleObject?.[StyleObjectProperty];
|
|
@@ -864,7 +943,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
864
943
|
return owners.size > 0 ? owners : null;
|
|
865
944
|
};
|
|
866
945
|
const dynamicStyleOwners = (name, staticConfig) => {
|
|
867
|
-
const
|
|
946
|
+
const probeValue = name === "transform" ? [{ scale: 1 }] : name === "transformMatrix" ? [
|
|
868
947
|
1,
|
|
869
948
|
0,
|
|
870
949
|
0,
|
|
@@ -874,7 +953,8 @@ function createTamaguiCompilerHost(options) {
|
|
|
874
953
|
] : name === "shadowOffset" ? {
|
|
875
954
|
width: 0,
|
|
876
955
|
height: 0
|
|
877
|
-
} : name === "shadowColor" ? "black" : name === "border" || name === "outline" ? "0 solid transparent" : name === "position" ? "relative" : name === "objectFit" ? "contain" : 0
|
|
956
|
+
} : name === "shadowColor" ? "black" : name === "border" || name === "outline" ? "0 solid transparent" : name === "position" ? "relative" : name === "objectFit" ? "contain" : 0;
|
|
957
|
+
const owners = styleOwners(name, probeValue, staticConfig);
|
|
878
958
|
if (!owners || name !== "flex") return owners;
|
|
879
959
|
const shorthandOwners = styleOwners(name, "0 1 auto", staticConfig);
|
|
880
960
|
if (!shorthandOwners) return null;
|
|
@@ -895,28 +975,35 @@ function createTamaguiCompilerHost(options) {
|
|
|
895
975
|
] : ["bailed"];
|
|
896
976
|
const why = result.ok ? flattened ? "Static styles were lowered and the component was flattened to a host element." : "Static styles were lowered while the Tamagui component remained at runtime." : result.bailout.message;
|
|
897
977
|
const styles = styleEntries.map((entry) => {
|
|
898
|
-
if (!result.ok)
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
978
|
+
if (!result.ok) {
|
|
979
|
+
return {
|
|
980
|
+
prop: entry.name,
|
|
981
|
+
tier: "bailed",
|
|
982
|
+
runtime: true,
|
|
983
|
+
why: `${result.bailout.message}. The Tamagui runtime resolved this prop.`
|
|
984
|
+
};
|
|
985
|
+
}
|
|
904
986
|
const edited = result.edits.some((edit) => edit.start < entry.span.end && edit.end > entry.span.start);
|
|
905
|
-
if (!flattened && !edited)
|
|
906
|
-
|
|
907
|
-
tier: "bailed",
|
|
908
|
-
runtime: true,
|
|
909
|
-
why: "This prop remained for Tamagui runtime resolution."
|
|
910
|
-
};
|
|
911
|
-
if (entry.value.kind === "static") {
|
|
912
|
-
const split = resolveSplitStyles({ [entry.name]: entry.value.value }, partialStaticConfig(component.staticConfig));
|
|
913
|
-
if (!Boolean(split && (Object.keys(split.classNames ?? {}).length > 0 || Object.keys(split.rulesToInsert ?? {}).length > 0 || staticObject(split.style) && Object.keys(split.style).length > 0 || staticObject(split.viewProps?.style) && Object.keys(split.viewProps.style).length > 0))) return {
|
|
987
|
+
if (!flattened && !edited) {
|
|
988
|
+
return {
|
|
914
989
|
prop: entry.name,
|
|
915
|
-
tier:
|
|
916
|
-
|
|
917
|
-
why:
|
|
990
|
+
tier: "bailed",
|
|
991
|
+
runtime: true,
|
|
992
|
+
why: "This prop remained for Tamagui runtime resolution."
|
|
918
993
|
};
|
|
919
994
|
}
|
|
995
|
+
if (entry.value.kind === "static") {
|
|
996
|
+
const split = resolveSplitStyles({ [entry.name]: entry.value.value }, partialStaticConfig(component.staticConfig));
|
|
997
|
+
const hasOutput = Boolean(split && (Object.keys(split.classNames ?? {}).length > 0 || Object.keys(split.rulesToInsert ?? {}).length > 0 || staticObject(split.style) && Object.keys(split.style).length > 0 || staticObject(split.viewProps?.style) && Object.keys(split.viewProps.style).length > 0));
|
|
998
|
+
if (!hasOutput) {
|
|
999
|
+
return {
|
|
1000
|
+
prop: entry.name,
|
|
1001
|
+
tier: flattened ? "flattened" : "lowered",
|
|
1002
|
+
dropped: true,
|
|
1003
|
+
why: `No ${platform} style output was produced for this prop.`
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
920
1007
|
return {
|
|
921
1008
|
prop: entry.name,
|
|
922
1009
|
tier: flattened ? "flattened" : "lowered",
|
|
@@ -941,68 +1028,94 @@ function createTamaguiCompilerHost(options) {
|
|
|
941
1028
|
resolveComponent: resolve,
|
|
942
1029
|
isStyleProp,
|
|
943
1030
|
canLowerDynamicStyleProp(name, component, valueKind) {
|
|
944
|
-
if (!options.disablePartialExtraction && valueKind === "conditional" && canLowerConditionalStyleProp(name, component))
|
|
1031
|
+
if (!options.disablePartialExtraction && valueKind === "conditional" && canLowerConditionalStyleProp(name, component)) {
|
|
1032
|
+
return true;
|
|
1033
|
+
}
|
|
945
1034
|
return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && directStyleName(name, component) === "opacity");
|
|
946
1035
|
},
|
|
947
1036
|
developmentDebugInstrumentation,
|
|
948
1037
|
lowerCandidate(input) {
|
|
949
1038
|
const component = input.component;
|
|
950
|
-
if (!component.canFlatten)
|
|
1039
|
+
if (!component.canFlatten) {
|
|
1040
|
+
const reason = component.staticConfig.acceptsClassName === false ? `${component.key} does not accept className` : component.staticConfig.neverFlatten ? `${component.key} is never flattened (behavior HOC)` : `${component.key} provides a styled context`;
|
|
1041
|
+
return bailout(input, "local/unsupported-target", reason, input.element.span, { rule: 6 });
|
|
1042
|
+
}
|
|
951
1043
|
if (options.zeroRuntime) {
|
|
952
1044
|
const spread = input.element.entries.find((entry) => entry.kind === "spread");
|
|
953
|
-
if (spread)
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1045
|
+
if (spread) {
|
|
1046
|
+
return bailout(input, "local/unsafe-style-spread", "Zero-runtime rejects prop spreads", spread.span, {
|
|
1047
|
+
rule: 1,
|
|
1048
|
+
message: zeroRuleMessage(1, { component: input.element.component.name })
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
957
1051
|
}
|
|
958
1052
|
const props = {};
|
|
959
1053
|
for (const entry of input.element.entries) {
|
|
960
1054
|
if (entry.kind === "child" || entry.value.kind !== "static") continue;
|
|
961
1055
|
if (entry.kind === "spread") {
|
|
962
|
-
if (!staticObject(entry.value.value))
|
|
1056
|
+
if (!staticObject(entry.value.value)) {
|
|
1057
|
+
return bailout(input, "local/unsafe-style-spread", "Static spread did not materialize to an object", entry.span);
|
|
1058
|
+
}
|
|
963
1059
|
Object.assign(props, entry.value.value);
|
|
964
|
-
} else
|
|
1060
|
+
} else {
|
|
1061
|
+
props[entry.name] = entry.value.value;
|
|
1062
|
+
}
|
|
965
1063
|
}
|
|
966
1064
|
const disableOptimizationEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "disableOptimization");
|
|
967
|
-
if (disableOptimizationEntry || Object.hasOwn(props, "disableOptimization"))
|
|
1065
|
+
if (disableOptimizationEntry || Object.hasOwn(props, "disableOptimization")) {
|
|
1066
|
+
return bailout(input, "local/unsupported-target", "disableOptimization keeps the component on the runtime path", disableOptimizationEntry?.span);
|
|
1067
|
+
}
|
|
968
1068
|
if (component.domTag && props.hidden) props.display = "none";
|
|
969
1069
|
if (component.domTag && platform === "native") {
|
|
970
|
-
for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES)
|
|
971
|
-
|
|
972
|
-
|
|
1070
|
+
for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES) {
|
|
1071
|
+
if (name in props) {
|
|
1072
|
+
props[styleKey] = props[name];
|
|
1073
|
+
delete props[name];
|
|
1074
|
+
}
|
|
973
1075
|
}
|
|
974
1076
|
}
|
|
975
|
-
if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !NATIVE_INPUT_TYPES.includes(props.type))
|
|
1077
|
+
if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !NATIVE_INPUT_TYPES.includes(props.type)) {
|
|
1078
|
+
return bailout(input, "local/unsupported-target", `input type ${props.type} has no native text-entry control`);
|
|
1079
|
+
}
|
|
976
1080
|
const dynamicStyleEntries = input.element.entries.filter((entry) => entry.kind === "prop" && (entry.value.kind === "bailout" || entry.value.kind === "conditional") && isStyleProp(entry.name, component));
|
|
977
1081
|
{
|
|
978
1082
|
const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
|
|
979
1083
|
const directRuntimeEvent = input.element.entries.find((entry) => entry.kind === "prop" && needsRuntimeMapping(entry.name));
|
|
980
1084
|
const runtimeEvent = directRuntimeEvent?.kind === "prop" ? directRuntimeEvent.name : Object.keys(props).find(needsRuntimeMapping);
|
|
981
|
-
if (runtimeEvent)
|
|
1085
|
+
if (runtimeEvent) {
|
|
1086
|
+
return bailout(input, "local/unsupported-target", `${runtimeEvent} requires Tamagui runtime event mapping`);
|
|
1087
|
+
}
|
|
982
1088
|
}
|
|
983
1089
|
const animationDefaultProps = core.getDefaultProps(component.staticConfig) ?? {};
|
|
984
1090
|
const animationProps = core.mergeProps(animationDefaultProps, props);
|
|
985
1091
|
const animationNames = /* @__PURE__ */ new Set([...input.element.entries.flatMap((entry) => entry.kind === "prop" && runtimeAnimationProps.has(entry.name) ? [entry.name] : []), ...Object.keys(animationProps).filter((name) => runtimeAnimationProps.has(name) && animationProps[name] !== void 0)]);
|
|
986
1092
|
const animateOnlyEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "animateOnly");
|
|
987
|
-
if (animationNames.has("animateOnly"))
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1093
|
+
if (animationNames.has("animateOnly")) {
|
|
1094
|
+
return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", animateOnlyEntry?.span, {
|
|
1095
|
+
rule: 5,
|
|
1096
|
+
message: zeroRuleMessage(5, { detail: animateOnlyEntry ? `animateOnly on ${input.element.component.name}` : `animateOnly in the styled() definition of ${input.element.component.name}` })
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
991
1099
|
const transitionEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "transition");
|
|
992
1100
|
const animatedBy = typeof animationProps.animatedBy === "string" ? animationProps.animatedBy.trim() : null;
|
|
993
1101
|
const namedAnimationDriver = animatedBy === null ? null : options.tamaguiConfig.animationDrivers?.[animatedBy];
|
|
994
|
-
const
|
|
1102
|
+
const namedCssAnimationDriver = platform === "web" && namedAnimationDriver && !namedAnimationDriver.isStub && namedAnimationDriver.outputStyle === "css" ? namedAnimationDriver : null;
|
|
1103
|
+
const cssAnimationDriver = namedCssAnimationDriver ?? (animatedBy === null || animatedBy === "default" ? configuredCssAnimationDriver : null);
|
|
995
1104
|
const resolvedCssTransition = animationNames.has("transition") && cssAnimationDriver ? resolveStaticCssTransition(animationProps.transition, cssAnimationDriver.animations ?? {}) : null;
|
|
996
|
-
if (resolvedCssTransition !== null)
|
|
1105
|
+
if (resolvedCssTransition !== null) {
|
|
1106
|
+
props.transition = resolvedCssTransition;
|
|
1107
|
+
}
|
|
997
1108
|
const animatedByNeedsRuntime = animationNames.has("animatedBy") && !animationNames.has("transition") && (dynamicStyleEntries.length > 0 || Object.keys(animationProps).some((name) => name !== "animatedBy" && (isStyleProp(name, component) && typeof animationProps[name] === "string" && animationProps[name].includes(":") || name === "animationConfig" || name === "forceStyle" || name === "onTransition")));
|
|
998
1109
|
const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy" && name !== "animateOnly") || animatedByNeedsRuntime;
|
|
999
1110
|
let dynamicHostStyleProperties = null;
|
|
1000
|
-
if (platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.length > 0 && !input.element.entries.some((entry) => entry.kind === "spread")) {
|
|
1111
|
+
if (platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.length > 0 && !input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static")) {
|
|
1001
1112
|
const seen = /* @__PURE__ */ new Set();
|
|
1002
1113
|
const properties = [];
|
|
1003
1114
|
const dynamicOwners = /* @__PURE__ */ new Set();
|
|
1004
1115
|
for (const entry of dynamicStyleEntries) {
|
|
1005
|
-
if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional")
|
|
1116
|
+
if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional") {
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1006
1119
|
const name = directStyleName(entry.name, component);
|
|
1007
1120
|
if (!name || seen.has(name)) {
|
|
1008
1121
|
properties.length = 0;
|
|
@@ -1015,11 +1128,13 @@ function createTamaguiCompilerHost(options) {
|
|
|
1015
1128
|
}
|
|
1016
1129
|
let property = null;
|
|
1017
1130
|
const expression = input.source.slice(entry.value.span.start, entry.value.span.end);
|
|
1018
|
-
if (resolvedCssTransition !== null && (name === "opacity" || name === "scale"))
|
|
1019
|
-
|
|
1131
|
+
if (resolvedCssTransition !== null && (name === "opacity" || name === "scale")) {
|
|
1132
|
+
property = name === "opacity" ? `opacity: (${expression})` : `transform: "scale(" + (${expression}) + ")"`;
|
|
1133
|
+
} else if (entry.value.kind === "bailout" && owners.size === 1 && owners.has(name)) {
|
|
1020
1134
|
const dynamic = entry.value.dynamic;
|
|
1021
|
-
if (dynamic?.type === "number")
|
|
1022
|
-
|
|
1135
|
+
if (dynamic?.type === "number") {
|
|
1136
|
+
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1137
|
+
} else if (dynamic?.type === "string" && dynamic.values?.length) {
|
|
1023
1138
|
let valuesStayLiteral = true;
|
|
1024
1139
|
for (const value of dynamic.values) {
|
|
1025
1140
|
const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
|
|
@@ -1029,7 +1144,9 @@ function createTamaguiCompilerHost(options) {
|
|
|
1029
1144
|
break;
|
|
1030
1145
|
}
|
|
1031
1146
|
}
|
|
1032
|
-
if (valuesStayLiteral)
|
|
1147
|
+
if (valuesStayLiteral) {
|
|
1148
|
+
property = `${JSON.stringify(name)}: (${expression})`;
|
|
1149
|
+
}
|
|
1033
1150
|
}
|
|
1034
1151
|
}
|
|
1035
1152
|
if (!property) {
|
|
@@ -1046,9 +1163,11 @@ function createTamaguiCompilerHost(options) {
|
|
|
1046
1163
|
if (!name) return false;
|
|
1047
1164
|
const owners = styleOwners(name, entry.value.value, component.staticConfig);
|
|
1048
1165
|
return !!owners && cssOwnersConflict(owners, dynamicOwners);
|
|
1049
|
-
}))
|
|
1166
|
+
})) {
|
|
1167
|
+
dynamicHostStyleProperties = properties;
|
|
1168
|
+
}
|
|
1050
1169
|
}
|
|
1051
|
-
const supportsWebConditionalClasses = platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicHostStyleProperties === null && dynamicStyleEntries.length
|
|
1170
|
+
const supportsWebConditionalClasses = platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicHostStyleProperties === null && dynamicStyleEntries.length > 0 && dynamicStyleEntries.every((entry) => entry.kind === "prop" && entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component));
|
|
1052
1171
|
if ("theme" in props || "themeInverse" in props) {
|
|
1053
1172
|
const themeProp = "theme" in props ? "theme" : "themeInverse";
|
|
1054
1173
|
return bailout(input, "local/unsupported-target", "Theme boundary candidates remain on the runtime path", input.element.span, {
|
|
@@ -1057,14 +1176,20 @@ function createTamaguiCompilerHost(options) {
|
|
|
1057
1176
|
});
|
|
1058
1177
|
}
|
|
1059
1178
|
const asChildEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "asChild");
|
|
1060
|
-
if (asChildEntry || Object.hasOwn(props, "asChild"))
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1179
|
+
if (asChildEntry || Object.hasOwn(props, "asChild")) {
|
|
1180
|
+
return bailout(input, "local/unsupported-target", "asChild renders a Slot, not a host view", asChildEntry?.span);
|
|
1181
|
+
}
|
|
1182
|
+
if (platform === "native" && ("group" in props || "container" in props || "containerName" in props || "containerType" in props)) {
|
|
1183
|
+
return bailout(input, "local/unsupported-target", "Native group and container providers remain on the runtime path");
|
|
1184
|
+
}
|
|
1185
|
+
if (runtimeAnimationRequired && !cssAnimationDriver) {
|
|
1186
|
+
return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
|
|
1187
|
+
rule: 5,
|
|
1188
|
+
message: zeroRuleMessage(5, { detail: `the animation configured on ${input.element.component.name}` })
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1066
1191
|
if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) && dynamicHostStyleProperties === null && !supportsWebConditionalClasses && component.partialRuntimeSafe) {
|
|
1067
|
-
const hasSpread = input.element.entries.some((entry) => entry.kind === "spread");
|
|
1192
|
+
const hasSpread = input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static");
|
|
1068
1193
|
const unsupportedRuntimeStyle = input.element.entries.find((entry) => entry.kind === "prop" && isStyleProp(entry.name, component) && !runtimeAnimationProps.has(entry.name) && !directStyleName(entry.name, component));
|
|
1069
1194
|
if (!hasSpread && !unsupportedRuntimeStyle) {
|
|
1070
1195
|
const dynamicOwners = /* @__PURE__ */ new Set();
|
|
@@ -1093,49 +1218,59 @@ function createTamaguiCompilerHost(options) {
|
|
|
1093
1218
|
}) : [];
|
|
1094
1219
|
if (staticStyleEntries.length > 0) {
|
|
1095
1220
|
const partialProps = {};
|
|
1096
|
-
for (const entry of staticStyleEntries)
|
|
1221
|
+
for (const entry of staticStyleEntries) {
|
|
1222
|
+
if (entry.kind === "prop" && entry.value.kind === "static") {
|
|
1223
|
+
partialProps[entry.name] = entry.value.value;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1097
1226
|
const partialSplit = resolveSplitStyles(partialProps, partialStaticConfig(component.staticConfig));
|
|
1098
1227
|
const partialInlineStyle = partialSplit?.viewProps?.style;
|
|
1099
|
-
const hasPartialInlineStyle = staticObject(partialInlineStyle) &&
|
|
1228
|
+
const hasPartialInlineStyle = staticObject(partialInlineStyle) && Object.keys(partialInlineStyle).length > 0;
|
|
1100
1229
|
if (partialSplit && !hasPartialInlineStyle) {
|
|
1101
1230
|
const artifacts2 = extractedStyleArtifacts(partialSplit, partialProps, options.tamaguiConfig, false);
|
|
1102
|
-
if (artifacts2.className)
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1231
|
+
if (artifacts2.className) {
|
|
1232
|
+
if (input.element.form !== "jsx") {
|
|
1233
|
+
const propsEdits = compiledPropsEdits(input, staticStyleEntries, objectClassName(artifacts2.className));
|
|
1234
|
+
if (propsEdits) {
|
|
1235
|
+
return {
|
|
1236
|
+
ok: true,
|
|
1237
|
+
edits: propsEdits,
|
|
1238
|
+
css: artifacts2.css,
|
|
1239
|
+
imports: [],
|
|
1240
|
+
flattened: false
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
} else {
|
|
1244
|
+
const [first2, ...rest2] = staticStyleEntries;
|
|
1245
|
+
return {
|
|
1246
|
+
ok: true,
|
|
1247
|
+
edits: [{
|
|
1248
|
+
start: first2.span.start,
|
|
1249
|
+
end: first2.span.end,
|
|
1250
|
+
content: jsxClassName(artifacts2.className),
|
|
1251
|
+
origin: first2.span
|
|
1252
|
+
}, ...rest2.map((entry) => ({
|
|
1253
|
+
start: entry.span.start,
|
|
1254
|
+
end: entry.span.end,
|
|
1255
|
+
content: "",
|
|
1256
|
+
origin: entry.span
|
|
1257
|
+
}))],
|
|
1258
|
+
css: artifacts2.css,
|
|
1259
|
+
imports: [],
|
|
1260
|
+
flattened: false
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1130
1263
|
}
|
|
1131
1264
|
}
|
|
1132
1265
|
}
|
|
1133
1266
|
}
|
|
1134
1267
|
}
|
|
1135
|
-
if (runtimeAnimationRequired)
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1268
|
+
if (runtimeAnimationRequired) {
|
|
1269
|
+
return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
|
|
1270
|
+
rule: 5,
|
|
1271
|
+
message: zeroRuleMessage(5, { detail: `the animation configured on ${input.element.component.name}` })
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1139
1274
|
const supportsNativeDynamicStyles = platform === "native" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.every((entry) => entry.kind === "prop" && (directStyleName(entry.name, component) === "opacity" || entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component)));
|
|
1140
1275
|
if (dynamicStyleEntries.length > 0 && dynamicHostStyleProperties === null && !supportsNativeDynamicStyles && !supportsWebConditionalClasses) {
|
|
1141
1276
|
const entry = dynamicStyleEntries[0];
|
|
@@ -1144,18 +1279,59 @@ function createTamaguiCompilerHost(options) {
|
|
|
1144
1279
|
const staticDefaultProps = core.getDefaultProps(component.staticConfig) ?? {};
|
|
1145
1280
|
const defaultProps = platform === "web" && !component.staticConfig.isText && options.tamaguiConfig.settings.defaultPosition === "relative" && staticDefaultProps.position === void 0 ? core.mergeProps({ position: "relative" }, staticDefaultProps) : staticDefaultProps;
|
|
1146
1281
|
let completeProps = core.mergeProps(defaultProps, props);
|
|
1147
|
-
if (platform === "native" && component.domTag && props.display === "flex")
|
|
1282
|
+
if (platform === "native" && component.domTag && props.display === "flex") {
|
|
1283
|
+
completeProps = core.mergeProps(core.mergeProps(defaultProps, NATIVE_FLEX_DEFAULTS), props);
|
|
1284
|
+
}
|
|
1285
|
+
const propsForConditional = (target, value) => {
|
|
1286
|
+
const branchProps = {};
|
|
1287
|
+
for (const entry of input.element.entries) {
|
|
1288
|
+
if (entry === target) {
|
|
1289
|
+
branchProps[target.name] = value;
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
if (entry.kind === "child" || entry.value.kind !== "static") continue;
|
|
1293
|
+
if (entry.kind === "spread") {
|
|
1294
|
+
if (staticObject(entry.value.value)) Object.assign(branchProps, entry.value.value);
|
|
1295
|
+
} else {
|
|
1296
|
+
branchProps[entry.name] = entry.value.value;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
if (component.domTag && branchProps.hidden) branchProps.display = "none";
|
|
1300
|
+
if (resolvedCssTransition !== null) {
|
|
1301
|
+
branchProps.transition = resolvedCssTransition;
|
|
1302
|
+
}
|
|
1303
|
+
if (component.domTag && platform === "native") {
|
|
1304
|
+
for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES) {
|
|
1305
|
+
if (name in branchProps) {
|
|
1306
|
+
branchProps[styleKey] = branchProps[name];
|
|
1307
|
+
delete branchProps[name];
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
const branchCompleteProps = platform === "native" && component.domTag && branchProps.display === "flex" ? core.mergeProps(core.mergeProps(defaultProps, NATIVE_FLEX_DEFAULTS), branchProps) : core.mergeProps(defaultProps, branchProps);
|
|
1312
|
+
return {
|
|
1313
|
+
branchProps,
|
|
1314
|
+
branchCompleteProps
|
|
1315
|
+
};
|
|
1316
|
+
};
|
|
1148
1317
|
if (platform === "native") {
|
|
1149
1318
|
const isClauseValue = (name, value) => isStyleProp(name, component) && (typeof value === "string" && flatClausePattern.test(value) || isClauseObjectValue(value));
|
|
1150
1319
|
const defaultVariants = component.staticConfig.defaultVariants ?? {};
|
|
1151
|
-
|
|
1320
|
+
const carriesClause = Object.entries(completeProps).some(([name, value]) => isClauseValue(name, value)) || Object.entries(component.staticConfig.variants ?? {}).some(([variantName, definitions]) => (completeProps[variantName] !== void 0 || defaultVariants[variantName] !== void 0) && staticObject(definitions) && Object.values(definitions).some((definition) => staticObject(definition) && Object.entries(definition).some(([name, value]) => isClauseValue(name, value)))) || (component.staticConfig.compoundVariants ?? []).some((compound) => staticObject(compound) && staticObject(compound.style) && Object.entries(compound.style).some(([name, value]) => isClauseValue(name, value)));
|
|
1321
|
+
if (carriesClause) {
|
|
1322
|
+
return bailout(input, "local/unsupported-target", "Native conditional value programs remain on the runtime path");
|
|
1323
|
+
}
|
|
1152
1324
|
}
|
|
1153
1325
|
const split = resolveSplitStyles(completeProps, component.staticConfig, cssAnimationDriver, component.displayName);
|
|
1154
|
-
if (!split)
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1326
|
+
if (!split) {
|
|
1327
|
+
return bailout(input, "local/style-resolution-failed", "getSplitStyles returned no static result");
|
|
1328
|
+
}
|
|
1329
|
+
if (split.programLifecycleStyleKeys?.enter?.size || split.programLifecycleStyleKeys?.exit?.size) {
|
|
1330
|
+
return bailout(input, "local/unsupported-target", "Lifecycle value programs remain on the runtime path", input.element.span, {
|
|
1331
|
+
rule: 5,
|
|
1332
|
+
message: zeroRuleMessage(5, { detail: `an enter or exit style program on ${input.element.component.name}` })
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1159
1335
|
const domStyleProgram = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "style" && entry.value.kind === "dom-style");
|
|
1160
1336
|
const flatTag = component.domTag ?? (typeof props.render === "string" ? props.render : typeof defaultProps.render === "string" ? defaultProps.render : component.staticConfig.isText ? "span" : "div");
|
|
1161
1337
|
const tagEdits = [input.element.component.span, input.element.component.closingSpan].filter((span) => !!span).map((span) => ({
|
|
@@ -1164,7 +1340,17 @@ function createTamaguiCompilerHost(options) {
|
|
|
1164
1340
|
content: input.element.form === "jsx" ? flatTag : JSON.stringify(flatTag),
|
|
1165
1341
|
origin: span
|
|
1166
1342
|
}));
|
|
1167
|
-
|
|
1343
|
+
const isPropIgnored = (name) => isStyleProp(name, component) || isInvalidHostStyleProp(name, component);
|
|
1344
|
+
const spreadReplacement = (form, entry) => spreadNonStyleReplacement(form, entry, isPropIgnored, (name, value) => {
|
|
1345
|
+
if (platform !== "web") return [name, value];
|
|
1346
|
+
if (name === "testID") return ["data-testid", value];
|
|
1347
|
+
if (component.domTag && name === "for") return ["htmlFor", value];
|
|
1348
|
+
if (component.domTag && name === "role" && value === "none") {
|
|
1349
|
+
return ["role", "presentation"];
|
|
1350
|
+
}
|
|
1351
|
+
return [name, value];
|
|
1352
|
+
});
|
|
1353
|
+
let styleEntries = input.element.entries.filter((entry) => entry.kind === "prop" && (isStyleProp(entry.name, component) || isInvalidHostStyleProp(entry.name, component)) || entry.kind === "spread" && entry.value.kind === "static" && staticObject(entry.value.value) && Object.keys(entry.value.value).some((name) => isStyleProp(name, component) || isInvalidHostStyleProp(name, component)));
|
|
1168
1354
|
let invalidHostStyle;
|
|
1169
1355
|
for (const entry of input.element.entries) {
|
|
1170
1356
|
if (entry.kind === "prop") {
|
|
@@ -1188,7 +1374,15 @@ function createTamaguiCompilerHost(options) {
|
|
|
1188
1374
|
}
|
|
1189
1375
|
}
|
|
1190
1376
|
}
|
|
1191
|
-
if (invalidHostStyle)
|
|
1377
|
+
if (invalidHostStyle) {
|
|
1378
|
+
return bailout(input, "local/unsupported-target", `"${invalidHostStyle.name}" is a text style prop and this component is not text. Use a Text-based component, or html.* for raw web elements.`, invalidHostStyle.entry.span);
|
|
1379
|
+
}
|
|
1380
|
+
if (platform === "native" && component.domTag) {
|
|
1381
|
+
const mixedSpread = styleEntries.find((entry) => entry.kind === "spread" && entry.value.kind === "static" && staticObject(entry.value.value) && Object.keys(entry.value.value).some((name) => !isPropIgnored(name)));
|
|
1382
|
+
if (mixedSpread) {
|
|
1383
|
+
return bailout(input, "local/unsafe-style-spread", "Native DOM prop mapping requires non-style spread props to remain on the runtime path", mixedSpread.span);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1192
1386
|
const webPropEdits = platform === "web" ? input.element.entries.flatMap((entry) => {
|
|
1193
1387
|
if (entry.kind !== "prop" || entry.name !== "testID") return [];
|
|
1194
1388
|
const content = input.source.slice(entry.span.start, entry.span.end);
|
|
@@ -1197,7 +1391,7 @@ function createTamaguiCompilerHost(options) {
|
|
|
1197
1391
|
const alreadyQuoted = content[nameOffset - 1] === "\"" || content[nameOffset - 1] === "'";
|
|
1198
1392
|
return [{
|
|
1199
1393
|
start: entry.span.start + nameOffset,
|
|
1200
|
-
end: entry.span.start + nameOffset +
|
|
1394
|
+
end: entry.span.start + nameOffset + "testID".length,
|
|
1201
1395
|
content: input.element.form === "jsx" || alreadyQuoted ? "data-testid" : `'data-testid'`,
|
|
1202
1396
|
origin: entry.span
|
|
1203
1397
|
}];
|
|
@@ -1207,8 +1401,6 @@ function createTamaguiCompilerHost(options) {
|
|
|
1207
1401
|
additions: []
|
|
1208
1402
|
};
|
|
1209
1403
|
webPropEdits.push(...webDOMResult.edits);
|
|
1210
|
-
const unsafeSpread = input.element.entries.find((entry) => entry.kind === "spread" && !styleEntries.includes(entry) && entry.value.kind === "static" && staticObject(entry.value.value) && Object.keys(entry.value.value).some((name) => isStyleProp(name, component)));
|
|
1211
|
-
if (unsafeSpread) return bailout(input, "local/unsafe-style-spread", "A mixed style/non-style spread cannot be removed transactionally", unsafeSpread.span);
|
|
1212
1404
|
if (platform === "native") {
|
|
1213
1405
|
const nativeStyleResolved = split.viewProps?.style;
|
|
1214
1406
|
let themedStyleKeys = null;
|
|
@@ -1217,16 +1409,25 @@ function createTamaguiCompilerHost(options) {
|
|
|
1217
1409
|
for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved)) {
|
|
1218
1410
|
if (!core.containsThemeRef(styleValue)) continue;
|
|
1219
1411
|
const themeKey = core.themeRefKey(styleValue);
|
|
1220
|
-
if (!themeKey)
|
|
1412
|
+
if (!themeKey) {
|
|
1413
|
+
return bailout(input, "local/dynamic-style-value", `Style ${styleKey} uses a theme value in a compound or modified position that compiled output cannot represent`);
|
|
1414
|
+
}
|
|
1415
|
+
;
|
|
1221
1416
|
(themedStyleKeys ||= {})[styleKey] = themeKey;
|
|
1222
1417
|
}
|
|
1223
1418
|
if (themedStyleKeys) {
|
|
1224
1419
|
const plain = {};
|
|
1225
|
-
for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved))
|
|
1420
|
+
for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved)) {
|
|
1421
|
+
if (!(styleKey in themedStyleKeys)) plain[styleKey] = styleValue;
|
|
1422
|
+
}
|
|
1226
1423
|
nativeStyle = plain;
|
|
1227
1424
|
}
|
|
1228
|
-
} else if (core.containsThemeRef(nativeStyleResolved))
|
|
1229
|
-
|
|
1425
|
+
} else if (core.containsThemeRef(nativeStyleResolved)) {
|
|
1426
|
+
return bailout(input, "local/dynamic-style-value", "Theme values inside non-object native style output stay on the runtime path");
|
|
1427
|
+
}
|
|
1428
|
+
if (!isSerializableNativeStyle(nativeStyle)) {
|
|
1429
|
+
return bailout(input, "local/unsupported-target", "Native style output is not a static serializable value");
|
|
1430
|
+
}
|
|
1230
1431
|
const nativeStyleLocal = unusedIdentifier(input.source, `__TamaguiNativeStyle${input.element.span.start}`);
|
|
1231
1432
|
const nativeStyleImports = [{
|
|
1232
1433
|
content: `
|
|
@@ -1247,12 +1448,16 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
|
|
|
1247
1448
|
};
|
|
1248
1449
|
}
|
|
1249
1450
|
if (component.domTag) {
|
|
1250
|
-
if (themedStyleKeys)
|
|
1451
|
+
if (themedStyleKeys) {
|
|
1452
|
+
return bailout(input, "local/unsupported-target", "Theme values on DOM-tag native output stay on the runtime path");
|
|
1453
|
+
}
|
|
1251
1454
|
const row = TAGS[component.domTag];
|
|
1252
1455
|
const basePrimitive = NATIVE_BACKING[row.backing].primitive;
|
|
1253
1456
|
let primitive = basePrimitive;
|
|
1254
1457
|
const propsResult = nativeDOMProps(input, component.domTag);
|
|
1255
|
-
if (propsResult.diagnostic)
|
|
1458
|
+
if (propsResult.diagnostic) {
|
|
1459
|
+
return bailout(input, "local/unsupported-target", propsResult.diagnostic, propsResult.diagnosticSpan);
|
|
1460
|
+
}
|
|
1256
1461
|
styleEntries = [.../* @__PURE__ */ new Set([...styleEntries, ...propsResult.consumed])];
|
|
1257
1462
|
let nativeDOMStyleSource = nativeStyleSource;
|
|
1258
1463
|
let runtimeStyleSource = null;
|
|
@@ -1260,22 +1465,32 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
|
|
|
1260
1465
|
const needsRuntime = domStyleProgram.value.items.some((item) => item.value.kind === "static" && staticObject(item.value.value) && (Object.keys(item.value.value).some((property) => nativeRuntimeOnlyStyleProperties.has(property)) || Object.values(item.value.value).some((value) => typeof value === "string" && (flatClausePattern.test(value) || nativeInheritedKeywordPattern.test(value)) || isClauseObjectValue(value))));
|
|
1261
1466
|
const itemSources = [];
|
|
1262
1467
|
for (const item of domStyleProgram.value.items) {
|
|
1263
|
-
if (item.value.kind !== "static" || !staticObject(item.value.value))
|
|
1264
|
-
|
|
1468
|
+
if (item.value.kind !== "static" || !staticObject(item.value.value)) {
|
|
1469
|
+
return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
|
|
1470
|
+
}
|
|
1471
|
+
if (Object.values(item.value.value).some((value2) => typeof value2 === "string" && nativeInitialKeywordPattern.test(value2))) {
|
|
1472
|
+
return bailout(input, "local/unsupported-target", "Native DOM style() does not support the CSS initial keyword, matching the pinned upstream limitation", item.value.span);
|
|
1473
|
+
}
|
|
1265
1474
|
let value;
|
|
1266
|
-
if (needsRuntime)
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1475
|
+
if (needsRuntime) {
|
|
1476
|
+
value = JSON.stringify(item.value.value);
|
|
1477
|
+
} else {
|
|
1478
|
+
const itemSplit = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig));
|
|
1479
|
+
const itemStyle = itemSplit?.viewProps?.style;
|
|
1480
|
+
if (!isSerializableNativeStyle(itemStyle) || core.containsThemeRef(itemStyle)) {
|
|
1481
|
+
return bailout(input, "local/unsupported-target", "Native style() output is not serializable", item.value.span);
|
|
1482
|
+
}
|
|
1270
1483
|
value = JSON.stringify(itemStyle ?? {});
|
|
1271
1484
|
}
|
|
1272
1485
|
const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
|
|
1273
1486
|
itemSources.push(condition ? `(${condition}) && ${value}` : value);
|
|
1274
1487
|
}
|
|
1275
1488
|
if (needsRuntime) {
|
|
1276
|
-
primitive = `DOMRuntime${basePrimitive.slice(
|
|
1489
|
+
primitive = `DOMRuntime${basePrimitive.slice("DOM".length)}`;
|
|
1277
1490
|
runtimeStyleSource = `[${itemSources.join(", ")}]`;
|
|
1278
|
-
} else
|
|
1491
|
+
} else {
|
|
1492
|
+
nativeDOMStyleSource = `[${[nativeDOMStyleSource, ...itemSources].join(", ")}]`;
|
|
1493
|
+
}
|
|
1279
1494
|
}
|
|
1280
1495
|
const nativeLocal2 = unusedIdentifier(input.source, `__Tamagui${primitive}`);
|
|
1281
1496
|
const propertyContent = [
|
|
@@ -1303,17 +1518,22 @@ import { ${primitive} as ${nativeLocal2} } from ${JSON.stringify(NATIVE_PRIMITIV
|
|
|
1303
1518
|
let needsCreateElement = false;
|
|
1304
1519
|
for (const entry of input.element.entries) {
|
|
1305
1520
|
if (entry.kind !== "child") continue;
|
|
1306
|
-
if (entry.value.kind === "empty" || entry.value.kind === "element" || entry.value.kind === "static" && (entry.value.value === null || typeof entry.value.value === "boolean"))
|
|
1307
|
-
|
|
1521
|
+
if (entry.value.kind === "empty" || entry.value.kind === "element" || entry.value.kind === "static" && (entry.value.value === null || typeof entry.value.value === "boolean")) {
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1524
|
+
if (entry.value.kind !== "static" || entry.value.literalOrigin !== true || typeof entry.value.value !== "string" && typeof entry.value.value !== "number") {
|
|
1525
|
+
return bailout(input, "local/unsupported-child", `html.${component.domTag} has a direct child that may render unwrapped native text; write a literal as JSX text or wrap the child in html.span`, entry.span);
|
|
1526
|
+
}
|
|
1308
1527
|
needsText = true;
|
|
1309
1528
|
const child = input.source.slice(entry.span.start, entry.span.end);
|
|
1310
|
-
if (input.element.form === "jsx")
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1529
|
+
if (input.element.form === "jsx") {
|
|
1530
|
+
literalEdits.push({
|
|
1531
|
+
start: entry.span.start,
|
|
1532
|
+
end: entry.span.end,
|
|
1533
|
+
content: `<${textLocal} __inherit>${child}</${textLocal}>`,
|
|
1534
|
+
origin: entry.span
|
|
1535
|
+
});
|
|
1536
|
+
} else {
|
|
1317
1537
|
needsCreateElement = true;
|
|
1318
1538
|
literalEdits.push({
|
|
1319
1539
|
start: entry.span.start,
|
|
@@ -1323,36 +1543,44 @@ import { ${primitive} as ${nativeLocal2} } from ${JSON.stringify(NATIVE_PRIMITIV
|
|
|
1323
1543
|
});
|
|
1324
1544
|
}
|
|
1325
1545
|
}
|
|
1326
|
-
if (needsText)
|
|
1327
|
-
|
|
1546
|
+
if (needsText) {
|
|
1547
|
+
imports.push({
|
|
1548
|
+
content: `
|
|
1328
1549
|
import { DOMText as ${textLocal} } from ${JSON.stringify(NATIVE_PRIMITIVE_MODULE)}
|
|
1329
1550
|
`,
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1551
|
+
origin: input.element.component.span
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
if (needsCreateElement) {
|
|
1555
|
+
imports.push({
|
|
1556
|
+
content: `
|
|
1334
1557
|
import { createElement as ${createElementLocal} } from "react"
|
|
1335
1558
|
`,
|
|
1336
|
-
|
|
1337
|
-
|
|
1559
|
+
origin: input.element.component.span
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1338
1562
|
}
|
|
1563
|
+
const [first3, ...rest3] = styleEntries;
|
|
1564
|
+
const firstNonStyle3 = first3 ? spreadReplacement("jsx", first3) : "";
|
|
1339
1565
|
const propsEdits = input.element.form === "jsx" ? styleEntries.length === 0 ? [{
|
|
1340
1566
|
start: input.element.component.span.end,
|
|
1341
1567
|
end: input.element.component.span.end,
|
|
1342
1568
|
content: ` ${propertyContent}`,
|
|
1343
1569
|
origin: input.element.component.span
|
|
1344
1570
|
}] : [{
|
|
1345
|
-
start:
|
|
1346
|
-
end:
|
|
1347
|
-
content: propertyContent,
|
|
1348
|
-
origin:
|
|
1349
|
-
}, ...
|
|
1571
|
+
start: first3.span.start,
|
|
1572
|
+
end: first3.span.end,
|
|
1573
|
+
content: [propertyContent, firstNonStyle3].filter(Boolean).join(" "),
|
|
1574
|
+
origin: first3.span
|
|
1575
|
+
}, ...rest3.map((entry) => ({
|
|
1350
1576
|
start: entry.span.start,
|
|
1351
1577
|
end: entry.span.end,
|
|
1352
|
-
content: "",
|
|
1578
|
+
content: spreadReplacement("jsx", entry),
|
|
1353
1579
|
origin: entry.span
|
|
1354
|
-
}))] : compiledPropsEdits(input, styleEntries, propertyContent);
|
|
1355
|
-
if (!propsEdits)
|
|
1580
|
+
}))] : compiledPropsEdits(input, styleEntries, propertyContent, (entry) => spreadReplacement(input.element.form, entry));
|
|
1581
|
+
if (!propsEdits) {
|
|
1582
|
+
return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
|
|
1583
|
+
}
|
|
1356
1584
|
return {
|
|
1357
1585
|
ok: true,
|
|
1358
1586
|
edits: [
|
|
@@ -1370,7 +1598,9 @@ import { createElement as ${createElementLocal} } from "react"
|
|
|
1370
1598
|
const useHostView = options.experimentalNativeFastPath && nativeName === "View" && isBareHostView(input.element);
|
|
1371
1599
|
const nativeExport = useHostView ? "unstable_NativeView" : nativeName;
|
|
1372
1600
|
const nativeLocal = unusedIdentifier(input.source, `__TamaguiNative${useHostView ? "HostView" : nativeName}`);
|
|
1373
|
-
if (themedStyleKeys && options.disablePartialExtraction)
|
|
1601
|
+
if (themedStyleKeys && options.disablePartialExtraction) {
|
|
1602
|
+
return bailout(input, "local/dynamic-style-value", "Theme values require partial extraction, which is disabled");
|
|
1603
|
+
}
|
|
1374
1604
|
if (dynamicStyleEntries.length > 0 || themedStyleKeys) {
|
|
1375
1605
|
if (nativeFastPath) {
|
|
1376
1606
|
const fastLocal = `__TamaguiNativeFast${nativeName}${input.element.span.start}`;
|
|
@@ -1392,7 +1622,9 @@ import { createElement as ${createElementLocal} } from "react"
|
|
|
1392
1622
|
content: "",
|
|
1393
1623
|
origin: entry.span
|
|
1394
1624
|
}))] : compiledPropsEdits(input, styleEntries, `_expressions: []`);
|
|
1395
|
-
if (!styleEdits)
|
|
1625
|
+
if (!styleEdits) {
|
|
1626
|
+
return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
|
|
1627
|
+
}
|
|
1396
1628
|
return {
|
|
1397
1629
|
ok: true,
|
|
1398
1630
|
edits: [...tagEdits4, ...styleEdits],
|
|
@@ -1420,34 +1652,63 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
|
|
|
1420
1652
|
const conditionalParts = [];
|
|
1421
1653
|
const conditionalKeys = /* @__PURE__ */ new Set();
|
|
1422
1654
|
const baseStyleForDiff = staticObject(nativeStyleResolved) ? nativeStyleResolved : {};
|
|
1423
|
-
for (const entry of dynamicStyleEntries)
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1655
|
+
for (const entry of dynamicStyleEntries) {
|
|
1656
|
+
if (entry.value.kind === "conditional" && directStyleName(entry.name, component) !== "opacity") {
|
|
1657
|
+
let serializeNativeTree = function(node) {
|
|
1658
|
+
if (node.kind === "leaf") {
|
|
1659
|
+
const diff = leafDiffs.get(node) ?? {};
|
|
1660
|
+
return JSON.stringify(diff);
|
|
1661
|
+
}
|
|
1662
|
+
const index = expressions.length;
|
|
1663
|
+
expressions.push(input.source.slice(node.test.start, node.test.end));
|
|
1664
|
+
return `expressions[${index}] ? ${serializeNativeTree(node.whenTrue)} : ${serializeNativeTree(node.whenFalse)}`;
|
|
1665
|
+
};
|
|
1666
|
+
const tree = entry.value.tree;
|
|
1667
|
+
const leaves = collectLeaves(tree);
|
|
1668
|
+
const leafDiffs = /* @__PURE__ */ new Map();
|
|
1669
|
+
for (const leaf of leaves) {
|
|
1670
|
+
const { branchCompleteProps } = propsForConditional(entry, leaf.value);
|
|
1671
|
+
const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
|
|
1672
|
+
const branchStyle = branchSplit?.viewProps?.style ?? {};
|
|
1673
|
+
if (!staticObject(branchStyle)) {
|
|
1674
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch did not resolve to a static native style`, entry.value.span);
|
|
1675
|
+
}
|
|
1676
|
+
for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit?.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
|
|
1677
|
+
if (viewPropsKey === "style") continue;
|
|
1678
|
+
if (JSON.stringify(branchSplit?.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
|
|
1679
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which the compiled style array cannot express`, entry.value.span);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
for (const key of Object.keys(baseStyleForDiff)) {
|
|
1683
|
+
if (!(key in branchStyle)) {
|
|
1684
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch removes ${key}, which an additive style array cannot express`, entry.value.span);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const diff = {};
|
|
1688
|
+
for (const [key, value] of Object.entries(branchStyle)) {
|
|
1689
|
+
if (JSON.stringify(baseStyleForDiff[key]) !== JSON.stringify(value)) {
|
|
1690
|
+
diff[key] = value;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
if (!isSerializableNativeStyle(diff) || core.containsThemeRef(diff)) {
|
|
1694
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch style is not statically representable`, entry.value.span);
|
|
1695
|
+
}
|
|
1696
|
+
for (const key of Object.keys(diff)) {
|
|
1697
|
+
if (conditionalKeys.has(key)) {
|
|
1698
|
+
return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
leafDiffs.set(leaf, diff);
|
|
1702
|
+
}
|
|
1703
|
+
for (const diff of leafDiffs.values()) {
|
|
1704
|
+
for (const key of Object.keys(diff)) conditionalKeys.add(key);
|
|
1435
1705
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
branchDiffs.push(diff);
|
|
1706
|
+
conditionalParts.push(serializeNativeTree(tree));
|
|
1707
|
+
} else {
|
|
1708
|
+
const index = expressions.length;
|
|
1709
|
+
expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
|
|
1710
|
+
plainDynamicParts.push(`${JSON.stringify(directStyleName(entry.name, component))}: expressions[${index}]`);
|
|
1442
1711
|
}
|
|
1443
|
-
for (const diff of branchDiffs) for (const key of Object.keys(diff)) conditionalKeys.add(key);
|
|
1444
|
-
const index = expressions.length;
|
|
1445
|
-
expressions.push(input.source.slice(entry.value.test.start, entry.value.test.end));
|
|
1446
|
-
conditionalParts.push(`expressions[${index}] ? ${JSON.stringify(branchDiffs[0])} : ${JSON.stringify(branchDiffs[1])}`);
|
|
1447
|
-
} else {
|
|
1448
|
-
const index = expressions.length;
|
|
1449
|
-
expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
|
|
1450
|
-
plainDynamicParts.push(`${JSON.stringify(directStyleName(entry.name, component))}: expressions[${index}]`);
|
|
1451
1712
|
}
|
|
1452
1713
|
const dynamicStyle = plainDynamicParts.join(", ");
|
|
1453
1714
|
const themedStyle = themedStyleKeys ? Object.entries(themedStyleKeys).map(([styleKey, themeKey]) => `${JSON.stringify(styleKey)}: _theme[${JSON.stringify(themeKey)}]?.get()`).join(", ") : null;
|
|
@@ -1464,18 +1725,21 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
|
|
|
1464
1725
|
origin: span
|
|
1465
1726
|
}));
|
|
1466
1727
|
const [first3, ...rest3] = styleEntries;
|
|
1728
|
+
const firstNonStyle3 = first3 ? spreadReplacement("jsx", first3) : "";
|
|
1467
1729
|
const expressionEdits = styleEntries.length === 0 ? [] : input.element.form === "jsx" ? [{
|
|
1468
1730
|
start: first3.span.start,
|
|
1469
1731
|
end: first3.span.end,
|
|
1470
|
-
content: expressions.length > 0 ? `_expressions={[${expressions.join(", ")}]}` : "",
|
|
1732
|
+
content: [expressions.length > 0 ? `_expressions={[${expressions.join(", ")}]}` : "", firstNonStyle3].filter(Boolean).join(" "),
|
|
1471
1733
|
origin: first3.span
|
|
1472
1734
|
}, ...rest3.map((entry) => ({
|
|
1473
1735
|
start: entry.span.start,
|
|
1474
1736
|
end: entry.span.end,
|
|
1475
|
-
content: "",
|
|
1737
|
+
content: spreadReplacement("jsx", entry),
|
|
1476
1738
|
origin: entry.span
|
|
1477
|
-
}))] : compiledPropsEdits(input, styleEntries, `_expressions: [${expressions.join(", ")}]
|
|
1478
|
-
if (!expressionEdits)
|
|
1739
|
+
}))] : compiledPropsEdits(input, styleEntries, `_expressions: [${expressions.join(", ")}]`, (entry) => spreadReplacement(input.element.form, entry));
|
|
1740
|
+
if (!expressionEdits) {
|
|
1741
|
+
return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
|
|
1742
|
+
}
|
|
1479
1743
|
return {
|
|
1480
1744
|
ok: true,
|
|
1481
1745
|
edits: [...tagEdits3, ...expressionEdits],
|
|
@@ -1504,8 +1768,10 @@ const ${stableLocal} = require('@tamagui/core')._withStableStyle(${nativeLocal},
|
|
|
1504
1768
|
origin: span
|
|
1505
1769
|
}));
|
|
1506
1770
|
if (input.element.form !== "jsx") {
|
|
1507
|
-
const propsEdits = compiledPropsEdits(input, styleEntries, styleContent);
|
|
1508
|
-
if (!propsEdits)
|
|
1771
|
+
const propsEdits = compiledPropsEdits(input, styleEntries, styleContent, (entry) => spreadReplacement(input.element.form, entry));
|
|
1772
|
+
if (!propsEdits) {
|
|
1773
|
+
return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
|
|
1774
|
+
}
|
|
1509
1775
|
return {
|
|
1510
1776
|
ok: true,
|
|
1511
1777
|
edits: [...tagEdits2, ...propsEdits],
|
|
@@ -1518,23 +1784,26 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1518
1784
|
flattened: true
|
|
1519
1785
|
};
|
|
1520
1786
|
}
|
|
1521
|
-
if (styleEntries.length === 0)
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1787
|
+
if (styleEntries.length === 0) {
|
|
1788
|
+
return {
|
|
1789
|
+
ok: true,
|
|
1790
|
+
edits: [...tagEdits2, {
|
|
1791
|
+
start: input.element.component.span.end,
|
|
1792
|
+
end: input.element.component.span.end,
|
|
1793
|
+
content: ` style={${nativeStyleSource}}`,
|
|
1794
|
+
origin: input.element.component.span
|
|
1795
|
+
}],
|
|
1796
|
+
css: [],
|
|
1797
|
+
imports: [...nativeStyleImports, {
|
|
1798
|
+
content: `
|
|
1532
1799
|
const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1800
|
+
origin: input.element.component.span
|
|
1801
|
+
}],
|
|
1802
|
+
flattened: true
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1537
1805
|
const [first2, ...rest2] = styleEntries;
|
|
1806
|
+
const firstNonStyle2 = first2 ? spreadReplacement("jsx", first2) : "";
|
|
1538
1807
|
return {
|
|
1539
1808
|
ok: true,
|
|
1540
1809
|
edits: [
|
|
@@ -1543,13 +1812,13 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1543
1812
|
{
|
|
1544
1813
|
start: first2.span.start,
|
|
1545
1814
|
end: first2.span.end,
|
|
1546
|
-
content: `style={${nativeStyleSource}}`,
|
|
1815
|
+
content: [`style={${nativeStyleSource}}`, firstNonStyle2].filter(Boolean).join(" "),
|
|
1547
1816
|
origin: first2.span
|
|
1548
1817
|
},
|
|
1549
1818
|
...rest2.map((entry) => ({
|
|
1550
1819
|
start: entry.span.start,
|
|
1551
1820
|
end: entry.span.end,
|
|
1552
|
-
content: "",
|
|
1821
|
+
content: spreadReplacement("jsx", entry),
|
|
1553
1822
|
origin: entry.span
|
|
1554
1823
|
}))
|
|
1555
1824
|
],
|
|
@@ -1565,60 +1834,112 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1565
1834
|
const artifacts = extractedStyleArtifacts(split, props, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
|
|
1566
1835
|
const className = artifacts.className;
|
|
1567
1836
|
const rawInlineStyle = split.viewProps?.style;
|
|
1568
|
-
const inlineStyle = staticObject(rawInlineStyle) &&
|
|
1569
|
-
if (rawInlineStyle && !inlineStyle && !isSerializableNativeStyle(rawInlineStyle))
|
|
1837
|
+
const inlineStyle = staticObject(rawInlineStyle) && Object.keys(rawInlineStyle).length > 0 ? rawInlineStyle : null;
|
|
1838
|
+
if (rawInlineStyle && !inlineStyle && !isSerializableNativeStyle(rawInlineStyle)) {
|
|
1839
|
+
return bailout(input, "local/unsupported-target", "Web inline style output is not a static serializable value");
|
|
1840
|
+
}
|
|
1570
1841
|
const programCSS = [];
|
|
1571
1842
|
const programClassSources = [];
|
|
1572
|
-
if (domStyleProgram?.kind === "prop" && domStyleProgram.value.kind === "dom-style")
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
const
|
|
1582
|
-
|
|
1843
|
+
if (domStyleProgram?.kind === "prop" && domStyleProgram.value.kind === "dom-style") {
|
|
1844
|
+
for (const item of domStyleProgram.value.items) {
|
|
1845
|
+
if (item.value.kind !== "static" || !staticObject(item.value.value)) {
|
|
1846
|
+
return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
|
|
1847
|
+
}
|
|
1848
|
+
const itemSplit = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig));
|
|
1849
|
+
if (!itemSplit) {
|
|
1850
|
+
return bailout(input, "local/style-resolution-failed", "A style() handle could not be resolved", item.value.span);
|
|
1851
|
+
}
|
|
1852
|
+
const itemInline = itemSplit.viewProps?.style;
|
|
1853
|
+
if (staticObject(itemInline) && Object.keys(itemInline).length > 0) {
|
|
1854
|
+
return bailout(input, "local/unsupported-target", "Conditional web style() handles must lower to CSS classes", item.value.span);
|
|
1855
|
+
}
|
|
1856
|
+
const itemArtifacts = extractedStyleArtifacts(itemSplit, item.value.value, options.tamaguiConfig, false);
|
|
1857
|
+
programCSS.push(...itemArtifacts.css);
|
|
1858
|
+
if (itemArtifacts.className) {
|
|
1859
|
+
const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
|
|
1860
|
+
programClassSources.push(condition ? `(${condition}) && ${JSON.stringify(itemArtifacts.className)}` : JSON.stringify(itemArtifacts.className));
|
|
1861
|
+
}
|
|
1583
1862
|
}
|
|
1584
1863
|
}
|
|
1585
|
-
|
|
1864
|
+
const baseStaticClasses = new Set(className.split(" ").filter(Boolean));
|
|
1865
|
+
const staticClasses = new Set(baseStaticClasses);
|
|
1586
1866
|
const webConditionalCSS = [];
|
|
1867
|
+
const webConditionalKeys = /* @__PURE__ */ new Set();
|
|
1587
1868
|
const webConditionalEntries = supportsWebConditionalClasses ? dynamicStyleEntries.filter((entry) => entry.value.kind === "conditional") : [];
|
|
1588
1869
|
for (const entry of webConditionalEntries) {
|
|
1870
|
+
let serializeWebTree = function(node) {
|
|
1871
|
+
if (node.kind === "leaf") {
|
|
1872
|
+
const artifacts2 = leafArtifactsMap.get(node);
|
|
1873
|
+
const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
|
|
1874
|
+
return JSON.stringify(only.join(" "));
|
|
1875
|
+
}
|
|
1876
|
+
const test = input.source.slice(node.test.start, node.test.end);
|
|
1877
|
+
const truePart = serializeWebTree(node.whenTrue);
|
|
1878
|
+
const falsePart = serializeWebTree(node.whenFalse);
|
|
1879
|
+
return `(${test}) ? ${truePart} : ${falsePart}`;
|
|
1880
|
+
};
|
|
1589
1881
|
if (entry.value.kind !== "conditional") continue;
|
|
1590
|
-
const
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1882
|
+
const tree = entry.value.tree;
|
|
1883
|
+
const leaves = collectLeaves(tree);
|
|
1884
|
+
const leafArtifactsMap = /* @__PURE__ */ new Map();
|
|
1885
|
+
const entryConditionalKeys = /* @__PURE__ */ new Set();
|
|
1886
|
+
for (const leaf of leaves) {
|
|
1887
|
+
const { branchProps, branchCompleteProps } = propsForConditional(entry, leaf.value);
|
|
1888
|
+
const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
|
|
1889
|
+
if (!branchSplit) {
|
|
1890
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch could not be resolved`, entry.value.span);
|
|
1891
|
+
}
|
|
1597
1892
|
for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
|
|
1598
1893
|
if (viewPropsKey === "className") continue;
|
|
1599
|
-
if (JSON.stringify(branchSplit.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey]))
|
|
1894
|
+
if (JSON.stringify(branchSplit.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
|
|
1895
|
+
return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which conditional classes cannot express`, entry.value.span);
|
|
1896
|
+
}
|
|
1600
1897
|
}
|
|
1601
|
-
const
|
|
1602
|
-
|
|
1603
|
-
[
|
|
1604
|
-
|
|
1605
|
-
|
|
1898
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
1899
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(branchSplit.classNames ?? {}), ...Object.keys(split.classNames ?? {})])) {
|
|
1900
|
+
if (JSON.stringify(branchSplit.classNames?.[key]) !== JSON.stringify(split.classNames?.[key])) {
|
|
1901
|
+
changedKeys.add(key);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
const branchStyle = branchSplit.viewProps?.style;
|
|
1905
|
+
const baseStyle = split.viewProps?.style;
|
|
1906
|
+
if (staticObject(branchStyle) || staticObject(baseStyle)) {
|
|
1907
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(staticObject(branchStyle) ? branchStyle : {}), ...Object.keys(staticObject(baseStyle) ? baseStyle : {})])) {
|
|
1908
|
+
if (JSON.stringify(staticObject(branchStyle) ? branchStyle[key] : void 0) !== JSON.stringify(staticObject(baseStyle) ? baseStyle[key] : void 0)) {
|
|
1909
|
+
changedKeys.add(key);
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
for (const key of changedKeys) {
|
|
1914
|
+
if (webConditionalKeys.has(key)) {
|
|
1915
|
+
return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
|
|
1916
|
+
}
|
|
1917
|
+
entryConditionalKeys.add(key);
|
|
1918
|
+
}
|
|
1919
|
+
const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
|
|
1920
|
+
leafArtifactsMap.set(leaf, {
|
|
1606
1921
|
classes: branchArtifacts.className.split(" ").filter(Boolean),
|
|
1607
1922
|
css: branchArtifacts.css
|
|
1608
1923
|
});
|
|
1609
1924
|
}
|
|
1610
|
-
const
|
|
1611
|
-
const
|
|
1612
|
-
|
|
1613
|
-
const falseOnly = whenFalse.classes.filter((item) => !shared.has(item));
|
|
1614
|
-
webClassName = [...shared].join(" ");
|
|
1615
|
-
webConditionalCSS.push(...whenTrue.css, ...whenFalse.css);
|
|
1616
|
-
if (trueOnly.length > 0 || falseOnly.length > 0) {
|
|
1617
|
-
const test = input.source.slice(entry.value.test.start, entry.value.test.end);
|
|
1618
|
-
programClassSources.push(`(${test}) ? ${JSON.stringify(trueOnly.join(" "))} : ${JSON.stringify(falseOnly.join(" "))}`);
|
|
1925
|
+
for (const key of entryConditionalKeys) webConditionalKeys.add(key);
|
|
1926
|
+
for (const artifacts2 of leafArtifactsMap.values()) {
|
|
1927
|
+
webConditionalCSS.push(...artifacts2.css);
|
|
1619
1928
|
}
|
|
1929
|
+
const allLeafArtifacts = leaves.map((l) => leafArtifactsMap.get(l));
|
|
1930
|
+
const sharedInConditional = new Set(allLeafArtifacts[0]?.classes.filter((c) => allLeafArtifacts.every((a) => a.classes.includes(c))) ?? []);
|
|
1931
|
+
for (const cls of baseStaticClasses) {
|
|
1932
|
+
if (!sharedInConditional.has(cls)) staticClasses.delete(cls);
|
|
1933
|
+
}
|
|
1934
|
+
for (const cls of sharedInConditional) {
|
|
1935
|
+
if (!baseStaticClasses.has(cls)) staticClasses.add(cls);
|
|
1936
|
+
}
|
|
1937
|
+
const classExpr = serializeWebTree(tree);
|
|
1938
|
+
programClassSources.push(classExpr);
|
|
1620
1939
|
}
|
|
1621
|
-
const
|
|
1940
|
+
const webClassName = [...staticClasses].join(" ");
|
|
1941
|
+
const hasStyleProgram = programClassSources.length > 0;
|
|
1942
|
+
const classNameExpression = hasStyleProgram ? `[${[JSON.stringify(webClassName), ...programClassSources].join(", ")}].filter(Boolean).join(" ")` : null;
|
|
1622
1943
|
const serializedInlineStyle = serializedStyle(inlineStyle, dynamicHostStyleProperties ?? []);
|
|
1623
1944
|
const jsxWebStyle = classNameExpression ? [`className={${classNameExpression}}`, serializedInlineStyle ? `style={${serializedInlineStyle}}` : ""].filter(Boolean).join(" ") : jsxStyleAttributes(webClassName, inlineStyle, dynamicHostStyleProperties ?? []);
|
|
1624
1945
|
const objectWebStyle = classNameExpression ? [`className: ${classNameExpression}`, serializedInlineStyle ? `style: ${serializedInlineStyle}` : ""].filter(Boolean).join(", ") : objectStyleProperties(webClassName, inlineStyle, dynamicHostStyleProperties ?? []);
|
|
@@ -1630,8 +1951,10 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1630
1951
|
const webExtraProps = serializedProps(input.element.form, webDOMResult.additions);
|
|
1631
1952
|
if (input.element.form !== "jsx") {
|
|
1632
1953
|
const replacement = [objectWebStyle, webExtraProps].filter(Boolean).join(", ");
|
|
1633
|
-
const propsEdits = compiledPropsEdits(input, styleEntries, replacement);
|
|
1634
|
-
if (!propsEdits)
|
|
1954
|
+
const propsEdits = compiledPropsEdits(input, styleEntries, replacement, (entry) => spreadReplacement(input.element.form, entry));
|
|
1955
|
+
if (!propsEdits) {
|
|
1956
|
+
return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
|
|
1957
|
+
}
|
|
1635
1958
|
return {
|
|
1636
1959
|
ok: true,
|
|
1637
1960
|
edits: [
|
|
@@ -1664,7 +1987,12 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1664
1987
|
};
|
|
1665
1988
|
}
|
|
1666
1989
|
const [first, ...rest] = styleEntries;
|
|
1667
|
-
const
|
|
1990
|
+
const firstNonStyle = first ? spreadReplacement("jsx", first) : "";
|
|
1991
|
+
const attributes = [
|
|
1992
|
+
jsxWebStyle,
|
|
1993
|
+
webExtraProps,
|
|
1994
|
+
firstNonStyle
|
|
1995
|
+
].filter(Boolean).join(" ");
|
|
1668
1996
|
return {
|
|
1669
1997
|
ok: true,
|
|
1670
1998
|
edits: [
|
|
@@ -1679,7 +2007,7 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
|
|
|
1679
2007
|
...rest.map((entry) => ({
|
|
1680
2008
|
start: entry.span.start,
|
|
1681
2009
|
end: entry.span.end,
|
|
1682
|
-
content: "",
|
|
2010
|
+
content: spreadReplacement("jsx", entry),
|
|
1683
2011
|
origin: entry.span
|
|
1684
2012
|
}))
|
|
1685
2013
|
],
|