@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.
@@ -102,7 +102,9 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
102
102
  media: []
103
103
  };
104
104
  const classKeys = /* @__PURE__ */ new Map();
105
- for (const [key, identifier] of Object.entries(split.classNames ?? {})) if (typeof identifier === "string") classKeys.set(identifier, key);
105
+ for (const [key, identifier] of Object.entries(split.classNames ?? {})) {
106
+ if (typeof identifier === "string") classKeys.set(identifier, key);
107
+ }
106
108
  const identifiers = /* @__PURE__ */ new Set([...classKeys.keys(), ...Object.values(rules).flatMap((styleObject) => {
107
109
  const identifier = styleObject?.[import_helpers.StyleObjectIdentifier];
108
110
  return typeof identifier === "string" ? [identifier] : [];
@@ -110,11 +112,17 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
110
112
  for (const identifier of identifiers) {
111
113
  const key = classKeys.get(identifier) ?? "";
112
114
  const css2 = cssFromRules(Object.fromEntries(Object.entries(rules).filter(([, styleObject]) => styleObject?.[import_helpers.StyleObjectIdentifier] === identifier))).join("");
113
- if (identifier.startsWith("t_group_")) buckets.group.push(identifier);
114
- else if (pseudoNames.some((name) => key.endsWith(`-${name}`))) buckets.pseudo.push(identifier);
115
- else if (css2.includes(".t_")) buckets.theme.push(identifier);
116
- else if ([...mediaNames].some((name) => key.endsWith(`-${name}`))) buckets.media.push(identifier);
117
- else buckets.normal.push(identifier);
115
+ if (identifier.startsWith("t_group_")) {
116
+ buckets.group.push(identifier);
117
+ } else if (pseudoNames.some((name) => key.endsWith(`-${name}`))) {
118
+ buckets.pseudo.push(identifier);
119
+ } else if (css2.includes(".t_")) {
120
+ buckets.theme.push(identifier);
121
+ } else if ([...mediaNames].some((name) => key.endsWith(`-${name}`))) {
122
+ buckets.media.push(identifier);
123
+ } else {
124
+ buckets.normal.push(identifier);
125
+ }
118
126
  }
119
127
  const orderedIdentifiers = [
120
128
  ...buckets.group,
@@ -134,17 +142,28 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
134
142
  css
135
143
  };
136
144
  }
137
- function compiledPropsEdits(input, styleEntries, replacement) {
145
+ function spreadNonStyleReplacement(form, entry, isPropIgnored, rewriteProp) {
146
+ if (entry.kind !== "spread" || entry.value.kind !== "static" || !staticObject(entry.value.value)) {
147
+ return "";
148
+ }
149
+ const nonStyleEntries = Object.entries(entry.value.value).filter(([key]) => !isPropIgnored(key)).map(([key, value]) => rewriteProp(key, value));
150
+ if (nonStyleEntries.length === 0) return "";
151
+ const objectSource = `{ ${nonStyleEntries.map(([key, value]) => `${JSON.stringify(key)}: ${JSON.stringify(value)}`).join(", ")} }`;
152
+ return form === "jsx" ? `{...${objectSource}}` : `...${objectSource}`;
153
+ }
154
+ function compiledPropsEdits(input, styleEntries, replacement, spreadReplacement) {
138
155
  const propsSpan = input.element.propsSpan;
139
156
  if (!propsSpan) return null;
140
157
  const original = input.source.slice(propsSpan.start, propsSpan.end);
141
158
  const trimmed = original.trim();
142
- if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return [{
143
- start: propsSpan.start,
144
- end: propsSpan.end,
145
- content: `{ ${replacement} }`,
146
- origin: propsSpan
147
- }];
159
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
160
+ return [{
161
+ start: propsSpan.start,
162
+ end: propsSpan.end,
163
+ content: `{ ${replacement} }`,
164
+ origin: propsSpan
165
+ }];
166
+ }
148
167
  if (styleEntries.length === 0) {
149
168
  const close = original.lastIndexOf("}");
150
169
  const separator = original.slice(1, close).trim() ? ", " : " ";
@@ -160,19 +179,22 @@ function compiledPropsEdits(input, styleEntries, replacement) {
160
179
  for (const [index, entry] of styleEntries.entries()) {
161
180
  let start = entry.span.start;
162
181
  let end = entry.span.end;
182
+ const nonStyle = spreadReplacement?.(entry) ?? "";
163
183
  if (index === 0) {
184
+ const content = [replacement, nonStyle].filter(Boolean).join(", ");
164
185
  edits.push({
165
186
  start,
166
187
  end,
167
- content: replacement,
188
+ content,
168
189
  origin: entry.span
169
190
  });
170
191
  continue;
171
192
  }
172
193
  let cursor = end - propsSpan.start;
173
194
  while (cursor < original.length - 1 && /\s/.test(original[cursor])) cursor++;
174
- if (original[cursor] === ",") end = propsSpan.start + cursor + 1;
175
- else {
195
+ if (original[cursor] === ",") {
196
+ end = propsSpan.start + cursor + 1;
197
+ } else {
176
198
  cursor = start - propsSpan.start - 1;
177
199
  while (cursor > 0 && /\s/.test(original[cursor])) cursor--;
178
200
  if (original[cursor] === ",") start = propsSpan.start + cursor;
@@ -180,15 +202,18 @@ function compiledPropsEdits(input, styleEntries, replacement) {
180
202
  edits.push({
181
203
  start,
182
204
  end,
183
- content: "",
205
+ content: nonStyle,
184
206
  origin: entry.span
185
207
  });
186
208
  }
187
209
  const merged = [];
188
210
  for (const edit of edits.sort((left, right) => left.start - right.start)) {
189
211
  const previous = merged.at(-1);
190
- if (previous && edit.start <= previous.end && !previous.content && !edit.content) previous.end = Math.max(previous.end, edit.end);
191
- else merged.push(edit);
212
+ if (previous && edit.start <= previous.end && !previous.content && !edit.content) {
213
+ previous.end = Math.max(previous.end, edit.end);
214
+ } else {
215
+ merged.push(edit);
216
+ }
192
217
  }
193
218
  return merged;
194
219
  }
@@ -443,7 +468,13 @@ const cssConflictFamilies = [
443
468
  ])
444
469
  ];
445
470
  function cssOwnersConflict(left, right) {
446
- for (const leftOwner of left) for (const rightOwner of right) if (leftOwner === rightOwner || cssShorthandConflicts[leftOwner]?.includes(rightOwner) || cssShorthandConflicts[rightOwner]?.includes(leftOwner) || cssConflictFamilies.some((family) => family.has(leftOwner) && family.has(rightOwner))) return true;
471
+ for (const leftOwner of left) {
472
+ for (const rightOwner of right) {
473
+ if (leftOwner === rightOwner || cssShorthandConflicts[leftOwner]?.includes(rightOwner) || cssShorthandConflicts[rightOwner]?.includes(leftOwner) || cssConflictFamilies.some((family) => family.has(leftOwner) && family.has(rightOwner))) {
474
+ return true;
475
+ }
476
+ }
477
+ }
447
478
  return false;
448
479
  }
449
480
  const runtimeEventProps = /* @__PURE__ */ new Set([
@@ -464,7 +495,9 @@ const nativePointerEventProps = /* @__PURE__ */ new Set([
464
495
  "onPointerUp"
465
496
  ]);
466
497
  function isSerializableNativeStyle(value) {
467
- if (value == null || typeof value === "number" || typeof value === "boolean") return true;
498
+ if (value == null || typeof value === "number" || typeof value === "boolean") {
499
+ return true;
500
+ }
468
501
  if (typeof value === "string") return true;
469
502
  if (Array.isArray(value)) return value.every(isSerializableNativeStyle);
470
503
  if (!staticObject(value)) return false;
@@ -475,7 +508,9 @@ function isSerializableNativeStyle(value) {
475
508
  function unusedIdentifier(source, base) {
476
509
  let candidate = base;
477
510
  let suffix = 0;
478
- while (new RegExp(`\\b${candidate}\\b`).test(source)) candidate = `${base}${++suffix}`;
511
+ while (new RegExp(`\\b${candidate}\\b`).test(source)) {
512
+ candidate = `${base}${++suffix}`;
513
+ }
479
514
  return candidate;
480
515
  }
481
516
  const VIEW_WRAPPER_PROPS = /^(aria-|accessibilityState$|accessibilityValue$|id$|tabIndex$|nativeID$)/;
@@ -509,7 +544,9 @@ function nativeDOMProps(input, tag) {
509
544
  const entries = input.element.entries.filter((entry) => entry.kind === "prop");
510
545
  const names = new Set(entries.map((entry) => entry.name));
511
546
  if (names.has("ref") || tag === "br") additions.push(["__tag", JSON.stringify(tag)]);
512
- if (import_dom.TAGS[tag].backing === "text" || import_dom.TAGS[tag].backing === "textinput") additions.push(["__inherit", "true"]);
547
+ if (import_dom.TAGS[tag].backing === "text" || import_dom.TAGS[tag].backing === "textinput") {
548
+ additions.push(["__inherit", "true"]);
549
+ }
513
550
  const add = (name, value) => additions.push([name, value]);
514
551
  const consume = (entry) => consumed.push(entry);
515
552
  for (const entry of entries) {
@@ -517,20 +554,24 @@ function nativeDOMProps(input, tag) {
517
554
  const attribute = (Object.hasOwn(import_dom.ATTRIBUTES, entry.name) ? import_dom.ATTRIBUTES[entry.name] : void 0) ?? (entry.name.startsWith("data-") ? import_dom.ATTRIBUTES["data-*"] : void 0);
518
555
  const event = Object.hasOwn(import_dom.EVENTS, entry.name) ? import_dom.EVENTS[entry.name] : void 0;
519
556
  if (event) {
520
- if (event.native === "none") return {
521
- consumed,
522
- edits,
523
- additions,
524
- diagnostic: `${entry.name} has no native DOM event equivalent`,
525
- diagnosticSpan: entry.span
526
- };
527
- if (entry.name === "onKeyDown" && tag !== "input" && tag !== "textarea") return {
528
- consumed,
529
- edits,
530
- additions,
531
- diagnostic: `onKeyDown requires a native text-entry control`,
532
- diagnosticSpan: entry.span
533
- };
557
+ if (event.native === "none") {
558
+ return {
559
+ consumed,
560
+ edits,
561
+ additions,
562
+ diagnostic: `${entry.name} has no native DOM event equivalent`,
563
+ diagnosticSpan: entry.span
564
+ };
565
+ }
566
+ if (entry.name === "onKeyDown" && tag !== "input" && tag !== "textarea") {
567
+ return {
568
+ consumed,
569
+ edits,
570
+ additions,
571
+ diagnostic: `onKeyDown requires a native text-entry control`,
572
+ diagnosticSpan: entry.span
573
+ };
574
+ }
534
575
  if ([
535
576
  "onClick",
536
577
  "onLoad",
@@ -538,7 +579,9 @@ function nativeDOMProps(input, tag) {
538
579
  "onChange",
539
580
  "onInput",
540
581
  "onKeyDown"
541
- ].includes(entry.name)) continue;
582
+ ].includes(entry.name)) {
583
+ continue;
584
+ }
542
585
  if (event.nativeProp) {
543
586
  const edit2 = renamedPropEdit(input, entry, event.nativeProp);
544
587
  if (edit2) edits.push(edit2);
@@ -547,24 +590,28 @@ function nativeDOMProps(input, tag) {
547
590
  }
548
591
  if (!attribute || attribute.native === "none" || entry.name === "style") continue;
549
592
  if (DOM_STYLE_ATTRIBUTES.has(entry.name)) {
550
- if (entry.value.kind !== "static") return {
551
- consumed,
552
- edits,
553
- additions,
554
- diagnostic: `html.${tag} ${entry.name} must be statically known for native lowering`,
555
- diagnosticSpan: entry.span
556
- };
593
+ if (entry.value.kind !== "static") {
594
+ return {
595
+ consumed,
596
+ edits,
597
+ additions,
598
+ diagnostic: `html.${tag} ${entry.name} must be statically known for native lowering`,
599
+ diagnosticSpan: entry.span
600
+ };
601
+ }
557
602
  consume(entry);
558
603
  continue;
559
604
  }
560
605
  if (entry.name === "hidden") {
561
- if (entry.value.kind !== "static") return {
562
- consumed,
563
- edits,
564
- additions,
565
- diagnostic: `html.${tag} hidden must be statically known for native lowering`,
566
- diagnosticSpan: entry.span
567
- };
606
+ if (entry.value.kind !== "static") {
607
+ return {
608
+ consumed,
609
+ edits,
610
+ additions,
611
+ diagnostic: `html.${tag} hidden must be statically known for native lowering`,
612
+ diagnosticSpan: entry.span
613
+ };
614
+ }
568
615
  consume(entry);
569
616
  continue;
570
617
  }
@@ -590,18 +637,22 @@ function nativeDOMProps(input, tag) {
590
637
  }
591
638
  if (entry.name === "type") {
592
639
  consume(entry);
593
- if (tag === "input" && entry.value.kind !== "static") return {
594
- consumed,
595
- edits,
596
- additions,
597
- diagnostic: `html.input type must be statically known for native lowering`,
598
- diagnosticSpan: entry.span
599
- };
640
+ if (tag === "input" && entry.value.kind !== "static") {
641
+ return {
642
+ consumed,
643
+ edits,
644
+ additions,
645
+ diagnostic: `html.input type must be statically known for native lowering`,
646
+ diagnosticSpan: entry.span
647
+ };
648
+ }
600
649
  if (tag === "input" && entry.value.kind === "static") {
601
650
  const type = entry.value.value;
602
651
  if (type === "password") add("secureTextEntry", "true");
603
652
  else if (typeof type === "string" && type !== "text" && import_dom.NATIVE_INPUT_TYPES.includes(type)) {
604
- if (!names.has("inputMode")) add("inputMode", JSON.stringify(type === "number" ? "numeric" : type));
653
+ if (!names.has("inputMode")) {
654
+ add("inputMode", JSON.stringify(type === "number" ? "numeric" : type));
655
+ }
605
656
  }
606
657
  }
607
658
  continue;
@@ -630,7 +681,9 @@ function nativeDOMProps(input, tag) {
630
681
  const edit = renamedPropEdit(input, entry, nativeProp);
631
682
  if (edit) edits.push(edit);
632
683
  }
633
- for (const [name, values] of nested) add(name, `{ ${values.map(([key, value]) => `${key}: ${value}`).join(", ")} }`);
684
+ for (const [name, values] of nested) {
685
+ add(name, `{ ${values.map(([key, value]) => `${key}: ${value}`).join(", ")} }`);
686
+ }
634
687
  if (!names.has("role") && import_dom.TAGS[tag].role) add("role", JSON.stringify(import_dom.TAGS[tag].role));
635
688
  if (tag === "textarea") add("multiline", "true");
636
689
  return {
@@ -649,15 +702,19 @@ function webDOMProps(input, tag) {
649
702
  const edit = renamedPropEdit(input, entry, "htmlFor");
650
703
  if (edit) edits.push(edit);
651
704
  }
652
- if (entry.name === "role" && entry.value.kind === "static" && entry.value.value === "none") edits.push({
653
- start: entry.value.span.start,
654
- end: entry.value.span.end,
655
- content: JSON.stringify("presentation"),
656
- origin: entry.value.span
657
- });
705
+ if (entry.name === "role" && entry.value.kind === "static" && entry.value.value === "none") {
706
+ edits.push({
707
+ start: entry.value.span.start,
708
+ end: entry.value.span.end,
709
+ content: JSON.stringify("presentation"),
710
+ origin: entry.value.span
711
+ });
712
+ }
658
713
  }
659
714
  if (tag === "button" && !names.has("type")) additions.push(["type", "\"button\""]);
660
- if ((tag === "input" || tag === "textarea") && !names.has("dir")) additions.push(["dir", "\"auto\""]);
715
+ if ((tag === "input" || tag === "textarea") && !names.has("dir")) {
716
+ additions.push(["dir", "\"auto\""]);
717
+ }
661
718
  return {
662
719
  edits,
663
720
  additions
@@ -667,7 +724,8 @@ function createTamaguiCompilerHost(options) {
667
724
  const platform = options.target === "native" ? "native" : "web";
668
725
  const core = (0, import_requireTamaguiCore.requireTamaguiCore)(platform);
669
726
  const firstThemeName = Object.keys(options.tamaguiConfig.themes ?? {})[0] ?? "";
670
- const theme = options.tamaguiConfig.themes?.[firstThemeName] ?? {};
727
+ const firstTheme = options.tamaguiConfig.themes?.[firstThemeName] ?? {};
728
+ const theme = firstTheme;
671
729
  const modifierRegistry = (0, import_tooling.createModifierRegistry)({
672
730
  mediaNames: options.tamaguiConfig.media ?? {},
673
731
  themeNames: options.tamaguiConfig.themes ?? {}
@@ -704,17 +762,25 @@ function createTamaguiCompilerHost(options) {
704
762
  resolvedPayloads.push(payload);
705
763
  continue;
706
764
  }
707
- if (transition.value.entries.length !== 1 || transition.value.entries[0].timing.type !== "preset") return null;
765
+ if (transition.value.entries.length !== 1 || transition.value.entries[0].timing.type !== "preset") {
766
+ return null;
767
+ }
708
768
  const preset = transitionPresets[transition.value.entries[0].timing.name];
709
769
  if (typeof preset !== "string") return null;
710
770
  const parsedPreset = (0, import_tooling.parseTransition)(preset);
711
- 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") return null;
771
+ 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") {
772
+ return null;
773
+ }
712
774
  resolvedPayloads.push(`all ${preset}`);
713
775
  }
714
776
  let payloadIndex = 0;
715
777
  const resolved = [];
716
- if (program.value.base !== null) resolved.push(resolvedPayloads[payloadIndex++]);
717
- for (const clause of program.value.clauses) resolved.push(`${clause.modifiers.join(":")}:${resolvedPayloads[payloadIndex++]}`);
778
+ if (program.value.base !== null) {
779
+ resolved.push(resolvedPayloads[payloadIndex++]);
780
+ }
781
+ for (const clause of program.value.clauses) {
782
+ resolved.push(`${clause.modifiers.join(":")}:${resolvedPayloads[payloadIndex++]}`);
783
+ }
718
784
  return resolved.join(" ");
719
785
  };
720
786
  const modulesById = new Map(options.componentModules.map((module2) => [module2.resolvedId, module2.moduleName]));
@@ -724,7 +790,8 @@ function createTamaguiCompilerHost(options) {
724
790
  const identity = element.component.provenance;
725
791
  if (!identity) return null;
726
792
  const moduleName = modulesById.get(identity.resolvedId);
727
- const info = (moduleName ? componentsByModule.get(moduleName) : void 0)?.nameToInfo[identity.importedName];
793
+ const component = moduleName ? componentsByModule.get(moduleName) : void 0;
794
+ const info = component?.nameToInfo[identity.importedName];
728
795
  return info ? {
729
796
  key: componentKey(identity.resolvedId, identity.importedName),
730
797
  staticConfig: normalizeStaticConfig(info.staticConfig),
@@ -734,9 +801,12 @@ function createTamaguiCompilerHost(options) {
734
801
  const domStaticConfig = (element) => {
735
802
  const identity = element.component.provenance;
736
803
  const tag = element.component.name;
737
- if (identity?.importedName !== "html" || !DOM_FRONTENDS.has(identity.specifier) || !Object.hasOwn(import_dom.TAGS, tag)) return null;
804
+ if (identity?.importedName !== "html" || !DOM_FRONTENDS.has(identity.specifier) || !Object.hasOwn(import_dom.TAGS, tag)) {
805
+ return null;
806
+ }
738
807
  const row = import_dom.TAGS[tag];
739
- const base = (row.backing === "text" || row.backing === "textinput" ? core.Text : core.View)?.staticConfig;
808
+ const textLike = row.backing === "text" || row.backing === "textinput";
809
+ const base = (textLike ? core.Text : core.View)?.staticConfig;
740
810
  if (!base) return null;
741
811
  const platformDefaults = platform === "web" ? {
742
812
  ...import_dom.DISPLAY_WEB_RESET[row.display],
@@ -840,7 +910,9 @@ function createTamaguiCompilerHost(options) {
840
910
  return name in import_helpers.stylePropsAll && !(0, import_web.isValidStyleKey)(name, validStyles, staticConfig.accept);
841
911
  };
842
912
  const directStyleName = (name, component) => {
843
- if (compilerStyleProps.has(name) || name === "style") return null;
913
+ if (compilerStyleProps.has(name) || name === "style") {
914
+ return null;
915
+ }
844
916
  const staticConfig = component.staticConfig;
845
917
  if (staticConfig.variants?.[name]) return null;
846
918
  const expanded = options.tamaguiConfig.shorthands?.[name] ?? name;
@@ -848,11 +920,15 @@ function createTamaguiCompilerHost(options) {
848
920
  };
849
921
  const resolveSplitStyles = (props, staticConfig, animationDriver, displayName) => {
850
922
  const previousStatic = process.env.IS_STATIC;
851
- const previousTarget = "web";
852
- if (platform === "native") process.env.IS_STATIC = "is_static";
853
- else delete process.env.IS_STATIC;
923
+ const previousTarget = process.env.TAMAGUI_TARGET;
924
+ if (platform === "native") {
925
+ process.env.IS_STATIC = "is_static";
926
+ } else {
927
+ delete process.env.IS_STATIC;
928
+ }
854
929
  process.env.TAMAGUI_TARGET = platform;
855
930
  try {
931
+ core.prepareStyleStaticConfig(staticConfig);
856
932
  return core.getSplitStyles(props, staticConfig, theme, firstThemeName, componentState, {
857
933
  resolveValues: platform === "native" ? "except-theme" : "variable",
858
934
  noClass: platform === "native",
@@ -862,7 +938,7 @@ function createTamaguiCompilerHost(options) {
862
938
  } finally {
863
939
  if (previousStatic === void 0) delete process.env.IS_STATIC;
864
940
  else process.env.IS_STATIC = previousStatic;
865
- if (previousTarget === void 0) delete "web";
941
+ if (previousTarget === void 0) delete process.env.TAMAGUI_TARGET;
866
942
  else process.env.TAMAGUI_TARGET = previousTarget;
867
943
  }
868
944
  };
@@ -878,7 +954,9 @@ function createTamaguiCompilerHost(options) {
878
954
  const split = resolveSplitStyles({ [name]: value }, partialStaticConfig(staticConfig));
879
955
  if (!split) return null;
880
956
  const inlineStyle = split.viewProps?.style;
881
- if (staticObject(inlineStyle) && !inlineStyle["$$css"] && Object.keys(inlineStyle).length > 0) return null;
957
+ if (staticObject(inlineStyle) && Object.keys(inlineStyle).length > 0) {
958
+ return null;
959
+ }
882
960
  const owners = new Set(Object.keys(split.classNames ?? {}));
883
961
  for (const styleObject of Object.values(split.rulesToInsert ?? {})) {
884
962
  const property = styleObject?.[import_helpers.StyleObjectProperty];
@@ -887,7 +965,7 @@ function createTamaguiCompilerHost(options) {
887
965
  return owners.size > 0 ? owners : null;
888
966
  };
889
967
  const dynamicStyleOwners = (name, staticConfig) => {
890
- const owners = styleOwners(name, name === "transform" ? [{ scale: 1 }] : name === "transformMatrix" ? [
968
+ const probeValue = name === "transform" ? [{ scale: 1 }] : name === "transformMatrix" ? [
891
969
  1,
892
970
  0,
893
971
  0,
@@ -897,7 +975,8 @@ function createTamaguiCompilerHost(options) {
897
975
  ] : name === "shadowOffset" ? {
898
976
  width: 0,
899
977
  height: 0
900
- } : name === "shadowColor" ? "black" : name === "border" || name === "outline" ? "0 solid transparent" : name === "position" ? "relative" : name === "objectFit" ? "contain" : 0, staticConfig);
978
+ } : name === "shadowColor" ? "black" : name === "border" || name === "outline" ? "0 solid transparent" : name === "position" ? "relative" : name === "objectFit" ? "contain" : 0;
979
+ const owners = styleOwners(name, probeValue, staticConfig);
901
980
  if (!owners || name !== "flex") return owners;
902
981
  const shorthandOwners = styleOwners(name, "0 1 auto", staticConfig);
903
982
  if (!shorthandOwners) return null;
@@ -918,28 +997,35 @@ function createTamaguiCompilerHost(options) {
918
997
  ] : ["bailed"];
919
998
  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;
920
999
  const styles = styleEntries.map((entry) => {
921
- if (!result.ok) return {
922
- prop: entry.name,
923
- tier: "bailed",
924
- runtime: true,
925
- why: `${result.bailout.message}. The Tamagui runtime resolved this prop.`
926
- };
1000
+ if (!result.ok) {
1001
+ return {
1002
+ prop: entry.name,
1003
+ tier: "bailed",
1004
+ runtime: true,
1005
+ why: `${result.bailout.message}. The Tamagui runtime resolved this prop.`
1006
+ };
1007
+ }
927
1008
  const edited = result.edits.some((edit) => edit.start < entry.span.end && edit.end > entry.span.start);
928
- if (!flattened && !edited) return {
929
- prop: entry.name,
930
- tier: "bailed",
931
- runtime: true,
932
- why: "This prop remained for Tamagui runtime resolution."
933
- };
934
- if (entry.value.kind === "static") {
935
- const split = resolveSplitStyles({ [entry.name]: entry.value.value }, partialStaticConfig(component.staticConfig));
936
- 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 {
1009
+ if (!flattened && !edited) {
1010
+ return {
937
1011
  prop: entry.name,
938
- tier: flattened ? "flattened" : "lowered",
939
- dropped: true,
940
- why: `No ${platform} style output was produced for this prop.`
1012
+ tier: "bailed",
1013
+ runtime: true,
1014
+ why: "This prop remained for Tamagui runtime resolution."
941
1015
  };
942
1016
  }
1017
+ if (entry.value.kind === "static") {
1018
+ const split = resolveSplitStyles({ [entry.name]: entry.value.value }, partialStaticConfig(component.staticConfig));
1019
+ 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));
1020
+ if (!hasOutput) {
1021
+ return {
1022
+ prop: entry.name,
1023
+ tier: flattened ? "flattened" : "lowered",
1024
+ dropped: true,
1025
+ why: `No ${platform} style output was produced for this prop.`
1026
+ };
1027
+ }
1028
+ }
943
1029
  return {
944
1030
  prop: entry.name,
945
1031
  tier: flattened ? "flattened" : "lowered",
@@ -964,68 +1050,94 @@ function createTamaguiCompilerHost(options) {
964
1050
  resolveComponent: resolve,
965
1051
  isStyleProp,
966
1052
  canLowerDynamicStyleProp(name, component, valueKind) {
967
- if (!options.disablePartialExtraction && valueKind === "conditional" && canLowerConditionalStyleProp(name, component)) return true;
1053
+ if (!options.disablePartialExtraction && valueKind === "conditional" && canLowerConditionalStyleProp(name, component)) {
1054
+ return true;
1055
+ }
968
1056
  return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && directStyleName(name, component) === "opacity");
969
1057
  },
970
1058
  developmentDebugInstrumentation,
971
1059
  lowerCandidate(input) {
972
1060
  const component = input.component;
973
- if (!component.canFlatten) return bailout(input, "local/unsupported-target", 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`, input.element.span, { rule: 6 });
1061
+ if (!component.canFlatten) {
1062
+ 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`;
1063
+ return bailout(input, "local/unsupported-target", reason, input.element.span, { rule: 6 });
1064
+ }
974
1065
  if (options.zeroRuntime) {
975
1066
  const spread = input.element.entries.find((entry) => entry.kind === "spread");
976
- if (spread) return bailout(input, "local/unsafe-style-spread", "Zero-runtime rejects prop spreads", spread.span, {
977
- rule: 1,
978
- message: (0, import_compiler_core.zeroRuleMessage)(1, { component: input.element.component.name })
979
- });
1067
+ if (spread) {
1068
+ return bailout(input, "local/unsafe-style-spread", "Zero-runtime rejects prop spreads", spread.span, {
1069
+ rule: 1,
1070
+ message: (0, import_compiler_core.zeroRuleMessage)(1, { component: input.element.component.name })
1071
+ });
1072
+ }
980
1073
  }
981
1074
  const props = {};
982
1075
  for (const entry of input.element.entries) {
983
1076
  if (entry.kind === "child" || entry.value.kind !== "static") continue;
984
1077
  if (entry.kind === "spread") {
985
- if (!staticObject(entry.value.value)) return bailout(input, "local/unsafe-style-spread", "Static spread did not materialize to an object", entry.span);
1078
+ if (!staticObject(entry.value.value)) {
1079
+ return bailout(input, "local/unsafe-style-spread", "Static spread did not materialize to an object", entry.span);
1080
+ }
986
1081
  Object.assign(props, entry.value.value);
987
- } else props[entry.name] = entry.value.value;
1082
+ } else {
1083
+ props[entry.name] = entry.value.value;
1084
+ }
988
1085
  }
989
1086
  const disableOptimizationEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "disableOptimization");
990
- if (disableOptimizationEntry || Object.hasOwn(props, "disableOptimization")) return bailout(input, "local/unsupported-target", "disableOptimization keeps the component on the runtime path", disableOptimizationEntry?.span);
1087
+ if (disableOptimizationEntry || Object.hasOwn(props, "disableOptimization")) {
1088
+ return bailout(input, "local/unsupported-target", "disableOptimization keeps the component on the runtime path", disableOptimizationEntry?.span);
1089
+ }
991
1090
  if (component.domTag && props.hidden) props.display = "none";
992
1091
  if (component.domTag && platform === "native") {
993
- for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES) if (name in props) {
994
- props[styleKey] = props[name];
995
- delete props[name];
1092
+ for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES) {
1093
+ if (name in props) {
1094
+ props[styleKey] = props[name];
1095
+ delete props[name];
1096
+ }
996
1097
  }
997
1098
  }
998
- if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !import_dom.NATIVE_INPUT_TYPES.includes(props.type)) return bailout(input, "local/unsupported-target", `input type ${props.type} has no native text-entry control`);
1099
+ if (platform === "native" && component.domTag === "input" && typeof props.type === "string" && !import_dom.NATIVE_INPUT_TYPES.includes(props.type)) {
1100
+ return bailout(input, "local/unsupported-target", `input type ${props.type} has no native text-entry control`);
1101
+ }
999
1102
  const dynamicStyleEntries = input.element.entries.filter((entry) => entry.kind === "prop" && (entry.value.kind === "bailout" || entry.value.kind === "conditional") && isStyleProp(entry.name, component));
1000
1103
  {
1001
1104
  const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
1002
1105
  const directRuntimeEvent = input.element.entries.find((entry) => entry.kind === "prop" && needsRuntimeMapping(entry.name));
1003
1106
  const runtimeEvent = directRuntimeEvent?.kind === "prop" ? directRuntimeEvent.name : Object.keys(props).find(needsRuntimeMapping);
1004
- if (runtimeEvent) return bailout(input, "local/unsupported-target", `${runtimeEvent} requires Tamagui runtime event mapping`);
1107
+ if (runtimeEvent) {
1108
+ return bailout(input, "local/unsupported-target", `${runtimeEvent} requires Tamagui runtime event mapping`);
1109
+ }
1005
1110
  }
1006
1111
  const animationDefaultProps = core.getDefaultProps(component.staticConfig) ?? {};
1007
1112
  const animationProps = core.mergeProps(animationDefaultProps, props);
1008
1113
  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)]);
1009
1114
  const animateOnlyEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "animateOnly");
1010
- if (animationNames.has("animateOnly")) return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", animateOnlyEntry?.span, {
1011
- rule: 5,
1012
- message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: animateOnlyEntry ? `animateOnly on ${input.element.component.name}` : `animateOnly in the styled() definition of ${input.element.component.name}` })
1013
- });
1115
+ if (animationNames.has("animateOnly")) {
1116
+ return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", animateOnlyEntry?.span, {
1117
+ rule: 5,
1118
+ message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: animateOnlyEntry ? `animateOnly on ${input.element.component.name}` : `animateOnly in the styled() definition of ${input.element.component.name}` })
1119
+ });
1120
+ }
1014
1121
  const transitionEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "transition");
1015
1122
  const animatedBy = typeof animationProps.animatedBy === "string" ? animationProps.animatedBy.trim() : null;
1016
1123
  const namedAnimationDriver = animatedBy === null ? null : options.tamaguiConfig.animationDrivers?.[animatedBy];
1017
- const cssAnimationDriver = (platform === "web" && namedAnimationDriver?.outputStyle === "css" ? namedAnimationDriver : null) ?? (animatedBy === null || animatedBy === "default" ? configuredCssAnimationDriver : null);
1124
+ const namedCssAnimationDriver = platform === "web" && namedAnimationDriver && !namedAnimationDriver.isStub && namedAnimationDriver.outputStyle === "css" ? namedAnimationDriver : null;
1125
+ const cssAnimationDriver = namedCssAnimationDriver ?? (animatedBy === null || animatedBy === "default" ? configuredCssAnimationDriver : null);
1018
1126
  const resolvedCssTransition = animationNames.has("transition") && cssAnimationDriver ? resolveStaticCssTransition(animationProps.transition, cssAnimationDriver.animations ?? {}) : null;
1019
- if (resolvedCssTransition !== null) props.transition = resolvedCssTransition;
1127
+ if (resolvedCssTransition !== null) {
1128
+ props.transition = resolvedCssTransition;
1129
+ }
1020
1130
  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")));
1021
1131
  const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy" && name !== "animateOnly") || animatedByNeedsRuntime;
1022
1132
  let dynamicHostStyleProperties = null;
1023
- if (platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicStyleEntries.length > 0 && !input.element.entries.some((entry) => entry.kind === "spread")) {
1133
+ 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")) {
1024
1134
  const seen = /* @__PURE__ */ new Set();
1025
1135
  const properties = [];
1026
1136
  const dynamicOwners = /* @__PURE__ */ new Set();
1027
1137
  for (const entry of dynamicStyleEntries) {
1028
- if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional") continue;
1138
+ if (entry.kind !== "prop" || entry.value.kind !== "bailout" && entry.value.kind !== "conditional") {
1139
+ continue;
1140
+ }
1029
1141
  const name = directStyleName(entry.name, component);
1030
1142
  if (!name || seen.has(name)) {
1031
1143
  properties.length = 0;
@@ -1038,11 +1150,13 @@ function createTamaguiCompilerHost(options) {
1038
1150
  }
1039
1151
  let property = null;
1040
1152
  const expression = input.source.slice(entry.value.span.start, entry.value.span.end);
1041
- if (resolvedCssTransition !== null && (name === "opacity" || name === "scale")) property = name === "opacity" ? `opacity: (${expression})` : `transform: "scale(" + (${expression}) + ")"`;
1042
- else if (entry.value.kind === "bailout" && owners.size === 1 && owners.has(name)) {
1153
+ if (resolvedCssTransition !== null && (name === "opacity" || name === "scale")) {
1154
+ property = name === "opacity" ? `opacity: (${expression})` : `transform: "scale(" + (${expression}) + ")"`;
1155
+ } else if (entry.value.kind === "bailout" && owners.size === 1 && owners.has(name)) {
1043
1156
  const dynamic = entry.value.dynamic;
1044
- if (dynamic?.type === "number") property = `${JSON.stringify(name)}: (${expression})`;
1045
- else if (dynamic?.type === "string" && dynamic.values?.length) {
1157
+ if (dynamic?.type === "number") {
1158
+ property = `${JSON.stringify(name)}: (${expression})`;
1159
+ } else if (dynamic?.type === "string" && dynamic.values?.length) {
1046
1160
  let valuesStayLiteral = true;
1047
1161
  for (const value of dynamic.values) {
1048
1162
  const split2 = resolveSplitStyles({ [entry.name]: value }, partialStaticConfig(component.staticConfig));
@@ -1052,7 +1166,9 @@ function createTamaguiCompilerHost(options) {
1052
1166
  break;
1053
1167
  }
1054
1168
  }
1055
- if (valuesStayLiteral) property = `${JSON.stringify(name)}: (${expression})`;
1169
+ if (valuesStayLiteral) {
1170
+ property = `${JSON.stringify(name)}: (${expression})`;
1171
+ }
1056
1172
  }
1057
1173
  }
1058
1174
  if (!property) {
@@ -1069,9 +1185,11 @@ function createTamaguiCompilerHost(options) {
1069
1185
  if (!name) return false;
1070
1186
  const owners = styleOwners(name, entry.value.value, component.staticConfig);
1071
1187
  return !!owners && cssOwnersConflict(owners, dynamicOwners);
1072
- })) dynamicHostStyleProperties = properties;
1188
+ })) {
1189
+ dynamicHostStyleProperties = properties;
1190
+ }
1073
1191
  }
1074
- const supportsWebConditionalClasses = platform === "web" && !options.disablePartialExtraction && (input.element.form === "jsx" || input.element.propsSpan !== null) && dynamicHostStyleProperties === null && dynamicStyleEntries.length === 1 && dynamicStyleEntries.every((entry) => entry.kind === "prop" && entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component));
1192
+ 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));
1075
1193
  if ("theme" in props || "themeInverse" in props) {
1076
1194
  const themeProp = "theme" in props ? "theme" : "themeInverse";
1077
1195
  return bailout(input, "local/unsupported-target", "Theme boundary candidates remain on the runtime path", input.element.span, {
@@ -1080,14 +1198,20 @@ function createTamaguiCompilerHost(options) {
1080
1198
  });
1081
1199
  }
1082
1200
  const asChildEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "asChild");
1083
- if (asChildEntry || Object.hasOwn(props, "asChild")) return bailout(input, "local/unsupported-target", "asChild renders a Slot, not a host view", asChildEntry?.span);
1084
- if (platform === "native" && ("group" in props || "container" in props || "containerName" in props || "containerType" in props)) return bailout(input, "local/unsupported-target", "Native group containers remain on the runtime path");
1085
- if (runtimeAnimationRequired && !cssAnimationDriver) return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
1086
- rule: 5,
1087
- message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
1088
- });
1201
+ if (asChildEntry || Object.hasOwn(props, "asChild")) {
1202
+ return bailout(input, "local/unsupported-target", "asChild renders a Slot, not a host view", asChildEntry?.span);
1203
+ }
1204
+ if (platform === "native" && ("group" in props || "container" in props || "containerName" in props || "containerType" in props)) {
1205
+ return bailout(input, "local/unsupported-target", "Native group and container providers remain on the runtime path");
1206
+ }
1207
+ if (runtimeAnimationRequired && !cssAnimationDriver) {
1208
+ return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
1209
+ rule: 5,
1210
+ message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
1211
+ });
1212
+ }
1089
1213
  if (platform === "web" && (dynamicStyleEntries.length > 0 || runtimeAnimationRequired) && dynamicHostStyleProperties === null && !supportsWebConditionalClasses && component.partialRuntimeSafe) {
1090
- const hasSpread = input.element.entries.some((entry) => entry.kind === "spread");
1214
+ const hasSpread = input.element.entries.some((entry) => entry.kind === "spread" && entry.value.kind !== "static");
1091
1215
  const unsupportedRuntimeStyle = input.element.entries.find((entry) => entry.kind === "prop" && isStyleProp(entry.name, component) && !runtimeAnimationProps.has(entry.name) && !directStyleName(entry.name, component));
1092
1216
  if (!hasSpread && !unsupportedRuntimeStyle) {
1093
1217
  const dynamicOwners = /* @__PURE__ */ new Set();
@@ -1116,49 +1240,59 @@ function createTamaguiCompilerHost(options) {
1116
1240
  }) : [];
1117
1241
  if (staticStyleEntries.length > 0) {
1118
1242
  const partialProps = {};
1119
- for (const entry of staticStyleEntries) if (entry.kind === "prop" && entry.value.kind === "static") partialProps[entry.name] = entry.value.value;
1243
+ for (const entry of staticStyleEntries) {
1244
+ if (entry.kind === "prop" && entry.value.kind === "static") {
1245
+ partialProps[entry.name] = entry.value.value;
1246
+ }
1247
+ }
1120
1248
  const partialSplit = resolveSplitStyles(partialProps, partialStaticConfig(component.staticConfig));
1121
1249
  const partialInlineStyle = partialSplit?.viewProps?.style;
1122
- const hasPartialInlineStyle = staticObject(partialInlineStyle) && !partialInlineStyle["$$css"] && Object.keys(partialInlineStyle).length > 0;
1250
+ const hasPartialInlineStyle = staticObject(partialInlineStyle) && Object.keys(partialInlineStyle).length > 0;
1123
1251
  if (partialSplit && !hasPartialInlineStyle) {
1124
1252
  const artifacts2 = extractedStyleArtifacts(partialSplit, partialProps, options.tamaguiConfig, false);
1125
- if (artifacts2.className) if (input.element.form !== "jsx") {
1126
- const propsEdits = compiledPropsEdits(input, staticStyleEntries, objectClassName(artifacts2.className));
1127
- if (propsEdits) return {
1128
- ok: true,
1129
- edits: propsEdits,
1130
- css: artifacts2.css,
1131
- imports: [],
1132
- flattened: false
1133
- };
1134
- } else {
1135
- const [first2, ...rest2] = staticStyleEntries;
1136
- return {
1137
- ok: true,
1138
- edits: [{
1139
- start: first2.span.start,
1140
- end: first2.span.end,
1141
- content: jsxClassName(artifacts2.className),
1142
- origin: first2.span
1143
- }, ...rest2.map((entry) => ({
1144
- start: entry.span.start,
1145
- end: entry.span.end,
1146
- content: "",
1147
- origin: entry.span
1148
- }))],
1149
- css: artifacts2.css,
1150
- imports: [],
1151
- flattened: false
1152
- };
1253
+ if (artifacts2.className) {
1254
+ if (input.element.form !== "jsx") {
1255
+ const propsEdits = compiledPropsEdits(input, staticStyleEntries, objectClassName(artifacts2.className));
1256
+ if (propsEdits) {
1257
+ return {
1258
+ ok: true,
1259
+ edits: propsEdits,
1260
+ css: artifacts2.css,
1261
+ imports: [],
1262
+ flattened: false
1263
+ };
1264
+ }
1265
+ } else {
1266
+ const [first2, ...rest2] = staticStyleEntries;
1267
+ return {
1268
+ ok: true,
1269
+ edits: [{
1270
+ start: first2.span.start,
1271
+ end: first2.span.end,
1272
+ content: jsxClassName(artifacts2.className),
1273
+ origin: first2.span
1274
+ }, ...rest2.map((entry) => ({
1275
+ start: entry.span.start,
1276
+ end: entry.span.end,
1277
+ content: "",
1278
+ origin: entry.span
1279
+ }))],
1280
+ css: artifacts2.css,
1281
+ imports: [],
1282
+ flattened: false
1283
+ };
1284
+ }
1153
1285
  }
1154
1286
  }
1155
1287
  }
1156
1288
  }
1157
1289
  }
1158
- if (runtimeAnimationRequired) return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
1159
- rule: 5,
1160
- message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
1161
- });
1290
+ if (runtimeAnimationRequired) {
1291
+ return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", transitionEntry?.span, {
1292
+ rule: 5,
1293
+ message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
1294
+ });
1295
+ }
1162
1296
  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)));
1163
1297
  if (dynamicStyleEntries.length > 0 && dynamicHostStyleProperties === null && !supportsNativeDynamicStyles && !supportsWebConditionalClasses) {
1164
1298
  const entry = dynamicStyleEntries[0];
@@ -1167,18 +1301,59 @@ function createTamaguiCompilerHost(options) {
1167
1301
  const staticDefaultProps = core.getDefaultProps(component.staticConfig) ?? {};
1168
1302
  const defaultProps = platform === "web" && !component.staticConfig.isText && options.tamaguiConfig.settings.defaultPosition === "relative" && staticDefaultProps.position === void 0 ? core.mergeProps({ position: "relative" }, staticDefaultProps) : staticDefaultProps;
1169
1303
  let completeProps = core.mergeProps(defaultProps, props);
1170
- if (platform === "native" && component.domTag && props.display === "flex") completeProps = core.mergeProps(core.mergeProps(defaultProps, import_dom.NATIVE_FLEX_DEFAULTS), props);
1304
+ if (platform === "native" && component.domTag && props.display === "flex") {
1305
+ completeProps = core.mergeProps(core.mergeProps(defaultProps, import_dom.NATIVE_FLEX_DEFAULTS), props);
1306
+ }
1307
+ const propsForConditional = (target, value) => {
1308
+ const branchProps = {};
1309
+ for (const entry of input.element.entries) {
1310
+ if (entry === target) {
1311
+ branchProps[target.name] = value;
1312
+ continue;
1313
+ }
1314
+ if (entry.kind === "child" || entry.value.kind !== "static") continue;
1315
+ if (entry.kind === "spread") {
1316
+ if (staticObject(entry.value.value)) Object.assign(branchProps, entry.value.value);
1317
+ } else {
1318
+ branchProps[entry.name] = entry.value.value;
1319
+ }
1320
+ }
1321
+ if (component.domTag && branchProps.hidden) branchProps.display = "none";
1322
+ if (resolvedCssTransition !== null) {
1323
+ branchProps.transition = resolvedCssTransition;
1324
+ }
1325
+ if (component.domTag && platform === "native") {
1326
+ for (const [name, styleKey] of DOM_STYLE_ATTRIBUTES) {
1327
+ if (name in branchProps) {
1328
+ branchProps[styleKey] = branchProps[name];
1329
+ delete branchProps[name];
1330
+ }
1331
+ }
1332
+ }
1333
+ const branchCompleteProps = platform === "native" && component.domTag && branchProps.display === "flex" ? core.mergeProps(core.mergeProps(defaultProps, import_dom.NATIVE_FLEX_DEFAULTS), branchProps) : core.mergeProps(defaultProps, branchProps);
1334
+ return {
1335
+ branchProps,
1336
+ branchCompleteProps
1337
+ };
1338
+ };
1171
1339
  if (platform === "native") {
1172
1340
  const isClauseValue = (name, value) => isStyleProp(name, component) && (typeof value === "string" && flatClausePattern.test(value) || isClauseObjectValue(value));
1173
1341
  const defaultVariants = component.staticConfig.defaultVariants ?? {};
1174
- if (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)))) return bailout(input, "local/unsupported-target", "Native conditional value programs remain on the runtime path");
1342
+ 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)));
1343
+ if (carriesClause) {
1344
+ return bailout(input, "local/unsupported-target", "Native conditional value programs remain on the runtime path");
1345
+ }
1175
1346
  }
