@tamagui/static 3.0.0-beta.924.1 → 3.0.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.
Files changed (59) hide show
  1. package/dist/cjs/compilerHost.cjs +241 -75
  2. package/dist/cjs/exports.cjs +5 -1
  3. package/dist/cjs/extractor/bundle.cjs +14 -9
  4. package/dist/cjs/extractor/bundleConfig.cjs +0 -1
  5. package/dist/cjs/extractor/esbuildTsconfigPaths.cjs +81 -45
  6. package/dist/cjs/extractor/generateConfigMarkdown.cjs +492 -0
  7. package/dist/cjs/extractor/loadTamagui.cjs +28 -20
  8. package/dist/cjs/extractor/regenerateConfig.cjs +30 -20
  9. package/dist/cjs/zero/islands.cjs +2 -1
  10. package/dist/cjs/zero/theme.cjs +6 -3
  11. package/dist/esm/compilerHost.mjs +242 -76
  12. package/dist/esm/compilerHost.mjs.map +1 -1
  13. package/dist/esm/exports.mjs +3 -1
  14. package/dist/esm/extractor/bundle.mjs +14 -9
  15. package/dist/esm/extractor/bundle.mjs.map +1 -1
  16. package/dist/esm/extractor/bundleConfig.mjs +0 -1
  17. package/dist/esm/extractor/bundleConfig.mjs.map +1 -1
  18. package/dist/esm/extractor/esbuildTsconfigPaths.mjs +80 -45
  19. package/dist/esm/extractor/esbuildTsconfigPaths.mjs.map +1 -1
  20. package/dist/esm/extractor/generateConfigMarkdown.mjs +472 -0
  21. package/dist/esm/extractor/generateConfigMarkdown.mjs.map +1 -0
  22. package/dist/esm/extractor/loadTamagui.mjs +28 -20
  23. package/dist/esm/extractor/loadTamagui.mjs.map +1 -1
  24. package/dist/esm/extractor/regenerateConfig.mjs +30 -20
  25. package/dist/esm/extractor/regenerateConfig.mjs.map +1 -1
  26. package/dist/esm/zero/islands.mjs +2 -1
  27. package/dist/esm/zero/islands.mjs.map +1 -1
  28. package/dist/esm/zero/theme.mjs +7 -4
  29. package/dist/esm/zero/theme.mjs.map +1 -1
  30. package/package.json +23 -20
  31. package/src/compilerHost.ts +387 -160
  32. package/src/exports.ts +3 -0
  33. package/src/extractor/bundle.ts +19 -7
  34. package/src/extractor/bundleConfig.ts +0 -1
  35. package/src/extractor/esbuildTsconfigPaths.ts +106 -78
  36. package/src/extractor/generateConfigMarkdown.ts +610 -0
  37. package/src/extractor/loadTamagui.ts +55 -24
  38. package/src/extractor/regenerateConfig.ts +36 -35
  39. package/src/zero/islands.ts +2 -1
  40. package/src/zero/options.ts +8 -3
  41. package/src/zero/theme.ts +29 -4
  42. package/types/compilerHost.d.ts.map +1 -1
  43. package/types/exports.d.ts +2 -0
  44. package/types/exports.d.ts.map +1 -1
  45. package/types/extractor/bundle.d.ts.map +1 -1
  46. package/types/extractor/bundleConfig.d.ts.map +1 -1
  47. package/types/extractor/esbuildTsconfigPaths.d.ts +5 -7
  48. package/types/extractor/esbuildTsconfigPaths.d.ts.map +1 -1
  49. package/types/extractor/generateConfigMarkdown.d.ts +5 -0
  50. package/types/extractor/generateConfigMarkdown.d.ts.map +1 -0
  51. package/types/extractor/loadTamagui.d.ts +13 -1
  52. package/types/extractor/loadTamagui.d.ts.map +1 -1
  53. package/types/extractor/regenerateConfig.d.ts.map +1 -1
  54. package/types/zero/identity.d.ts +1 -1
  55. package/types/zero/islands.d.ts.map +1 -1
  56. package/types/zero/options.d.ts +8 -3
  57. package/types/zero/options.d.ts.map +1 -1
  58. package/types/zero/theme.d.ts +2 -0
  59. package/types/zero/theme.d.ts.map +1 -1
@@ -27,6 +27,7 @@ module.exports = __toCommonJS(compilerHost_exports);
27
27
  var import_compiler_core = require("@tamagui/compiler-core");
28
28
  var import_helpers = require("@tamagui/helpers");
29
29
  var import_dom = require("@tamagui/dom");
30
+ var import_animation_helpers = require("@tamagui/animation-helpers");
30
31
  var import_tooling = require("@tamagui/style-grammar/tooling");
31
32
  var import_web = require("@tamagui/web");
32
33
  var import_concatClassName = require("./extractor/concatClassName.cjs");
@@ -64,13 +65,6 @@ const nativeRuntimeOnlyStyleProperties = /* @__PURE__ */ new Set(["textIndent"])
64
65
  function componentKey(resolvedId, exportName) {
65
66
  return `${resolvedId}#${exportName}`;
66
67
  }
67
- function cssFromRules(rules) {
68
- return Object.values(rules).flatMap((styleObject) => {
69
- const identifier = styleObject?.[import_helpers.StyleObjectIdentifier];
70
- const styleRules = styleObject?.[import_helpers.StyleObjectRules];
71
- return identifier && Array.isArray(styleRules) ? styleRules : [];
72
- });
73
- }
74
68
  function jsxClassName(value) {
75
69
  return `className=${JSON.stringify(value)}`;
76
70
  }
@@ -94,7 +88,16 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
94
88
  const viewClassName = typeof split.viewProps?.className === "string" ? split.viewProps.className : "";