1176
1347
  const split = resolveSplitStyles(completeProps, component.staticConfig, cssAnimationDriver, component.displayName);
1177
- if (!split) return bailout(input, "local/style-resolution-failed", "getSplitStyles returned no static result");
1178
- if (split.programLifecycleStyleKeys?.enter?.size || split.programLifecycleStyleKeys?.exit?.size) return bailout(input, "local/unsupported-target", "Lifecycle value programs remain on the runtime path", input.element.span, {
1179
- rule: 5,
1180
- message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `an enter or exit style program on ${input.element.component.name}` })
1181
- });
1348
+ if (!split) {
1349
+ return bailout(input, "local/style-resolution-failed", "getSplitStyles returned no static result");
1350
+ }
1351
+ if (split.programLifecycleStyleKeys?.enter?.size || split.programLifecycleStyleKeys?.exit?.size) {
1352
+ return bailout(input, "local/unsupported-target", "Lifecycle value programs remain on the runtime path", input.element.span, {
1353
+ rule: 5,
1354
+ message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `an enter or exit style program on ${input.element.component.name}` })
1355
+ });
1356
+ }
1182
1357
  const domStyleProgram = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "style" && entry.value.kind === "dom-style");
1183
1358
  const flatTag = component.domTag ?? (typeof props.render === "string" ? props.render : typeof defaultProps.render === "string" ? defaultProps.render : component.staticConfig.isText ? "span" : "div");
1184
1359
  const tagEdits = [input.element.component.span, input.element.component.closingSpan].filter((span) => !!span).map((span) => ({
@@ -1187,7 +1362,17 @@ function createTamaguiCompilerHost(options) {
1187
1362
  content: input.element.form === "jsx" ? flatTag : JSON.stringify(flatTag),
1188
1363
  origin: span
1189
1364
  }));
1190
- 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).every((name) => isStyleProp(name, component) || isInvalidHostStyleProp(name, component)));
1365
+ const isPropIgnored = (name) => isStyleProp(name, component) || isInvalidHostStyleProp(name, component);
1366
+ const spreadReplacement = (form, entry) => spreadNonStyleReplacement(form, entry, isPropIgnored, (name, value) => {
1367
+ if (platform !== "web") return [name, value];
1368
+ if (name === "testID") return ["data-testid", value];
1369
+ if (component.domTag && name === "for") return ["htmlFor", value];
1370
+ if (component.domTag && name === "role" && value === "none") {
1371
+ return ["role", "presentation"];
1372
+ }
1373
+ return [name, value];
1374
+ });
1375
+ 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)));
1191
1376
  let invalidHostStyle;
1192
1377
  for (const entry of input.element.entries) {
1193
1378
  if (entry.kind === "prop") {
@@ -1211,7 +1396,15 @@ function createTamaguiCompilerHost(options) {
1211
1396
  }
1212
1397
  }
1213
1398
  }