95
89
  const classNameWithoutCaller = callerClassName && viewClassName.endsWith(callerClassName) ? viewClassName.slice(0, -callerClassName.length).trimEnd() : viewClassName;
96
90
  const rules = split.rulesToInsert ?? {};
97
- const mediaNames = new Set(Object.keys(config.media ?? {}));
91
+ const mediaNames = Object.keys(config.media ?? {});
92
+ const rulesByIdentifier = /* @__PURE__ */ new Map();
93
+ for (const styleObject of Object.values(rules)) {
94
+ const identifier = styleObject?.[import_helpers.StyleObjectIdentifier];
95
+ const styleRules = styleObject?.[import_helpers.StyleObjectRules];
96
+ if (typeof identifier !== "string" || !Array.isArray(styleRules)) continue;
97
+ const existing = rulesByIdentifier.get(identifier);
98
+ if (existing) existing.push(...styleRules);
99
+ else rulesByIdentifier.set(identifier, [...styleRules]);
100
+ }
98
101
  const pseudoNames = [
99
102
  "hover",
100
103
  "press",
@@ -120,14 +123,14 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
120
123
  })]);
121
124
  for (const identifier of identifiers) {
122
125
  const key = classKeys.get(identifier) ?? "";
123
- const css2 = cssFromRules(Object.fromEntries(Object.entries(rules).filter(([, styleObject]) => styleObject?.[import_helpers.StyleObjectIdentifier] === identifier))).join("");
126
+ const css2 = (rulesByIdentifier.get(identifier) ?? []).join("");
124
127
  if (identifier.startsWith("t_group_")) {
125
128
  buckets.group.push(identifier);
126
129
  } else if (pseudoNames.some((name) => key.endsWith(`-${name}`))) {
127
130
  buckets.pseudo.push(identifier);
128
131
  } else if (css2.includes(".t_")) {
129
132
  buckets.theme.push(identifier);
130
- } else if ([...mediaNames].some((name) => key.endsWith(`-${name}`))) {
133
+ } else if (mediaNames.some((name) => key.endsWith(`-${name}`))) {
131
134
  buckets.media.push(identifier);
132
135
  } else {
133
136
  buckets.normal.push(identifier);
@@ -143,7 +146,7 @@ function extractedStyleArtifacts(split, props, config, includeRuntimeBase = true
143
146
  const orderedSet = new Set(orderedIdentifiers);
144
147
  const baseViewClassName = includeRuntimeBase ? classNameWithoutCaller.split(/\s+/).filter((token) => token && !orderedSet.has(token)).join(" ") : "";
145
148
  const css = orderedIdentifiers.flatMap((identifier) => {
146
- const identifierRules = cssFromRules(Object.fromEntries(Object.entries(rules).filter(([, styleObject]) => styleObject?.[import_helpers.StyleObjectIdentifier] === identifier)));
149
+ const identifierRules = rulesByIdentifier.get(identifier) ?? [];
147
150
  return buckets.theme.includes(identifier) ? identifierRules.map((rule) => rule.replace(":root:root:root.t_", ":root:root:root:root.t_")) : identifierRules;
148
151
  });
149
152
  return {
@@ -232,7 +235,6 @@ const compilerStyleProps = /* @__PURE__ */ new Set([
232
235
  "group",
233
236
  "transition",
234
237
  "animation",
235
- "animateOnly",
236
238
  "animatePresence",
237
239
  "animatedBy",
238
240
  "fontFamily",
@@ -241,7 +243,6 @@ const compilerStyleProps = /* @__PURE__ */ new Set([
241
243
  const runtimeAnimationProps = /* @__PURE__ */ new Set([
242
244
  "transition",
243
245
  "animation",
244
- "animateOnly",
245
246
  "animatePresence",
246
247
  "animatedBy"
247
248
  ]);
@@ -514,6 +515,77 @@ const nativePointerEventProps = /* @__PURE__ */ new Set([
514
515
  "onPointerMove",
515
516
  "onPointerUp"
516
517
  ]);
518
+ const nativeShorthandFamilies = [
519
+ [
520
+ "padding",
521
+ [
522
+ "paddingTop",
523
+ "paddingRight",
524
+ "paddingBottom",
525
+ "paddingLeft"
526
+ ],
527
+ /^padding/
528
+ ],
529
+ [
530
+ "margin",
531
+ [
532
+ "marginTop",
533
+ "marginRight",
534
+ "marginBottom",
535
+ "marginLeft"
536
+ ],
537
+ /^margin/
538
+ ],
539
+ [
540
+ "borderWidth",
541
+ [
542
+ "borderTopWidth",
543
+ "borderRightWidth",
544
+ "borderBottomWidth",
545
+ "borderLeftWidth"
546
+ ],
547
+ /^border.*Width$/
548
+ ],
549
+ [
550
+ "borderColor",
551
+ [
552
+ "borderTopColor",
553
+ "borderRightColor",
554
+ "borderBottomColor",
555
+ "borderLeftColor"
556
+ ],
557
+ /^border.*Color$/
558
+ ],
559
+ [
560
+ "borderRadius",
561
+ [
562
+ "borderTopLeftRadius",
563
+ "borderTopRightRadius",
564
+ "borderBottomRightRadius",
565
+ "borderBottomLeftRadius"
566
+ ],
567
+ /^border.*Radius$/
568
+ ]
569
+ ];
570
+ function collapseNativeShorthands(style) {
571
+ if (!staticObject(style)) return style;
572
+ const keys = Object.keys(style);
573
+ const collapsed = /* @__PURE__ */ new Map();
574
+ for (const [shorthand, sides, family] of nativeShorthandFamilies) {
575
+ const value = style[sides[0]];
576
+ if (value !== void 0 && !(shorthand in style) && sides.every((side) => style[side] === value) && keys.filter((key) => family.test(key)).length === sides.length) {
577
+ for (const side of sides) collapsed.set(side, shorthand);
578
+ }
579
+ }
580
+ if (!collapsed.size) return style;
581
+ const out = {};
582
+ for (const key of keys) {
583
+ const shorthand = collapsed.get(key);
584
+ if (!shorthand) out[key] = style[key];
585
+ else if (!(shorthand in out)) out[shorthand] = style[key];
586
+ }
587
+ return out;
588
+ }
517
589
  function isSerializableNativeStyle(value) {
518
590
  if (value == null || typeof value === "number" || typeof value === "boolean") {
519
591
  return true;
@@ -525,6 +597,35 @@ function isSerializableNativeStyle(value) {
525
597
  if (prototype !== Object.prototype && prototype !== null) return false;
526
598
  return Object.values(value).every(isSerializableNativeStyle);
527
599
  }
600
+ function nativeTextMetrics(result) {
601
+ const value = result?.nativeTextMetrics;
602
+ if (!staticObject(value)) return null;
603
+ const { fontSize, lineHeight } = value;
604
+ if (fontSize !== void 0 && typeof fontSize !== "number" || lineHeight !== void 0 && typeof lineHeight !== "number" && typeof lineHeight !== "string") {
605
+ return null;
606
+ }
607
+ return fontSize === void 0 && lineHeight === void 0 ? null : value;
608
+ }
609
+ function mergeNativeTextMetrics(current, next) {
610
+ if (!current) return next;
611
+ if (!next) return current;
612
+ return {
613
+ fontSize: next.fontSize ?? current.fontSize,
614
+ lineHeight: next.lineHeight ?? current.lineHeight
615
+ };
616
+ }
617
+ function hasChildThatMayRenderReactNode(element) {
618
+ return element.entries.some((entry) => {
619
+ if (entry.kind !== "child" || entry.value.kind === "empty") return false;
620
+ if (entry.value.kind === "element") return true;
621
+ if (entry.value.kind === "bailout") return entry.value.dynamic === null;
622
+ if (entry.value.kind === "conditional") {
623
+ return (0, import_compiler_core.collectLeaves)(entry.value.tree).some(({ value }) => value === void 0 || value !== null && typeof value === "object");
624
+ }
625
+ if (entry.value.kind !== "static") return true;
626
+ return entry.value.value !== null && typeof entry.value.value === "object";
627
+ });
628
+ }
528
629
  function unusedIdentifier(source, base) {
529
630
  let candidate = base;
530
631
  let suffix = 0;
@@ -789,6 +890,7 @@ function createTamaguiCompilerHost(options) {
789
890
  };
790
891
  const configuredAnimationDriver = options.tamaguiConfig.animations;
791
892
  const configuredCssAnimationDriver = platform === "web" && configuredAnimationDriver?.outputStyle === "css" && !options.tamaguiConfig.animationDrivers ? configuredAnimationDriver : null;
893
+ const nativeTextMetricsByElement = /* @__PURE__ */ new WeakMap();
792
894
  const resolveStaticCssTransition = (value, transitionPresets) => {
793
895
  if (platform !== "web" || typeof value !== "string") return null;
794
896
  const transitionPresetNames = new Set(Object.keys(transitionPresets));
@@ -800,20 +902,19 @@ function createTamaguiCompilerHost(options) {
800
902
  for (const payload of payloads) {
801
903
  const transition = (0, import_tooling.parseTransition)(payload, transitionPresetNames);
802
904
  if (!transition.ok) return null;
803
- if (transition.value.kind === "global" || transition.value.entries.every((entry) => entry.timing.type === "css")) {
905
+ if (transition.value.kind === "global") {
804
906
  resolvedPayloads.push(payload);
805
907
  continue;
806
908
  }
807
- if (transition.value.entries.length !== 1 || transition.value.entries[0].timing.type !== "preset") {
808
- return null;
809
- }
810
- const preset = transitionPresets[transition.value.entries[0].timing.name];
811
- if (typeof preset !== "string") return null;
812
- const parsedPreset = (0, import_tooling.parseTransition)(preset);
813
- 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") {
814
- return null;
909
+ const resolved2 = (0, import_animation_helpers.resolveTransition)(payload, { animations: transitionPresets });
910
+ if (resolved2.diagnostics.length > 0) return null;
911
+ if (!resolved2.fused) {
912
+ resolvedPayloads.push(payload);
913
+ continue;
815
914
  }
816
- resolvedPayloads.push(`all ${preset}`);
915
+ const css = (0, import_animation_helpers.toCSSTransition)(resolved2);
916
+ if (css === void 0) return null;
917
+ resolvedPayloads.push(css);
817
918
  }
818
919
  let payloadIndex = 0;
819
920
  const resolved = [];
@@ -863,7 +964,6 @@ function createTamaguiCompilerHost(options) {
863
964
  const base = (textLike ? core.Text : core.View)?.staticConfig;
864
965
  if (!base) return null;
865
966
  const platformDefaults = platform === "web" ? {
866
- ...import_dom.DISPLAY_WEB_RESET[row.display],
867
967
  ...row.defaults,
868
968
  ...import_dom.TAG_WEB_DEFAULTS[tag]
869
969
  } : {
@@ -878,6 +978,7 @@ function createTamaguiCompilerHost(options) {
878
978
  displayName: tag,
879
979
  staticConfig: normalizeStaticConfig({
880
980
  ...base,
981
+ isDOM: true,
881
982
  isInput: row.backing === "textinput",
882
983
  validStyles: {
883
984
  ...import_helpers.validStyles,
@@ -941,7 +1042,7 @@ function createTamaguiCompilerHost(options) {
941
1042
  const defaultProps = resolved.staticConfig.defaultProps ?? {};
942
1043
  return {
943
1044
  key: resolved.key,
944
- canFlatten: resolved.staticConfig.acceptsClassName !== false && !resolved.staticConfig.neverFlatten && !resolved.staticConfig.context,
1045
+ canFlatten: resolved.staticConfig.acceptsClassName !== false && !resolved.staticConfig.isHOC && !resolved.staticConfig.neverFlatten && !resolved.staticConfig.context,
945
1046
  staticConfig: resolved.staticConfig,
946
1047
  displayName: resolved.displayName,
947
1048
  ...dom && { domTag: dom.tag },
@@ -958,7 +1059,6 @@ function createTamaguiCompilerHost(options) {
958
1059
  "group",
959
1060
  "transition",
960
1061
  "animation",
961
- "animateOnly",
962
1062
  "animatePresence",
963
1063
  "animatedBy",
964
1064
  "render"
@@ -973,11 +1073,20 @@ function createTamaguiCompilerHost(options) {
973
1073
  if (dynamic?.type !== "string" || !dynamic.values?.length) return null;
974
1074
  return dynamic.values.map(String);
975
1075
  };
1076
+ const nativeDynamicShape = (name, component, dynamic) => {
1077
+ if (!dynamic || !canLowerConditionalStyleProp(name, component)) return null;
1078
+ if (dynamic.values?.length) return "domain";
1079
+ if (dynamic.type === "number" && directStyleName(name, component)) return "number";
1080
+ return null;
1081
+ };
976
1082
  const conditionalClassEntry = (entry, component) => entry.value.kind === "conditional" && canLowerConditionalStyleProp(entry.name, component) || frontendClassDomain(entry, component) !== null;
1083
+ const expandStyleShorthand = (name) => options.tamaguiConfig.shorthands?.[name] ?? name;
977
1084
  const isInvalidHostStyleProp = (name, component) => {
1085
+ const expanded = expandStyleShorthand(name);
978
1086
  const staticConfig = component.staticConfig;
1087
+ if (staticConfig.inlineProps?.has(name) || staticConfig.variants?.[name]) return false;
979
1088
  const validStyles = staticConfig.validStyles || (staticConfig.isInput ? import_helpers.stylePropsInput : staticConfig.isText ? import_helpers.stylePropsText : import_helpers.validStyles);
980
- return name in import_helpers.stylePropsAll && !(0, import_web.isValidStyleKey)(name, validStyles);
1089
+ return expanded in import_helpers.stylePropsAll && !(0, import_web.isValidStyleKey)(expanded, validStyles);
981
1090
  };
982
1091
  const directStyleName = (name, component) => {
983
1092
  if (compilerStyleProps.has(name) || name === "style") {
@@ -985,7 +1094,7 @@ function createTamaguiCompilerHost(options) {
985
1094
  }
986
1095
  const staticConfig = component.staticConfig;
987
1096
  if (staticConfig.variants?.[name]) return null;
988
- const expanded = options.tamaguiConfig.shorthands?.[name] ?? name;
1097
+ const expanded = expandStyleShorthand(name);
989
1098
  return staticConfig.validStyles?.[expanded] ? expanded : null;
990
1099
  };
991
1100
  const resolveSplitStyles = (props, staticConfig, animationDriver, displayName) => {
@@ -1118,7 +1227,7 @@ function createTamaguiCompilerHost(options) {
1118
1227
  return {
1119
1228
  resolveComponent: resolve,
1120
1229
  isStyleProp,
1121
- canLowerDynamicStyleProp(name, component, valueKind) {
1230
+ canLowerDynamicStyleProp(name, component, valueKind, dynamic) {
1122
1231
  if (!options.disablePartialExtraction && valueKind === "conditional" && canLowerConditionalStyleProp(name, component)) {
1123
1232
  return true;
1124
1233
  }
@@ -1128,7 +1237,7 @@ function createTamaguiCompilerHost(options) {
1128
1237
  if (!options.disablePartialExtraction && platform === "web" && isFrontendClassName(name, component)) {
1129
1238
  return true;
1130
1239
  }
1131
- return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && directStyleName(name, component) === "opacity");
1240
+ return !options.disablePartialExtraction && (platform === "web" && !!directStyleName(name, component) || platform === "native" && (directStyleName(name, component) === "opacity" || valueKind === "bailout" && nativeDynamicShape(name, component, dynamic) !== null));
1132
1241
  },
1133
1242
  developmentDebugInstrumentation,
1134
1243
  lowerCandidate(input) {
@@ -1223,7 +1332,7 @@ function createTamaguiCompilerHost(options) {
1223
1332
  if (styleObjectStatic) props.style = styleObjectStatic;
1224
1333
  const dynamicStyleEntries = [...input.element.entries.filter((entry) => entry.kind === "prop" && (entry.value.kind === "bailout" || entry.value.kind === "conditional") && isStyleProp(entry.name, component)), ...styleMemberEntries];
1225
1334
  {
1226
- const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
1335
+ const needsRuntimeMapping = (name) => runtimeEventProps.has(name) || platform === "web" && name === "onLayout" || platform === "native" && !component.domTag && nativePointerEventProps.has(name);
1227
1336
  const directRuntimeEvent = input.element.entries.find((entry) => entry.kind === "prop" && needsRuntimeMapping(entry.name));
1228
1337
  const runtimeEvent = directRuntimeEvent?.kind === "prop" ? directRuntimeEvent.name : Object.keys(props).find(needsRuntimeMapping);
1229
1338
  if (runtimeEvent) {
@@ -1233,13 +1342,6 @@ function createTamaguiCompilerHost(options) {
1233
1342
  const animationDefaultProps = component.staticConfig.defaultProps ?? {};
1234
1343
  const animationProps = core.mergeProps(animationDefaultProps, props);
1235
1344
  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)]);
1236
- const animateOnlyEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "animateOnly");
1237
- if (animationNames.has("animateOnly")) {
1238
- return bailout(input, "local/unsupported-target", "Animated candidates remain on the runtime path", animateOnlyEntry?.span, {
1239
- rule: 5,
1240
- 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}` })
1241
- });
1242
- }
1243
1345
  const transitionEntry = input.element.entries.find((entry) => entry.kind === "prop" && entry.name === "transition");
1244
1346
  const animatedBy = typeof animationProps.animatedBy === "string" ? animationProps.animatedBy.trim() : null;
1245
1347
  const namedAnimationDriver = animatedBy === null ? null : options.tamaguiConfig.animationDrivers?.[animatedBy];
@@ -1250,7 +1352,7 @@ function createTamaguiCompilerHost(options) {
1250
1352
  props.transition = resolvedCssTransition;
1251
1353
  }
1252
1354
  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")));
1253
- const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy" && name !== "animateOnly") || animatedByNeedsRuntime;
1355
+ const runtimeAnimationRequired = animationNames.has("transition") && resolvedCssTransition === null || [...animationNames].some((name) => name !== "transition" && name !== "animatedBy") || animatedByNeedsRuntime;
1254
1356
  let dynamicHostStyleProperties = null;
1255
1357
  let laneAEntries = [];
1256
1358
  const laneAOwners = /* @__PURE__ */ new Set();
@@ -1444,7 +1546,7 @@ function createTamaguiCompilerHost(options) {
1444
1546
  message: (0, import_compiler_core.zeroRuleMessage)(5, { detail: `the animation configured on ${input.element.component.name}` })
1445
1547
  });
1446
1548
  }
1447
- 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)));
1549
+ 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) || entry.value.kind === "bailout" && nativeDynamicShape(entry.name, component, entry.value.dynamic) !== null));
1448
1550
  if (dynamicStyleEntries.length > 0 && !laneACoversAll && !supportsNativeDynamicStyles && !supportsWebConditionalClasses) {
1449
1551
  const entry = dynamicStyleEntries[0];
1450
1552
  return bailout(input, "local/dynamic-style-value", `Style prop ${entry.kind === "prop" ? entry.name : "unknown"} could not be safely extracted`, entry.span);
@@ -1539,6 +1641,21 @@ function createTamaguiCompilerHost(options) {
1539
1641
  if (!split) {
1540
1642
  return bailout(input, "local/style-resolution-failed", "getSplitStyles returned no static result");
1541
1643
  }
1644
+ const nativeMetrics = platform === "native" ? nativeTextMetrics(split) : null;
1645
+ if (nativeMetrics) nativeTextMetricsByElement.set(input.element, nativeMetrics);
1646
+ const hasDynamicFontSize = dynamicStyleEntries.some((entry) => {
1647
+ const name = directStyleName(entry.name, component);
1648
+ return name === "fontFamily" || name === "fontSize";
1649
+ });
1650
+ const hasUnresolvedNativeLineHeight = typeof nativeMetrics?.lineHeight === "number" && nativeMetrics.fontSize === void 0 && !hasDynamicFontSize;
1651
+ const hasDynamicTextMetric = dynamicStyleEntries.some((entry) => {
1652
+ const name = directStyleName(entry.name, component);
1653
+ return name === "fontFamily" || name === "fontSize" || name === "lineHeight" || name === null && !!component.staticConfig.variants?.[entry.name];
1654
+ });
1655
+ const changesInheritedNativeFontSize = nativeMetrics?.fontSize !== void 0 && nativeMetrics.lineHeight === void 0;
1656
+ if (platform === "native" && component.staticConfig.isText && !component.domTag && (hasUnresolvedNativeLineHeight || changesInheritedNativeFontSize || hasChildThatMayRenderReactNode(input.element) && (nativeMetrics !== null || hasDynamicTextMetric) || input.module.elements.some((ancestor) => ancestor !== input.element && ancestor.span.start < input.element.span.start && ancestor.span.end > input.element.span.end && nativeTextMetricsByElement.has(ancestor)))) {
1657
+ return bailout(input, "local/unsupported-target", "Native text metrics need the runtime Text provider for this subtree");
1658
+ }
1542
1659
  if (split.programLifecycleStyleKeys?.enter?.size || split.programLifecycleStyleKeys?.exit?.size) {
1543
1660
  return bailout(input, "local/unsupported-target", "Lifecycle value programs remain on the runtime path", input.element.span, {
1544
1661
  rule: 5,
@@ -1641,14 +1758,15 @@ function createTamaguiCompilerHost(options) {
1641
1758
  return bailout(input, "local/unsupported-target", "Native style output is not a static serializable value");
1642
1759
  }
1643
1760
  const nativeStyleLocal = unusedIdentifier(input.source, `__TamaguiNativeStyle${input.element.span.start}`);
1761
+ const usesNativeFastPath = !!themedStyleKeys && !!options.experimentalNativeFastPath && dynamicStyleEntries.length === 0 && !input.element.entries.some((entry) => entry.kind === "spread");
1644
1762
  const nativeStyleImports = [{
1645
1763
  content: `
1646
- function ${nativeStyleLocal}() { return ${nativeStyleLocal}._ ?? (${nativeStyleLocal}._ = ${JSON.stringify(nativeStyle ?? {})}); } ${nativeStyleLocal}();`,
1764
+ function ${nativeStyleLocal}() { return ${nativeStyleLocal}._ ?? (${nativeStyleLocal}._ = ${JSON.stringify((usesNativeFastPath ? nativeStyle : collapseNativeShorthands(nativeStyle)) ?? {})}); } ${nativeStyleLocal}();`,
1647
1765
  origin: input.element.component.span
1648
1766
  }];
1649
1767
  const nativeStyleSource = `${nativeStyleLocal}._ ?? ${nativeStyleLocal}()`;
1650
1768
  let nativeFastPath;
1651
- if (themedStyleKeys && options.experimentalNativeFastPath && dynamicStyleEntries.length === 0 && !input.element.entries.some((entry) => entry.kind === "spread")) {
1769
+ if (usesNativeFastPath) {
1652
1770
  const mappingLocal = unusedIdentifier(input.source, `__TamaguiNativeMapping${input.element.span.start}`);
1653
1771
  nativeFastPath = {
1654
1772
  mappingLocal,
@@ -1672,6 +1790,7 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
1672
1790
  }
1673
1791
  styleEntries = [.../* @__PURE__ */ new Set([...styleEntries, ...propsResult.consumed])];
1674
1792
  let nativeDOMStyleSource = nativeStyleSource;
1793
+ let nativeDOMMetrics = nativeMetrics;
1675
1794
  let runtimeStyleSource = null;
1676
1795
  if (domStyleProgram?.kind === "prop" && domStyleProgram.value.kind === "dom-style") {
1677
1796
  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))));
@@ -1692,6 +1811,7 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
1692
1811
  if (!isSerializableNativeStyle(itemStyle) || core.containsThemeRef(itemStyle)) {
1693
1812
  return bailout(input, "local/unsupported-target", "Native style() output is not serializable", item.value.span);
1694
1813
  }
1814
+ nativeDOMMetrics = mergeNativeTextMetrics(nativeDOMMetrics, nativeTextMetrics(itemSplit));
1695
1815
  value = JSON.stringify(itemStyle ?? {});
1696
1816
  }
1697
1817
  const condition = item.condition ? input.source.slice(item.condition.start, item.condition.end) : null;
@@ -1708,6 +1828,7 @@ const ${mappingLocal} = ${JSON.stringify(themedStyleKeys)};`,
1708
1828
  const propertyContent = [
1709
1829
  input.element.form === "jsx" ? `style={${nativeDOMStyleSource}}` : `style: ${nativeDOMStyleSource}`,
1710
1830
  runtimeStyleSource ? input.element.form === "jsx" ? `__styles={${runtimeStyleSource}}` : `__styles: ${runtimeStyleSource}` : "",
1831
+ nativeDOMMetrics ? serializedProps(input.element.form, [["__textMetrics", JSON.stringify(nativeDOMMetrics)]]) : "",
1711
1832
  serializedProps(input.element.form, propsResult.additions)
1712
1833
  ].filter(Boolean).join(input.element.form === "jsx" ? " " : ", ");
1713
1834
  const primitiveTagEdits = [input.element.component.span, input.element.component.closingSpan].filter((span) => !!span).map((span) => ({
@@ -1864,7 +1985,45 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
1864
1985
  const conditionalParts = [];
1865
1986
  const conditionalKeys = /* @__PURE__ */ new Set();
1866
1987
  const baseStyleForDiff = staticObject(nativeStyleResolved) ? nativeStyleResolved : {};
1988
+ const valueDiff = (entry, value, what) => {
1989
+ const { branchCompleteProps } = propsForConditional(entry, value);
1990
+ const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
1991
+ const branchStyle = branchSplit?.viewProps?.style ?? {};
1992
+ if (!staticObject(branchStyle)) {
1993
+ return `${what} did not resolve to a static native style`;
1994
+ }
1995
+ for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit?.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
1996
+ if (viewPropsKey === "style") continue;
1997
+ if (JSON.stringify(branchSplit?.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
1998
+ return `${what} changes ${viewPropsKey}, which the compiled style array cannot express`;
1999
+ }
2000
+ }
2001
+ for (const key of Object.keys(baseStyleForDiff)) {
2002
+ if (!(key in branchStyle)) {
2003
+ return `${what} removes ${key}, which an additive style array cannot express`;
2004
+ }
2005
+ }
2006
+ const diff = {};
2007
+ for (const [key, value2] of Object.entries(branchStyle)) {
2008
+ if (JSON.stringify(baseStyleForDiff[key]) !== JSON.stringify(value2)) {
2009
+ diff[key] = value2;
2010
+ }
2011
+ }
2012
+ if (!isSerializableNativeStyle(diff) || core.containsThemeRef(diff)) {
2013
+ return `${what} style is not statically representable`;
2014
+ }
2015
+ return diff;
2016
+ };
2017
+ const claimKeys = (entry, keys) => {
2018
+ for (const key of keys) {
2019
+ if (conditionalKeys.has(key)) {
2020
+ return bailout(input, "local/dynamic-style-value", `Multiple dynamic props contribute ${key}; their interaction cannot be resolved at compile time`, entry.value.span);
2021
+ }
2022
+ }
2023
+ return null;
2024
+ };
1867
2025
  for (const entry of dynamicStyleEntries) {
2026
+ const shape = entry.value.kind === "bailout" ? nativeDynamicShape(entry.name, component, entry.value.dynamic) : null;
1868
2027
  if (entry.value.kind === "conditional" && directStyleName(entry.name, component) !== "opacity") {
1869
2028
  let serializeNativeTree = function(node) {
1870
2029
  if (node.kind === "leaf") {
@@ -1879,47 +2038,54 @@ const ${fastLocal} = require('@tamagui/core')._withNativeStyle(${nativeLocal}, $
1879
2038
  const leaves = (0, import_compiler_core.collectLeaves)(tree);
1880
2039
  const leafDiffs = /* @__PURE__ */ new Map();
1881
2040
  for (const leaf of leaves) {
1882
- const { branchCompleteProps } = propsForConditional(entry, leaf.value);
1883
- const branchSplit = resolveSplitStyles(branchCompleteProps, component.staticConfig, cssAnimationDriver, component.displayName);
1884
- const branchStyle = branchSplit?.viewProps?.style ?? {};
1885
- if (!staticObject(branchStyle)) {
1886
- return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch did not resolve to a static native style`, entry.value.span);
1887
- }
1888
- for (const viewPropsKey of /* @__PURE__ */ new Set([...Object.keys(branchSplit?.viewProps ?? {}), ...Object.keys(split.viewProps ?? {})])) {
1889
- if (viewPropsKey === "style") continue;
1890
- if (JSON.stringify(branchSplit?.viewProps?.[viewPropsKey]) !== JSON.stringify(split.viewProps?.[viewPropsKey])) {
1891
- return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch changes ${viewPropsKey}, which the compiled style array cannot express`, entry.value.span);
1892
- }
1893
- }
1894
- for (const key of Object.keys(baseStyleForDiff)) {
1895
- if (!(key in branchStyle)) {
1896
- return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch removes ${key}, which an additive style array cannot express`, entry.value.span);
1897
- }
1898
- }
1899
- const diff = {};
1900
- for (const [key, value] of Object.entries(branchStyle)) {
1901
- if (JSON.stringify(baseStyleForDiff[key]) !== JSON.stringify(value)) {
1902
- diff[key] = value;
1903
- }
1904
- }
1905
- if (!isSerializableNativeStyle(diff) || core.containsThemeRef(diff)) {
1906
- return bailout(input, "local/dynamic-style-value", `Conditional ${entry.name} branch style is not statically representable`, entry.value.span);
1907
- }
1908
- for (const key of Object.keys(diff)) {
1909
- if (conditionalKeys.has(key)) {
1910
- return bailout(input, "local/dynamic-style-value", `Multiple conditionals contribute ${key}; their interaction cannot be resolved per-branch`, entry.value.span);
1911
- }
2041
+ const diff = valueDiff(entry, leaf.value, `Conditional ${entry.name} branch`);
2042
+ if (typeof diff === "string") {
2043
+ return bailout(input, "local/dynamic-style-value", diff, entry.value.span);
1912
2044
  }
2045
+ const conflict = claimKeys(entry, Object.keys(diff));
2046
+ if (conflict) return conflict;
1913
2047
  leafDiffs.set(leaf, diff);
1914
2048
  }
1915
2049
  for (const diff of leafDiffs.values()) {
1916
2050
  for (const key of Object.keys(diff)) conditionalKeys.add(key);
1917
2051
  }
1918
2052
  conditionalParts.push(serializeNativeTree(tree));
2053
+ } else if (shape === "domain" && entry.value.kind === "bailout") {
2054
+ const lookup = [];
2055
+ const keys = /* @__PURE__ */ new Set();
2056
+ for (const value of entry.value.dynamic.values) {
2057
+ const diff = valueDiff(entry, value, `${entry.name} value ${JSON.stringify(value)}`);
2058
+ if (typeof diff === "string") {
2059
+ return bailout(input, "local/dynamic-style-value", diff, entry.value.span);
2060
+ }
2061
+ for (const key of Object.keys(diff)) keys.add(key);
2062
+ lookup.push(`${JSON.stringify(String(value))}: ${JSON.stringify(diff)}`);
2063
+ }
2064
+ const conflict = claimKeys(entry, keys);
2065
+ if (conflict) return conflict;
2066
+ for (const key of keys) conditionalKeys.add(key);
2067
+ const index = expressions.length;
2068
+ expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
2069
+ conditionalParts.push(`({ ${lookup.join(", ")} })[expressions[${index}]]`);
1919
2070
  } else {
2071
+ const key = directStyleName(entry.name, component);
2072
+ if (shape === "number") {
2073
+ for (const probe of [7.25, 1031]) {
2074
+ const diff = valueDiff(entry, probe, `${entry.name} number`);
2075
+ if (typeof diff === "string" || JSON.stringify(diff) !== JSON.stringify({ [key]: probe })) {
2076
+ return bailout(input, "local/dynamic-style-value", `Style prop ${entry.name} transforms numbers on native, so its runtime value cannot pass through`, entry.value.span);
2077
+ }
2078
+ }
2079
+ if (key in baseStyleForDiff) {
2080
+ return bailout(input, "local/dynamic-style-value", `Style prop ${entry.name} overlaps a static ${key}`, entry.value.span);
2081
+ }
2082
+ const conflict = claimKeys(entry, [key]);
2083
+ if (conflict) return conflict;
2084
+ conditionalKeys.add(key);
2085
+ }
1920
2086
  const index = expressions.length;
1921
2087
  expressions.push(input.source.slice(entry.value.span.start, entry.value.span.end));
1922
- plainDynamicParts.push(`${JSON.stringify(directStyleName(entry.name, component))}: expressions[${index}]`);
2088
+ plainDynamicParts.push(`${JSON.stringify(key)}: expressions[${index}]`);
1923
2089
  }
1924
2090
  }
1925
2091
  const dynamicStyle = plainDynamicParts.join(", ");
@@ -2043,7 +2209,7 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
2043
2209
  flattened: true
2044
2210
  };
2045
2211
  }
2046
- const artifacts = extractedStyleArtifacts(split, props, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
2212
+ const artifacts = extractedStyleArtifacts(split, props, options.tamaguiConfig, true, Boolean(component.staticConfig.styleFrontend));
2047
2213
  const className = artifacts.className;
2048
2214
  const rawInlineStyle = split.viewProps?.style;
2049
2215
  const inlineStyle = staticObject(rawInlineStyle) && Object.keys(rawInlineStyle).length > 0 ? rawInlineStyle : null;
@@ -2139,7 +2305,7 @@ const ${nativeLocal} = require('react-native').${nativeExport};`,
2139
2305
  if (conflictsWithInline(changedKeys, laneAOwners, laneAMemberOwners)) {
2140
2306
  return bailout(input, "local/dynamic-style-value", `${entry.name} and an inline dynamic style both contribute a CSS property; their precedence cannot be resolved per-branch`, entry.value.span);
2141
2307
  }
2142
- const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, !component.domTag, Boolean(component.staticConfig.styleFrontend));
2308
+ const branchArtifacts = extractedStyleArtifacts(branchSplit, branchProps, options.tamaguiConfig, true, Boolean(component.staticConfig.styleFrontend));
2143
2309
  leafArtifactsMap.set(leaf, {
2144
2310
  classes: branchArtifacts.className.split(" ").filter(Boolean),
2145
2311
  css: branchArtifacts.css
@@ -22,9 +22,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
22
22
  var exports_exports = {};
23
23
  __export(exports_exports, {
24
24
  clearFormatCache: () => import_detectModuleFormat.clearFormatCache,
25
+ createTsconfigPathsMatcher: () => import_esbuildTsconfigPaths.createTsconfigPathsMatcher,
25
26
  detectModuleFormat: () => import_detectModuleFormat.detectModuleFormat,
26
27
  esbundleTamaguiConfig: () => import_bundle.esbundleTamaguiConfig,
27
- evaluateComponentModule: () => import_bundleConfig.evaluateComponentModule
28
+ evaluateComponentModule: () => import_bundleConfig.evaluateComponentModule,
29
+ generateConfigMarkdown: () => import_generateConfigMarkdown.generateConfigMarkdown
28
30
  });
29
31
  module.exports = __toCommonJS(exports_exports);
30
32
  __reExport(exports_exports, require("./checkDeps.cjs"), module.exports);
@@ -40,5 +42,7 @@ __reExport(exports_exports, require("./extractor/watchTamaguiConfig.cjs"), modul
40
42
  __reExport(exports_exports, require("./registerRequire.cjs"), module.exports);
41
43
  var import_detectModuleFormat = require("./extractor/detectModuleFormat.cjs");
42
44
  var import_bundle = require("./extractor/bundle.cjs");
45
+ var import_esbuildTsconfigPaths = require("./extractor/esbuildTsconfigPaths.cjs");
43
46
  __reExport(exports_exports, require("./getPragmaOptions.cjs"), module.exports);
44
47
  __reExport(exports_exports, require("./zero/index.cjs"), module.exports);
48
+ var import_generateConfigMarkdown = require("./extractor/generateConfigMarkdown.cjs");
@@ -70,7 +70,7 @@ const esbuildLoaderConfig = {
70
70
  };
71
71
  const dataExtensions = Object.keys(esbuildLoaderConfig).filter((k) => esbuildLoaderConfig[k] === "file" || esbuildLoaderConfig[k] === "dataurl").map((k) => k.slice(1));
72
72
  const esbuildIgnoreFilesRegex = new RegExp(`.(${dataExtensions.join("|")})$`, "i");
73
- function getESBuildConfig({ entryPoints, resolvePlatformSpecificEntries, dangerouslyIgnoreStaticEvaluationModules = [], define: callerDefine, ...options }, platform, aliases) {
73
+ function getESBuildConfig({ entryPoints, resolvePlatformSpecificEntries, dangerouslyIgnoreStaticEvaluationModules = [], define: callerDefine, conditions: callerConditions = [], ...options }, platform, aliases) {
74
74
  if (process.env.DEBUG?.startsWith("tamagui")) {
75
75
  console.info(`Building`, entryPoints);
76
76
  }
@@ -88,14 +88,16 @@ function getESBuildConfig({ entryPoints, resolvePlatformSpecificEntries, dangero
88
88
  ...platformDefines,
89
89
  ...callerDefine
90
90
  },
91
- ...platform === "native" ? {
92
- conditions: ["react-native"],
93
- mainFields: [
94
- "react-native",
95
- "module",
96
- "main"
97
- ]
98
- } : {},
91
+ conditions: [
92
+ "tamagui-compiler",
93
+ ...platform === "native" ? ["react-native"] : [],
94
+ ...callerConditions
95
+ ],
96
+ ...platform === "native" ? { mainFields: [
97
+ "react-native",
98
+ "module",
99
+ "main"
100
+ ] } : {},
99
101
  ...detectedFormat === "esm" ? {
100
102
  ...platform === "web" ? { mainFields: ["module", "main"] } : {},
101
103
  banner: { js: "import { createRequire as __cr } from \"module\"; const require = __cr(import.meta.url);" }
@@ -220,6 +222,9 @@ async function esbundleTamaguiConfig(props, platform, aliases) {
220
222
  const result = await import_esbuild.default.build({
221
223
  ...config,
222
224
  outfile: tmpFile
225
+ }).catch(async (err) => {
226
+ await import_fs_extra.default.remove(tmpFile).catch(() => {});
227
+ throw err;
223
228
  });
224
229
  await import_fs_extra.default.rename(tmpFile, props.outfile);
225
230
  return result;
@@ -335,7 +335,6 @@ async function bundleConfig(props, rebuild = false) {
335
335
  return (0, import_bundle.esbundleTamaguiConfig)({
336
336
  entryPoints: [componentModule],
337
337
  resolvePlatformSpecificEntries: props.platform !== "native" || componentModule.startsWith(".") || (0, import_node_path.isAbsolute)(componentModule),
338
- conditions: props.platform === "native" ? ["react-native"] : void 0,
339
338
  external,
340
339
  outfile: componentOutPaths[i],
341
340
  target: "node24",