1214
- if (invalidHostStyle) 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);
1399
+ if (invalidHostStyle) {
1400
+ 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);
1401
+ }
1402
+ if (platform === "native" && component.domTag) {
1403
+ 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)));
1404
+ if (mixedSpread) {
1405
+ return bailout(input, "local/unsafe-style-spread", "Native DOM prop mapping requires non-style spread props to remain on the runtime path", mixedSpread.span);
1406
+ }
1407
+ }
1215
1408
  const webPropEdits = platform === "web" ? input.element.entries.flatMap((entry) => {
1216
1409
  if (entry.kind !== "prop" || entry.name !== "testID") return [];
1217
1410
  const content = input.source.slice(entry.span.start, entry.span.end);
@@ -1220,7 +1413,7 @@ function createTamaguiCompilerHost(options) {
1220
1413
  const alreadyQuoted = content[nameOffset - 1] === "\"" || content[nameOffset - 1] === "'";
1221
1414
  return [{
1222
1415
  start: entry.span.start + nameOffset,
1223
- end: entry.span.start + nameOffset + 6,
1416
+ end: entry.span.start + nameOffset + "testID".length,
1224
1417
  content: input.element.form === "jsx" || alreadyQuoted ? "data-testid" : `'data-testid'`,
1225
1418
  origin: entry.span
1226
1419
  }];
@@ -1230,8 +1423,6 @@ function createTamaguiCompilerHost(options) {
1230
1423
  additions: []
1231
1424
  };
1232
1425
  webPropEdits.push(...webDOMResult.edits);
1233
- 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)));
1234
- if (unsafeSpread) return bailout(input, "local/unsafe-style-spread", "A mixed style/non-style spread cannot be removed transactionally", unsafeSpread.span);
1235
1426
  if (platform === "native") {
1236
1427
  const nativeStyleResolved = split.viewProps?.style;
1237
1428
  let themedStyleKeys = null;
@@ -1240,16 +1431,25 @@ function createTamaguiCompilerHost(options) {
1240
1431
  for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved)) {
1241
1432
  if (!core.containsThemeRef(styleValue)) continue;
1242
1433
  const themeKey = core.themeRefKey(styleValue);
1243
- if (!themeKey) return bailout(input, "local/dynamic-style-value", `Style ${styleKey} uses a theme value in a compound or modified position that compiled output cannot represent`);
1434
+ if (!themeKey) {
1435
+ return bailout(input, "local/dynamic-style-value", `Style ${styleKey} uses a theme value in a compound or modified position that compiled output cannot represent`);
1436
+ }
1437
+ ;
1244
1438
  (themedStyleKeys ||= {})[styleKey] = themeKey;
1245
1439
  }
1246
1440
  if (themedStyleKeys) {
1247
1441
  const plain = {};
1248
- for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved)) if (!(styleKey in themedStyleKeys)) plain[styleKey] = styleValue;
1442
+ for (const [styleKey, styleValue] of Object.entries(nativeStyleResolved)) {
1443
+ if (!(styleKey in themedStyleKeys)) plain[styleKey] = styleValue;
1444
+ }
1249
1445
  nativeStyle = plain;
1250
1446
  }
1251
- } else if (core.containsThemeRef(nativeStyleResolved)) return bailout(input, "local/dynamic-style-value", "Theme values inside non-object native style output stay on the runtime path");
1252
- if (!isSerializableNativeStyle(nativeStyle)) return bailout(input, "local/unsupported-target", "Native style output is not a static serializable value");
1447
+ } else if (core.containsThemeRef(nativeStyleResolved)) {
1448
+ return bailout(input, "local/dynamic-style-value", "Theme values inside non-object native style output stay on the runtime path");
1449
+ }
1450
+ if (!isSerializableNativeStyle(nativeStyle)) {
1451
+ return bailout(input, "local/unsupported-target", "Native style output is not a static serializable value");
1452
+ }
1253
1453
  const nativeStyleLocal = unusedIdentifier(input.source, `__TamaguiNativeStyle${input.element.span.start}`);
1254
1454
  const nativeStyleImports = [{
1255
1455
  content: `
@@ -1270,12 +1470,16 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
1270
1470
  };
1271
1471
  }
1272
1472
  if (component.domTag) {
1273
- if (themedStyleKeys) return bailout(input, "local/unsupported-target", "Theme values on DOM-tag native output stay on the runtime path");
1473
+ if (themedStyleKeys) {
1474
+ return bailout(input, "local/unsupported-target", "Theme values on DOM-tag native output stay on the runtime path");
1475
+ }
1274
1476
  const row = import_dom.TAGS[component.domTag];
1275
1477
  const basePrimitive = import_dom.NATIVE_BACKING[row.backing].primitive;
1276
1478
  let primitive = basePrimitive;
1277
1479
  const propsResult = nativeDOMProps(input, component.domTag);
1278
- if (propsResult.diagnostic) return bailout(input, "local/unsupported-target", propsResult.diagnostic, propsResult.diagnosticSpan);
1480
+ if (propsResult.diagnostic) {
1481
+ return bailout(input, "local/unsupported-target", propsResult.diagnostic, propsResult.diagnosticSpan);
1482
+ }
1279
1483
  styleEntries = [.../* @__PURE__ */ new Set([...styleEntries, ...propsResult.consumed])];
1280
1484
  let nativeDOMStyleSource = nativeStyleSource;
1281
1485
  let runtimeStyleSource = null;
@@ -1283,22 +1487,32 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
1283
1487
  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))));
1284
1488
  const itemSources = [];
1285
1489
  for (const item of domStyleProgram.value.items) {
1286
- if (item.value.kind !== "static" || !staticObject(item.value.value)) return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
1287
- if (Object.values(item.value.value).some((value2) => typeof value2 === "string" && nativeInitialKeywordPattern.test(value2))) return bailout(input, "local/unsupported-target", "Native DOM style() does not support the CSS initial keyword, matching the pinned upstream limitation", item.value.span);
1490
+ if (item.value.kind !== "static" || !staticObject(item.value.value)) {
1491
+ return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
1492
+ }
1493
+ if (Object.values(item.value.value).some((value2) => typeof value2 === "string" && nativeInitialKeywordPattern.test(value2))) {
1494
+ return bailout(input, "local/unsupported-target", "Native DOM style() does not support the CSS initial keyword, matching the pinned upstream limitation", item.value.span);
1495
+ }
1288
1496
  let value;
1289
- if (needsRuntime) value = JSON.stringify(item.value.value);
1290
- else {
1291
- const itemStyle = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig))?.viewProps?.style;
1292
- if (!isSerializableNativeStyle(itemStyle) || core.containsThemeRef(itemStyle)) return bailout(input, "local/unsupported-target", "Native style() output is not serializable", item.value.span);
1497
+ if (needsRuntime) {
1498
+ value = JSON.stringify(item.value.value);
1499
+ } else {
1500
+ const itemSplit = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig));
1501
+ const itemStyle = itemSplit?.viewProps?.style;
1502
+ if (!isSerializableNativeStyle(itemStyle) || core.containsThemeRef(itemStyle)) {
1503
+ return bailout(input, "local/unsupported-target", "Native style() output is not serializable", item.value.span);
1504
+ }
1293
1505
  value = JSON.stringify(itemStyle ?? {});
1294
1506
  }
1295
1507
  const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
1296
1508
  itemSources.push(condition ? `(${condition}) && ${value}` : value);
1297
1509
  }
1298
1510
  if (needsRuntime) {
1299
- primitive = `DOMRuntime${basePrimitive.slice(3)}`;
1511
+ primitive = `DOMRuntime${basePrimitive.slice("DOM".length)}`;
1300
1512
  runtimeStyleSource = `[${itemSources.join(", ")}]`;
1301
- } else nativeDOMStyleSource = `[${[nativeDOMStyleSource, ...itemSources].join(", ")}]`;
1513
+ } else {
1514
+ nativeDOMStyleSource = `[${[nativeDOMStyleSource, ...itemSources].join(", ")}]`;
1515
+ }
1302
1516
  }
1303
1517
  const nativeLocal2 = unusedIdentifier(input.source, `__Tamagui${primitive}`);
1304
1518
  const propertyContent = [
@@ -1326,17 +1540,22 @@ import { ${primitive} as ${nativeLocal2} } from ${JSON.stringify(import_dom.NATI
1326
1540
  let needsCreateElement = false;
1327
1541
  for (const entry of input.element.entries) {
1328
1542
  if (entry.kind !== "child") continue;
1329
- if (entry.value.kind === "empty" || entry.value.kind === "element" || entry.value.kind === "static" && (entry.value.value === null || typeof entry.value.value === "boolean")) continue;
1330
- if (entry.value.kind !== "static" || entry.value.literalOrigin !== true || typeof entry.value.value !== "string" && typeof entry.value.value !== "number") 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);
1543
+ if (entry.value.kind === "empty" || entry.value.kind === "element" || entry.value.kind === "static" && (entry.value.value === null || typeof entry.value.value === "boolean")) {
1544
+ continue;
1545
+ }
1546
+ if (entry.value.kind !== "static" || entry.value.literalOrigin !== true || typeof entry.value.value !== "string" && typeof entry.value.value !== "number") {
1547
+ 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);
1548
+ }
1331
1549
  needsText = true;
1332
1550
  const child = input.source.slice(entry.span.start, entry.span.end);
1333
- if (input.element.form === "jsx") literalEdits.push({
1334
- start: entry.span.start,
1335
- end: entry.span.end,
1336
- content: `<${textLocal} __inherit>${child}</${textLocal}>`,
1337
- origin: entry.span
1338
- });
1339
- else {
1551
+ if (input.element.form === "jsx") {
1552
+ literalEdits.push({
1553
+ start: entry.span.start,
1554
+ end: entry.span.end,
1555
+ content: `<${textLocal} __inherit>${child}</${textLocal}>`,
1556
+ origin: entry.span
1557
+ });
1558
+ } else {
1340
1559
  needsCreateElement = true;
1341
1560
  literalEdits.push({
1342
1561
  start: entry.span.start,
@@ -1346,36 +1565,44 @@ import { ${primitive} as ${nativeLocal2} } from ${JSON.stringify(import_dom.NATI
1346
1565
  });
1347
1566
  }
1348
1567
  }
1349
- if (needsText) imports.push({
1350
- content: `
1568
+ if (needsText) {
1569
+ imports.push({
1570
+ content: `
1351
1571
  import { DOMText as ${textLocal} } from ${JSON.stringify(import_dom.NATIVE_PRIMITIVE_MODULE)}
1352
1572
  `,
1353
- origin: input.element.component.span
1354
- });
1355
- if (needsCreateElement) imports.push({
1356
- content: `
1573
+ origin: input.element.component.span
1574
+ });
1575
+ }
1576
+ if (needsCreateElement) {
1577
+ imports.push({
1578
+ content: `
1357
1579
  import { createElement as ${createElementLocal} } from "react"
1358
1580
  `,
1359
- origin: input.element.component.span
1360
- });
1581
+ origin: input.element.component.span
1582
+ });
1583
+ }
1361
1584
  }
1585
+ const [first3, ...rest3] = styleEntries;
1586
+ const firstNonStyle3 = first3 ? spreadReplacement("jsx", first3) : "";
1362
1587
  const propsEdits = input.element.form === "jsx" ? styleEntries.length === 0 ? [{
1363
1588
  start: input.element.component.span.end,
1364
1589
  end: input.element.component.span.end,
1365
1590
  content: ` ${propertyContent}`,
1366
1591
  origin: input.element.component.span
1367
1592
  }] : [{
1368
- start: styleEntries[0].span.start,
1369
- end: styleEntries[0].span.end,
1370
- content: propertyContent,
1371
- origin: styleEntries[0].span
1372
- }, ...styleEntries.slice(1).map((entry) => ({
1593
+ start: first3.span.start,
1594
+ end: first3.span.end,
1595
+ content: [propertyContent, firstNonStyle3].filter(Boolean).join(" "),
1596
+ origin: first3.span
1597
+ }, ...rest3.map((entry) => ({
1373
1598
  start: entry.span.start,
1374
1599
  end: entry.span.end,
1375
- content: "",
1600
+ content: spreadReplacement("jsx", entry),
1376
1601
  origin: entry.span
1377
- }))] : compiledPropsEdits(input, styleEntries, propertyContent);
1378
- if (!propsEdits) return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1602
+ }))] : compiledPropsEdits(input, styleEntries, propertyContent, (entry) => spreadReplacement(input.element.form, entry));
1603
+ if (!propsEdits) {
1604
+ return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1605
+ }
1379
1606
  return {
1380
1607
  ok: true,
1381
1608
  edits: [
@@ -1393,7 +1620,9 @@ import { createElement as ${createElementLocal} } from "react"
1393
1620
  const useHostView = options.experimentalNativeFastPath && nativeName === "View" && isBareHostView(input.element);
1394
1621
  const nativeExport = useHostView ? "unstable_NativeView" : nativeName;
1395
1622
  const nativeLocal = unusedIdentifier(input.source, `__TamaguiNative${useHostView ? "HostView" : nativeName}`);
1396
- if (themedStyleKeys && options.disablePartialExtraction) return bailout(input, "local/dynamic-style-value", "Theme values require partial extraction, which is disabled");
1623
+ if (themedStyleKeys && options.disablePartialExtraction) {
1624
+ return bailout(input, "local/dynamic-style-value", "Theme values require partial extraction, which is disabled");
1625
+ }
1397
1626
  if (dynamicStyleEntries.length > 0 || themedStyleKeys) {
1398
1627
  if (nativeFastPath) {
1399
1628
  const fastLocal = `__TamaguiNativeFast${nativeName}${input.element.span.start}`;
@@ -1415,7 +1644,9 @@ import { createElement as ${createElementLocal} } from "react"
1415
1644
  content: "",
1416
1645
  origin: entry.span
1417
1646
  }))] : compiledPropsEdits(input, styleEntries, `_expressions: []`);
1418
- if (!styleEdits) return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1647
+ if (!styleEdits) {
1648
+ return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1649
+ }
1419
1650
  return {
1420
1651
  ok: true,
1421
1652
  edits: [...tagEdits4, ...styleEdits],
@@ -1443,34 +1674,63 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
1443
1674
  const conditionalParts = [];
1444
1675
  const conditionalKeys = /* @__PURE__ */ new Set();
1445
1676
  const baseStyleForDiff = staticObject(nativeStyleResolved) ? nativeStyleResolved : {};
1446
- for (const entry of dynamicStyleEntries) if (entry.value.kind === "conditional" && directStyleName(entry.name, component) !== "opacity") {
1447
- const branchDiffs = [];
1448
- for (const branchValue of [entry.value.whenTrue, entry.value.whenFalse]) {
1449
- const branchSplit = resolveSplitStyles({
1450
- ...completeProps,
1451
- [entry.name]: branchValue
1452
- }, component.staticConfig, cssAnimationDriver, component.displayName);
1453
- const branchStyle = branchSplit?.viewProps?.style;
1454
- if (!staticObject(branchStyle)) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch did not resolve to a static native style`, entry.value.span);
1455
- for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit?.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
1456
- if (viewPropsKey === "style") continue;
1457
- if (JSON.stringify(branchSplit?.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which the compiled style array cannot express`, entry.value.span);
1677
+ for (const entry of dynamicStyleEntries) {
1678
+ if (entry.value.kind === "conditional" && directStyleName(entry.name, component) !== "opacity") {
1679
+ let serializeNativeTree = function(node) {
1680
+ if (node.kind === "leaf") {
1681
+ const diff = leafDiffs.get(node) ?? {};
1682
+ return JSON.stringify(diff);
1683
+ }
1684
+ const index = expressions.length;
1685
+ expressions.push(input.source.slice(node.test.start, node.test.end));
1686
+ return `expressions[${index}] ? ${serializeNativeTree(node.whenTrue)} : ${serializeNativeTree(node.whenFalse)}`;
1687
+ };
1688
+ const tree = entry.value.tree;
1689
+ const leaves = (0, import_compiler_core.collectLeaves)(tree);
1690
+ const leafDiffs = /* @__PURE__ */ new Map();
1691
+ for (const leaf of leaves) {
1692
+ const { branchCompleteProps } = propsForConditional(entry, leaf.value);
1693
+ const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
1694
+ const branchStyle = branchSplit?.viewProps?.style ?? {};
1695
+ if (!staticObject(branchStyle)) {
1696
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch did not resolve to a static native style`, entry.value.span);
1697
+ }
1698
+ for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit?.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
1699
+ if (viewPropsKey === "style") continue;
1700
+ if (JSON.stringify(branchSplit?.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
1701
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which the compiled style array cannot express`, entry.value.span);
1702
+ }
1703
+ }
1704
+ for (const key of Object.keys(baseStyleForDiff)) {
1705
+ if (!(key in branchStyle)) {
1706
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch removes ${key}, which an additive style array cannot express`, entry.value.span);
1707
+ }
1708
+ }
1709
+ const diff = {};
1710
+ for (const [key, value] of Object.entries(branchStyle)) {
1711
+ if (JSON.stringify(baseStyleForDiff[key]) !== JSON.stringify(value)) {
1712
+ diff[key] = value;
1713
+ }
1714
+ }
1715
+ if (!isSerializableNativeStyle(diff) || core.containsThemeRef(diff)) {
1716
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch style is not statically representable`, entry.value.span);
1717
+ }
1718
+ for (const key of Object.keys(diff)) {
1719
+ if (conditionalKeys.has(key)) {
1720
+ return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
1721
+ }
1722
+ }
1723
+ leafDiffs.set(leaf, diff);
1724
+ }
1725
+ for (const diff of leafDiffs.values()) {
1726
+ for (const key of Object.keys(diff)) conditionalKeys.add(key);
1458
1727
  }
1459
- for (const key of Object.keys(baseStyleForDiff)) if (!(key in branchStyle)) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch removes ${key}, which an additive style array cannot express`, entry.value.span);
1460
- const diff = {};
1461
- for (const [key, value] of Object.entries(branchStyle)) if (JSON.stringify(baseStyleForDiff[key]) !== JSON.stringify(value)) diff[key] = value;
1462
- if (!isSerializableNativeStyle(diff) || core.containsThemeRef(diff)) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch style is not statically representable`, entry.value.span);
1463
- for (const key of Object.keys(diff)) if (conditionalKeys.has(key)) return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
1464
- branchDiffs.push(diff);
1728
+ conditionalParts.push(serializeNativeTree(tree));
1729
+ } else {
1730
+ const index = expressions.length;
1731
+ expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
1732
+ plainDynamicParts.push(`${JSON.stringify(directStyleName(entry.name, component))}: expressions[${index}]`);
1465
1733
  }
1466
- for (const diff of branchDiffs) for (const key of Object.keys(diff)) conditionalKeys.add(key);
1467
- const index = expressions.length;
1468
- expressions.push(input.source.slice(entry.value.test.start, entry.value.test.end));
1469
- conditionalParts.push(`expressions[${index}] ? ${JSON.stringify(branchDiffs[0])} : ${JSON.stringify(branchDiffs[1])}`);
1470
- } else {
1471
- const index = expressions.length;
1472
- expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
1473
- plainDynamicParts.push(`${JSON.stringify(directStyleName(entry.name, component))}: expressions[${index}]`);
1474
1734
  }
1475
1735
  const dynamicStyle = plainDynamicParts.join(", ");
1476
1736
  const themedStyle = themedStyleKeys ? Object.entries(themedStyleKeys).map(([styleKey, themeKey]) => `${JSON.stringify(styleKey)}: _theme[${JSON.stringify(themeKey)}]?.get()`).join(", ") : null;
@@ -1487,18 +1747,21 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
1487
1747
  origin: span
1488
1748
  }));
1489
1749
  const [first3, ...rest3] = styleEntries;
1750
+ const firstNonStyle3 = first3 ? spreadReplacement("jsx", first3) : "";
1490
1751
  const expressionEdits = styleEntries.length === 0 ? [] : input.element.form === "jsx" ? [{
1491
1752
  start: first3.span.start,
1492
1753
  end: first3.span.end,
1493
- content: expressions.length > 0 ? `_expressions={[${expressions.join(", ")}]}` : "",
1754
+ content: [expressions.length > 0 ? `_expressions={[${expressions.join(", ")}]}` : "", firstNonStyle3].filter(Boolean).join(" "),
1494
1755
  origin: first3.span
1495
1756
  }, ...rest3.map((entry) => ({
1496
1757
  start: entry.span.start,
1497
1758
  end: entry.span.end,
1498
- content: "",
1759
+ content: spreadReplacement("jsx", entry),
1499
1760
  origin: entry.span
1500
- }))] : compiledPropsEdits(input, styleEntries, `_expressions: [${expressions.join(", ")}]`);
1501
- if (!expressionEdits) return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1761
+ }))] : compiledPropsEdits(input, styleEntries, `_expressions: [${expressions.join(", ")}]`, (entry) => spreadReplacement(input.element.form, entry));
1762
+ if (!expressionEdits) {
1763
+ return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1764
+ }
1502
1765
  return {
1503
1766
  ok: true,
1504
1767
  edits: [...tagEdits3, ...expressionEdits],
@@ -1527,8 +1790,10 @@ const ${stableLocal} = require('@tamagui/core')._withStableStyle(${nativeLocal},
1527
1790
  origin: span
1528
1791
  }));
1529
1792
  if (input.element.form !== "jsx") {
1530
- const propsEdits = compiledPropsEdits(input, styleEntries, styleContent);
1531
- if (!propsEdits) return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1793
+ const propsEdits = compiledPropsEdits(input, styleEntries, styleContent, (entry) => spreadReplacement(input.element.form, entry));
1794
+ if (!propsEdits) {
1795
+ return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1796
+ }
1532
1797
  return {
1533
1798
  ok: true,
1534
1799
  edits: [...tagEdits2, ...propsEdits],
@@ -1541,23 +1806,26 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1541
1806
  flattened: true
1542
1807
  };
1543
1808
  }
1544
- if (styleEntries.length === 0) return {
1545
- ok: true,
1546
- edits: [...tagEdits2, {
1547
- start: input.element.component.span.end,
1548
- end: input.element.component.span.end,
1549
- content: ` style={${nativeStyleSource}}`,
1550
- origin: input.element.component.span
1551
- }],
1552
- css: [],
1553
- imports: [...nativeStyleImports, {
1554
- content: `
1809
+ if (styleEntries.length === 0) {
1810
+ return {
1811
+ ok: true,
1812
+ edits: [...tagEdits2, {
1813
+ start: input.element.component.span.end,
1814
+ end: input.element.component.span.end,
1815
+ content: ` style={${nativeStyleSource}}`,
1816
+ origin: input.element.component.span
1817
+ }],
1818
+ css: [],
1819
+ imports: [...nativeStyleImports, {
1820
+ content: `
1555
1821
  const ${nativeLocal} = require('react-native').${nativeExport};`,
1556
- origin: input.element.component.span
1557
- }],
1558
- flattened: true
1559
- };
1822
+ origin: input.element.component.span
1823
+ }],
1824
+ flattened: true
1825
+ };
1826
+ }
1560
1827
  const [first2, ...rest2] = styleEntries;
1828
+ const firstNonStyle2 = first2 ? spreadReplacement("jsx", first2) : "";
1561
1829
  return {
1562
1830
  ok: true,
1563
1831
  edits: [
@@ -1566,13 +1834,13 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1566
1834
  {
1567
1835
  start: first2.span.start,
1568
1836
  end: first2.span.end,
1569
- content: `style={${nativeStyleSource}}`,
1837
+ content: [`style={${nativeStyleSource}}`, firstNonStyle2].filter(Boolean).join(" "),
1570
1838
  origin: first2.span
1571
1839
  },
1572
1840
  ...rest2.map((entry) => ({
1573
1841
  start: entry.span.start,
1574
1842
  end: entry.span.end,
1575
- content: "",
1843
+ content: spreadReplacement("jsx", entry),
1576
1844
  origin: entry.span
1577
1845
  }))
1578
1846
  ],
@@ -1588,60 +1856,112 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1588
1856
  const artifacts = extractedStyleArtifacts(split, props, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
1589
1857
  const className = artifacts.className;
1590
1858
  const rawInlineStyle = split.viewProps?.style;
1591
- const inlineStyle = staticObject(rawInlineStyle) && !rawInlineStyle["$$css"] && Object.keys(rawInlineStyle).length > 0 ? rawInlineStyle : null;
1592
- if (rawInlineStyle && !inlineStyle && !isSerializableNativeStyle(rawInlineStyle)) return bailout(input, "local/unsupported-target", "Web inline style output is not a static serializable value");
1859
+ const inlineStyle = staticObject(rawInlineStyle) && Object.keys(rawInlineStyle).length > 0 ? rawInlineStyle : null;
1860
+ if (rawInlineStyle && !inlineStyle && !isSerializableNativeStyle(rawInlineStyle)) {
1861
+ return bailout(input, "local/unsupported-target", "Web inline style output is not a static serializable value");
1862
+ }
1593
1863
  const programCSS = [];
1594
1864
  const programClassSources = [];
1595
- if (domStyleProgram?.kind === "prop" && domStyleProgram.value.kind === "dom-style") for (const item of domStyleProgram.value.items) {
1596
- if (item.value.kind !== "static" || !staticObject(item.value.value)) return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
1597
- const itemSplit = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig));
1598
- if (!itemSplit) return bailout(input, "local/style-resolution-failed", "A style() handle could not be resolved", item.value.span);
1599
- const itemInline = itemSplit.viewProps?.style;
1600
- if (staticObject(itemInline) && !itemInline["$$css"] && Object.keys(itemInline).length > 0) return bailout(input, "local/unsupported-target", "Conditional web style() handles must lower to CSS classes", item.value.span);
1601
- const itemArtifacts = extractedStyleArtifacts(itemSplit, item.value.value, options.tamaguiConfig, false);
1602
- programCSS.push(...itemArtifacts.css);
1603
- if (itemArtifacts.className) {
1604
- const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
1605
- programClassSources.push(condition ? `(${condition}) && ${JSON.stringify(itemArtifacts.className)}` : JSON.stringify(itemArtifacts.className));
1865
+ if (domStyleProgram?.kind === "prop" && domStyleProgram.value.kind === "dom-style") {
1866
+ for (const item of domStyleProgram.value.items) {
1867
+ if (item.value.kind !== "static" || !staticObject(item.value.value)) {
1868
+ return bailout(input, "local/dynamic-style-value", "Every style() handle in a style array must be statically evaluable", item.value.span);
1869
+ }
1870
+ const itemSplit = resolveSplitStyles(item.value.value, partialStaticConfig(component.staticConfig));
1871
+ if (!itemSplit) {
1872
+ return bailout(input, "local/style-resolution-failed", "A style() handle could not be resolved", item.value.span);
1873
+ }
1874
+ const itemInline = itemSplit.viewProps?.style;
1875
+ if (staticObject(itemInline) && Object.keys(itemInline).length > 0) {
1876
+ return bailout(input, "local/unsupported-target", "Conditional web style() handles must lower to CSS classes", item.value.span);
1877
+ }
1878
+ const itemArtifacts = extractedStyleArtifacts(itemSplit, item.value.value, options.tamaguiConfig, false);
1879
+ programCSS.push(...itemArtifacts.css);
1880
+ if (itemArtifacts.className) {
1881
+ const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
1882
+ programClassSources.push(condition ? `(${condition}) && ${JSON.stringify(itemArtifacts.className)}` : JSON.stringify(itemArtifacts.className));
1883
+ }
1606
1884
  }
1607
1885
  }
1608
- let webClassName = className;
1886
+ const baseStaticClasses = new Set(className.split(" ").filter(Boolean));
1887
+ const staticClasses = new Set(baseStaticClasses);
1609
1888
  const webConditionalCSS = [];
1889
+ const webConditionalKeys = /* @__PURE__ */ new Set();
1610
1890
  const webConditionalEntries = supportsWebConditionalClasses ? dynamicStyleEntries.filter((entry) => entry.value.kind === "conditional") : [];
1611
1891
  for (const entry of webConditionalEntries) {
1892
+ let serializeWebTree = function(node) {
1893
+ if (node.kind === "leaf") {
1894
+ const artifacts2 = leafArtifactsMap.get(node);
1895
+ const only = artifacts2 ? artifacts2.classes.filter((item) => !sharedInConditional.has(item)) : [];
1896
+ return JSON.stringify(only.join(" "));
1897
+ }
1898
+ const test = input.source.slice(node.test.start, node.test.end);
1899
+ const truePart = serializeWebTree(node.whenTrue);
1900
+ const falsePart = serializeWebTree(node.whenFalse);
1901
+ return `(${test}) ? ${truePart} : ${falsePart}`;
1902
+ };
1612
1903
  if (entry.value.kind !== "conditional") continue;
1613
- const branches = [];
1614
- for (const branchValue of [entry.value.whenTrue, entry.value.whenFalse]) {
1615
- const branchSplit = resolveSplitStyles({
1616
- ...completeProps,
1617
- [entry.name]: branchValue
1618
- }, component.staticConfig, cssAnimationDriver, component.displayName);
1619
- if (!branchSplit) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch could not be resolved`, entry.value.span);
1904
+ const tree = entry.value.tree;
1905
+ const leaves = (0, import_compiler_core.collectLeaves)(tree);
1906
+ const leafArtifactsMap = /* @__PURE__ */ new Map();
1907
+ const entryConditionalKeys = /* @__PURE__ */ new Set();
1908
+ for (const leaf of leaves) {
1909
+ const { branchProps, branchCompleteProps } = propsForConditional(entry, leaf.value);
1910
+ const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
1911
+ if (!branchSplit) {
1912
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch could not be resolved`, entry.value.span);
1913
+ }
1620
1914
  for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
1621
1915
  if (viewPropsKey === "className") continue;
1622
- if (JSON.stringify(branchSplit.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which conditional classes cannot express`, entry.value.span);
1916
+ if (JSON.stringify(branchSplit.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
1917
+ return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which conditional classes cannot express`, entry.value.span);
1918
+ }
1623
1919
  }
1624
- const branchArtifacts = extractedStyleArtifacts(branchSplit, {
1625
- ...props,
1626
- [entry.name]: branchValue
1627
- }, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
1628
- branches.push({
1920
+ const changedKeys = /* @__PURE__ */ new Set();
1921
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(branchSplit.classNames ?? {}), ...Object.keys(split.classNames ?? {})])) {
1922
+ if (JSON.stringify(branchSplit.classNames?.[key]) !== JSON.stringify(split.classNames?.[key])) {
1923
+ changedKeys.add(key);
1924
+ }
1925
+ }
1926
+ const branchStyle = branchSplit.viewProps?.style;
1927
+ const baseStyle = split.viewProps?.style;
1928
+ if (staticObject(branchStyle) || staticObject(baseStyle)) {
1929
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(staticObject(branchStyle) ? branchStyle : {}), ...Object.keys(staticObject(baseStyle) ? baseStyle : {})])) {
1930
+ if (JSON.stringify(staticObject(branchStyle) ? branchStyle[key] : void 0) !== JSON.stringify(staticObject(baseStyle) ? baseStyle[key] : void 0)) {
1931
+ changedKeys.add(key);
1932
+ }
1933
+ }
1934
+ }
1935
+ for (const key of changedKeys) {
1936
+ if (webConditionalKeys.has(key)) {
1937
+ return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
1938
+ }
1939
+ entryConditionalKeys.add(key);
1940
+ }
1941
+ const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
1942
+ leafArtifactsMap.set(leaf, {
1629
1943
  classes: branchArtifacts.className.split(" ").filter(Boolean),
1630
1944
  css: branchArtifacts.css
1631
1945
  });
1632
1946
  }
1633
- const [whenTrue, whenFalse] = branches;
1634
- const shared = new Set(whenTrue.classes.filter((item) => whenFalse.classes.includes(item)));
1635
- const trueOnly = whenTrue.classes.filter((item) => !shared.has(item));
1636
- const falseOnly = whenFalse.classes.filter((item) => !shared.has(item));
1637
- webClassName = [...shared].join(" ");
1638
- webConditionalCSS.push(...whenTrue.css, ...whenFalse.css);
1639
- if (trueOnly.length > 0 || falseOnly.length > 0) {
1640
- const test = input.source.slice(entry.value.test.start, entry.value.test.end);
1641
- programClassSources.push(`(${test}) ? ${JSON.stringify(trueOnly.join(" "))} : ${JSON.stringify(falseOnly.join(" "))}`);
1947
+ for (const key of entryConditionalKeys) webConditionalKeys.add(key);
1948
+ for (const artifacts2 of leafArtifactsMap.values()) {
1949
+ webConditionalCSS.push(...artifacts2.css);
1642
1950
  }
1951
+ const allLeafArtifacts = leaves.map((l) => leafArtifactsMap.get(l));
1952
+ const sharedInConditional = new Set(allLeafArtifacts[0]?.classes.filter((c) => allLeafArtifacts.every((a) => a.classes.includes(c))) ?? []);
1953
+ for (const cls of baseStaticClasses) {
1954
+ if (!sharedInConditional.has(cls)) staticClasses.delete(cls);
1955
+ }
1956
+ for (const cls of sharedInConditional) {
1957
+ if (!baseStaticClasses.has(cls)) staticClasses.add(cls);
1958
+ }
1959
+ const classExpr = serializeWebTree(tree);
1960
+ programClassSources.push(classExpr);
1643
1961
  }
1644
- const classNameExpression = programClassSources.length > 0 ? `[${[JSON.stringify(webClassName), ...programClassSources].join(", ")}].filter(Boolean).join(" ")` : null;
1962
+ const webClassName = [...staticClasses].join(" ");
1963
+ const hasStyleProgram = programClassSources.length > 0;
1964
+ const classNameExpression = hasStyleProgram ? `[${[JSON.stringify(webClassName), ...programClassSources].join(", ")}].filter(Boolean).join(" ")` : null;
1645
1965
  const serializedInlineStyle = serializedStyle(inlineStyle, dynamicHostStyleProperties ?? []);
1646
1966
  const jsxWebStyle = classNameExpression ? [`className={${classNameExpression}}`, serializedInlineStyle ? `style={${serializedInlineStyle}}` : ""].filter(Boolean).join(" ") : jsxStyleAttributes(webClassName, inlineStyle, dynamicHostStyleProperties ?? []);
1647
1967
  const objectWebStyle = classNameExpression ? [`className: ${classNameExpression}`, serializedInlineStyle ? `style: ${serializedInlineStyle}` : ""].filter(Boolean).join(", ") : objectStyleProperties(webClassName, inlineStyle, dynamicHostStyleProperties ?? []);
@@ -1653,8 +1973,10 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1653
1973
  const webExtraProps = serializedProps(input.element.form, webDOMResult.additions);
1654
1974
  if (input.element.form !== "jsx") {
1655
1975
  const replacement = [objectWebStyle, webExtraProps].filter(Boolean).join(", ");
1656
- const propsEdits = compiledPropsEdits(input, styleEntries, replacement);
1657
- if (!propsEdits) return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1976
+ const propsEdits = compiledPropsEdits(input, styleEntries, replacement, (entry) => spreadReplacement(input.element.form, entry));
1977
+ if (!propsEdits) {
1978
+ return bailout(input, "local/unsupported-target", `Compiled ${input.element.form} call has no editable props argument`);
1979
+ }
1658
1980
  return {
1659
1981
  ok: true,
1660
1982
  edits: [
@@ -1687,7 +2009,12 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1687
2009
  };
1688
2010
  }
1689
2011
  const [first, ...rest] = styleEntries;
1690
- const attributes = [jsxWebStyle, webExtraProps].filter(Boolean).join(" ");
2012
+ const firstNonStyle = first ? spreadReplacement("jsx", first) : "";
2013
+ const attributes = [
2014
+ jsxWebStyle,
2015
+ webExtraProps,
2016
+ firstNonStyle
2017
+ ].filter(Boolean).join(" ");
1691
2018
  return {
1692
2019
  ok: true,
1693
2020
  edits: [
@@ -1702,7 +2029,7 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
1702
2029
  ...rest.map((entry) => ({
1703
2030
  start: entry.span.start,
1704
2031
  end: entry.span.end,
1705
- content: "",
2032
+ content: spreadReplacement("jsx", entry),
1706
2033
  origin: entry.span
1707
2034
  }))
1708
2035
  ],