styled-components-to-stylex-codemod 0.0.52 → 0.0.54

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.
@@ -1,10 +1,10 @@
1
1
  import { t as createModuleResolver } from "./resolve-imports-DgSAddIF.mjs";
2
2
  import { a as isDirectionalResult, n as mergeMarkerDeclarations, o as assertValidAdapter, r as DEFAULT_THEME_HOOK, t as transformedComponentAcceptsSx } from "./sx-surface-CEPFSTO1.mjs";
3
- import { a as findImportSource, c as resolveBarrelReExportBinding, d as UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING, l as CASCADE_CONFLICT_WARNING, n as createPrepassParser, o as getReExportedSourceName, r as fileExports, t as walkAst, u as Logger } from "./ast-walk-BOXS-DT7.mjs";
3
+ import { a as findImportSource, c as resolveBarrelReExportBinding, d as PARTIAL_MIGRATION_INCOMPLETE_WARNING, f as UNSUPPORTED_SHOULD_FORWARD_PROP_WARNING, l as CASCADE_CONFLICT_WARNING, n as createPrepassParser, o as getReExportedSourceName, r as fileExports, t as walkAst, u as Logger } from "./ast-walk-CCXrDCKY.mjs";
4
4
  import { n as resolveExistingFilePath, r as toRealPath, t as isRelativeSpecifier } from "./path-utils-BC4U8X_q.mjs";
5
- import { a as isBackgroundImageValue, c as isSingleBackgroundComponent, d as kebabToCamelCase, f as looksLikeLength, h as sanitizeIdentifier, i as getCommentBody, l as isStyleSectionMarkerComment, m as normalizeWhitespace, n as capitalize$1, o as isJSDocBlockComment, p as lowerFirst, r as escapeRegex, s as isPrettierIgnoreComment, t as camelToKebabCase, u as isValidIdentifierName } from "./string-utils-BYTEHwNg.mjs";
5
+ import { a as hasTopLevelMatch, c as isPrettierIgnoreComment, d as isValidIdentifierName, f as kebabToCamelCase, g as sanitizeIdentifier, h as normalizeWhitespace, i as getCommentBody, l as isSingleBackgroundComponent, m as lowerFirst, n as capitalize$1, o as isBackgroundImageValue, p as looksLikeLength, r as escapeRegex, s as isJSDocBlockComment, t as camelToKebabCase, u as isStyleSectionMarkerComment } from "./string-utils-Bo3cWgss.mjs";
6
6
  import { a as terminateStandaloneInterpolationStatements, i as parseStyledTemplateLiteral, n as isTemplatePlaceholderInSelectorContext, r as PLACEHOLDER_RE } from "./selector-context-heuristic-LVizWWOR.mjs";
7
- import { _ as walkForImportsAndTemplates, a as mergeComponentPropUsage, i as getExhaustiveObservedStaticValues, n as createComponentPropUsageInfo, o as readStaticJsxLiteral, r as formatObservedVariantCondition, s as collectStylexExportNames, t as KNOWN_NON_ELEMENT_PROPS, u as buildImportMapFromNodes } from "./prop-usage-SADzZJdX.mjs";
7
+ import { _ as walkForImportsAndTemplates, a as mergeComponentPropUsage, i as getExhaustiveObservedStaticValues, n as createComponentPropUsageInfo, o as readStaticJsxLiteral, r as formatObservedVariantCondition, s as collectStylexExportNames, t as KNOWN_NON_ELEMENT_PROPS, u as buildImportMapFromNodes } from "./prop-usage-DyWABApg.mjs";
8
8
  import { createRequire } from "node:module";
9
9
  import jscodeshift from "jscodeshift";
10
10
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -351,24 +351,33 @@ const UNSUPPORTED_STYLEX_CSS_PROPS = new Set([
351
351
  "all",
352
352
  "scroll-margin-block",
353
353
  "scroll-margin-block-start",
354
- "scroll-margin-block-end",
355
- "scroll-margin-inline",
356
- "scroll-margin-inline-start",
357
- "scroll-margin-inline-end",
358
- "scroll-padding-block",
359
- "scroll-padding-block-start",
360
- "scroll-padding-block-end",
361
- "scroll-padding-inline",
362
- "scroll-padding-inline-start",
363
- "scroll-padding-inline-end"
354
+ "scroll-margin-block-end"
364
355
  ]);
365
356
  /**
357
+ * Logical scroll shorthands that expand to Start/End longhands. StyleX's
358
+ * valid-styles rule accepts only the longhand forms.
359
+ */
360
+ const LOGICAL_SCROLL_AXIS_SHORTHANDS = {
361
+ "scroll-margin-inline": "scrollMarginInline",
362
+ "scroll-padding-block": "scrollPaddingBlock",
363
+ "scroll-padding-inline": "scrollPaddingInline"
364
+ };
365
+ /**
366
366
  * Returns true if the CSS property is a shorthand that StyleX cannot express directly
367
367
  * and requires expansion (e.g., `padding`, `margin`, `border`, `background`).
368
368
  */
369
369
  function isCssShorthandProperty(cssProp) {
370
370
  return cssProp in DIRECTIONAL_SHORTHAND_MAP || cssProp === "border" || /^border-(top|right|bottom|left)$/.test(cssProp) || cssProp === "background";
371
371
  }
372
+ /**
373
+ * True for the logical scroll axis shorthands (`scroll-margin-inline`,
374
+ * `scroll-padding-block`, `scroll-padding-inline`). StyleX accepts only their
375
+ * Start/End longhands, so a static value is expanded; a dynamic value cannot be
376
+ * split losslessly and must bail.
377
+ */
378
+ function isLogicalScrollAxisShorthand(cssProp) {
379
+ return cssProp.trim() in LOGICAL_SCROLL_AXIS_SHORTHANDS;
380
+ }
372
381
  function isUnsupportedStylexProperty(cssProp) {
373
382
  return UNSUPPORTED_STYLEX_CSS_PROPS.has(cssProp.trim());
374
383
  }
@@ -394,6 +403,111 @@ function resolveBackgroundStylexPropForVariants(values) {
394
403
  if (hasGradient && hasColor) return null;
395
404
  return hasGradient ? "backgroundImage" : "backgroundColor";
396
405
  }
406
+ /**
407
+ * Expands a static multi-component `background` shorthand (single layer) into
408
+ * the full set of StyleX background longhands, e.g.
409
+ * `#fff url(a.svg) no-repeat center / cover`. Components omitted from the
410
+ * shorthand are emitted at their CSS initial value (e.g. `backgroundColor:
411
+ * transparent`), reproducing the shorthand's reset semantics so the expansion
412
+ * fully overrides any background longhand inherited from a merged/extended base.
413
+ *
414
+ * Returns null when the value cannot be expanded losslessly: multiple layers
415
+ * (top-level commas), unrecognized tokens, duplicate components, or fewer than
416
+ * two explicit components (single components keep the single-longhand path).
417
+ */
418
+ function expandBackgroundShorthandComponents(rawValue) {
419
+ const value = rawValue.trim();
420
+ if (!value || hasTopLevelMatch(value, /,/)) return null;
421
+ const tokens = tokenizeBackgroundValue(value);
422
+ if (!tokens) return null;
423
+ let color;
424
+ let image;
425
+ let attachment;
426
+ const repeatTokens = [];
427
+ const positionTokens = [];
428
+ const sizeTokens = [];
429
+ const boxTokens = [];
430
+ let inSizeMode = false;
431
+ for (const token of tokens) {
432
+ if (token === "/") {
433
+ if (inSizeMode || positionTokens.length === 0) return null;
434
+ inSizeMode = true;
435
+ continue;
436
+ }
437
+ if (inSizeMode) {
438
+ if (sizeTokens.length >= 2 || !isBackgroundSizeToken(token)) return null;
439
+ sizeTokens.push(token);
440
+ continue;
441
+ }
442
+ if (token === "none" || isBackgroundImageValue(token)) {
443
+ if (image !== void 0) return null;
444
+ image = token;
445
+ continue;
446
+ }
447
+ if (isCssColorToken(token)) {
448
+ if (color !== void 0) return null;
449
+ color = token;
450
+ continue;
451
+ }
452
+ if (BACKGROUND_REPEAT_KEYWORDS.has(token)) {
453
+ if (repeatTokens.length >= 2) return null;
454
+ repeatTokens.push(token);
455
+ continue;
456
+ }
457
+ if (BACKGROUND_ATTACHMENT_KEYWORDS.has(token)) {
458
+ if (attachment !== void 0) return null;
459
+ attachment = token;
460
+ continue;
461
+ }
462
+ if (BACKGROUND_BOX_KEYWORDS.has(token)) {
463
+ if (boxTokens.length >= 2) return null;
464
+ boxTokens.push(token);
465
+ continue;
466
+ }
467
+ if (isBackgroundPositionToken(token)) {
468
+ if (positionTokens.length >= 2) return null;
469
+ positionTokens.push(token);
470
+ continue;
471
+ }
472
+ return null;
473
+ }
474
+ if (inSizeMode && sizeTokens.length === 0) return null;
475
+ if ((color !== void 0 ? 1 : 0) + (image !== void 0 ? 1 : 0) + (attachment !== void 0 ? 1 : 0) + (repeatTokens.length ? 1 : 0) + (positionTokens.length ? 1 : 0) + (sizeTokens.length ? 1 : 0) + (boxTokens.length ? 1 : 0) < 2) return null;
476
+ return [
477
+ {
478
+ prop: "backgroundColor",
479
+ value: color ?? "transparent"
480
+ },
481
+ {
482
+ prop: "backgroundImage",
483
+ value: image ?? "none"
484
+ },
485
+ {
486
+ prop: "backgroundRepeat",
487
+ value: repeatTokens.length ? repeatTokens.join(" ") : "repeat"
488
+ },
489
+ {
490
+ prop: "backgroundAttachment",
491
+ value: attachment ?? "scroll"
492
+ },
493
+ {
494
+ prop: "backgroundPosition",
495
+ value: positionTokens.length ? positionTokens.join(" ") : "0% 0%"
496
+ },
497
+ {
498
+ prop: "backgroundSize",
499
+ value: sizeTokens.length ? sizeTokens.join(" ") : "auto"
500
+ },
501
+ {
502
+ prop: "backgroundOrigin",
503
+ value: boxTokens[0] ?? "padding-box"
504
+ },
505
+ {
506
+ prop: "backgroundClip",
507
+ value: boxTokens[1] ?? boxTokens[0] ?? "border-box"
508
+ }
509
+ ];
510
+ }
397
511
  function parseInterpolatedBorderStaticParts(args) {
398
512
  const { prop, prefix, suffix } = args;
399
513
  const borderMatch = prop.match(/^border(-top|-right|-bottom|-left)?$/);
@@ -464,6 +578,28 @@ function cssDeclarationToStylexDeclarations(decl) {
464
578
  }
465
579
  }));
466
580
  }
581
+ const logicalScrollAxis = LOGICAL_SCROLL_AXIS_SHORTHANDS[prop];
582
+ if (logicalScrollAxis && decl.value.kind === "static") {
583
+ const values = splitCssValueWhitespace(decl.valueRaw.trim());
584
+ if (values.length >= 1 && values.length <= 2) {
585
+ const start = values[0];
586
+ const end = values[1] ?? start;
587
+ const withImportant = (value) => decl.important ? `${value} !important` : value;
588
+ return [{
589
+ prop: `${logicalScrollAxis}Start`,
590
+ value: {
591
+ kind: "static",
592
+ value: withImportant(start)
593
+ }
594
+ }, {
595
+ prop: `${logicalScrollAxis}End`,
596
+ value: {
597
+ kind: "static",
598
+ value: withImportant(end)
599
+ }
600
+ }];
601
+ }
602
+ }
467
603
  if (prop === "background") {
468
604
  const rawVal = (decl.valueRaw ?? "").trim();
469
605
  if (rawVal === "none") return [{
@@ -482,6 +618,22 @@ function cssDeclarationToStylexDeclarations(decl) {
482
618
  }];
483
619
  }
484
620
  if (prop === "display" && decl.value.kind === "static" && decl.valueRaw.trim() === "wrap") return [];
621
+ if (prop === "overflow" && decl.value.kind === "static") {
622
+ const tokens = decl.valueRaw.trim().split(/\s+/);
623
+ if (tokens.length === 2) return [{
624
+ prop: "overflowX",
625
+ value: {
626
+ kind: "static",
627
+ value: tokens[0]
628
+ }
629
+ }, {
630
+ prop: "overflowY",
631
+ value: {
632
+ kind: "static",
633
+ value: tokens[1]
634
+ }
635
+ }];
636
+ }
485
637
  if (prop === "animation" && decl.value.kind === "static" && decl.valueRaw.trim() === "none") return [{
486
638
  prop: "animationName",
487
639
  value: decl.value
@@ -729,6 +881,87 @@ function classifyBorderTokens(tokens) {
729
881
  color
730
882
  };
731
883
  }
884
+ const BACKGROUND_REPEAT_KEYWORDS = new Set([
885
+ "repeat",
886
+ "repeat-x",
887
+ "repeat-y",
888
+ "no-repeat",
889
+ "space",
890
+ "round"
891
+ ]);
892
+ const BACKGROUND_ATTACHMENT_KEYWORDS = new Set([
893
+ "scroll",
894
+ "fixed",
895
+ "local"
896
+ ]);
897
+ const BACKGROUND_BOX_KEYWORDS = new Set([
898
+ "border-box",
899
+ "padding-box",
900
+ "content-box"
901
+ ]);
902
+ const BACKGROUND_POSITION_KEYWORDS = new Set([
903
+ "left",
904
+ "right",
905
+ "top",
906
+ "bottom",
907
+ "center"
908
+ ]);
909
+ const CSS_COLOR_FUNCTION_RE = /^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\(/i;
910
+ const CSS_NAMED_COLORS = new Set("aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen transparent currentcolor".split(" "));
911
+ function isCssColorToken(token) {
912
+ if (token.startsWith("#")) return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(token);
913
+ if (CSS_COLOR_FUNCTION_RE.test(token)) return true;
914
+ return CSS_NAMED_COLORS.has(token.toLowerCase());
915
+ }
916
+ function isBackgroundPositionToken(token) {
917
+ return BACKGROUND_POSITION_KEYWORDS.has(token.toLowerCase()) || /^-?\d*\.?\d+(?:[a-z%]*)$/i.test(token) || /^calc\(/i.test(token);
918
+ }
919
+ function isBackgroundSizeToken(token) {
920
+ const lower = token.toLowerCase();
921
+ return lower === "cover" || lower === "contain" || lower === "auto" || /^-?\d*\.?\d+(?:[a-z%]*)$/i.test(token) || /^calc\(/i.test(token);
922
+ }
923
+ /**
924
+ * Splits a background shorthand value into top-level tokens, keeping function
925
+ * calls intact and emitting `/` (position/size separator) as its own token.
926
+ * Returns null for values containing placeholders or unbalanced parens.
927
+ */
928
+ function tokenizeBackgroundValue(value) {
929
+ if (value.includes("__SC_EXPR_")) return null;
930
+ const tokens = [];
931
+ let current = "";
932
+ let depth = 0;
933
+ const flush = () => {
934
+ if (current) {
935
+ tokens.push(current);
936
+ current = "";
937
+ }
938
+ };
939
+ for (const c of value) {
940
+ if (c === "(") {
941
+ depth++;
942
+ current += c;
943
+ continue;
944
+ }
945
+ if (c === ")") {
946
+ depth = Math.max(0, depth - 1);
947
+ current += c;
948
+ continue;
949
+ }
950
+ if (depth === 0 && /\s/.test(c)) {
951
+ flush();
952
+ continue;
953
+ }
954
+ if (depth === 0 && c === "/") {
955
+ flush();
956
+ tokens.push("/");
957
+ continue;
958
+ }
959
+ current += c;
960
+ }
961
+ if (depth !== 0) return null;
962
+ flush();
963
+ return tokens.length ? tokens : null;
964
+ }
732
965
  //#endregion
733
966
  //#region src/internal/transform-parse-expr.ts
734
967
  function parseExpr(api, exprSource) {
@@ -761,7 +994,7 @@ function createResolveAdapterSafe(args) {
761
994
  */
762
995
  const resolveValueCore = (ctx) => {
763
996
  if (bailRef.value) return;
764
- if (ctx.kind === "importedValue" && isStylexFileSource(ctx.source)) return stylexImportPassthrough(ctx.importedName, ctx.source, ctx.path);
997
+ if (ctx.kind === "importedValue" && isStylexFileSource$1(ctx.source)) return stylexImportPassthrough(ctx.importedName, ctx.source, ctx.path);
765
998
  const res = adapter.resolveValue(ctx);
766
999
  if (res === void 0 && ctx.kind !== "cssVariable") {
767
1000
  bailRef.value = true;
@@ -779,7 +1012,7 @@ function createResolveAdapterSafe(args) {
779
1012
  };
780
1013
  const resolveCallSafe = (ctx) => {
781
1014
  if (bailRef.value) return;
782
- if (isStylexFileSource(ctx.calleeSource)) return stylexImportPassthrough(ctx.calleeImportedName, ctx.calleeSource, ctx.calleeMemberPath?.join("."));
1015
+ if (isStylexFileSource$1(ctx.calleeSource)) return stylexImportPassthrough(ctx.calleeImportedName, ctx.calleeSource, ctx.calleeMemberPath?.join("."));
783
1016
  const res = adapter.resolveCall(ctx);
784
1017
  if (res === void 0) {
785
1018
  bailRef.value = true;
@@ -788,7 +1021,7 @@ function createResolveAdapterSafe(args) {
788
1021
  return res;
789
1022
  };
790
1023
  const resolveSelectorSafe = (ctx) => {
791
- if (isStylexFileSource(ctx.source)) return {
1024
+ if (isStylexFileSource$1(ctx.source)) return {
792
1025
  kind: "media",
793
1026
  ...stylexImportPassthrough(ctx.importedName, ctx.source, ctx.path)
794
1027
  };
@@ -802,10 +1035,10 @@ function createResolveAdapterSafe(args) {
802
1035
  bailRef
803
1036
  };
804
1037
  }
805
- const STYLEX_FILE_RE = /\.stylex(\.\w+)?$/;
1038
+ const STYLEX_FILE_RE$1 = /\.stylex(\.\w+)?$/;
806
1039
  /** Imports from `.stylex` files are already StyleX-compatible and need no adapter resolution. */
807
- function isStylexFileSource(source) {
808
- return STYLEX_FILE_RE.test(source.value);
1040
+ function isStylexFileSource$1(source) {
1041
+ return STYLEX_FILE_RE$1.test(source.value);
809
1042
  }
810
1043
  /** Build a passthrough result that preserves the original import reference from a `.stylex` file. */
811
1044
  function stylexImportPassthrough(importedName, source, path) {
@@ -1334,10 +1567,12 @@ function collectPatternBindingNames$2(node, names) {
1334
1567
  *
1335
1568
  * Returns null for non-literal or dynamic nodes.
1336
1569
  */
1337
- function literalToStaticValue(node) {
1570
+ function literalToStaticValue(node, options = {}) {
1338
1571
  if (!node || typeof node !== "object") return null;
1572
+ const allowCssTaggedTemplates = options.allowCssTaggedTemplates ?? true;
1573
+ const allowStaticArrowFunctions = options.allowStaticArrowFunctions ?? true;
1339
1574
  const type = node.type;
1340
- if (type === "TSAsExpression" || type === "TSSatisfiesExpression") return literalToStaticValue(node.expression);
1575
+ if (type === "TSAsExpression" || type === "TSSatisfiesExpression") return literalToStaticValue(node.expression, options);
1341
1576
  if (type === "StringLiteral") return node.value;
1342
1577
  if (type === "BooleanLiteral") return node.value;
1343
1578
  if (type === "Literal") {
@@ -1348,25 +1583,53 @@ function literalToStaticValue(node) {
1348
1583
  if (type === "UnaryExpression") {
1349
1584
  const n = node;
1350
1585
  if (n.prefix && (n.operator === "-" || n.operator === "+")) {
1351
- const argVal = literalToStaticValue(n.argument);
1586
+ const argVal = literalToStaticValue(n.argument, options);
1352
1587
  if (typeof argVal === "number") return n.operator === "-" ? -argVal : argVal;
1353
1588
  }
1354
1589
  }
1355
1590
  if (type === "TemplateLiteral") {
1356
1591
  const n = node;
1357
- if (!n.expressions || n.expressions.length === 0) return (n.quasis ?? []).map((q) => q.value?.raw ?? "").join("");
1592
+ if (!n.expressions || n.expressions.length === 0) {
1593
+ const quasis = n.quasis ?? [];
1594
+ const parts = [];
1595
+ for (const q of quasis) {
1596
+ const cooked = q.value?.cooked;
1597
+ if (cooked == null) return null;
1598
+ parts.push(cooked);
1599
+ }
1600
+ return parts.join("");
1601
+ }
1358
1602
  }
1359
- if (type === "TaggedTemplateExpression") {
1603
+ if (type === "TaggedTemplateExpression" && allowCssTaggedTemplates) {
1360
1604
  const n = node;
1361
- if (n.tag?.type === "Identifier" && n.tag.name === "css") return literalToStaticValue(n.quasi);
1605
+ if (n.tag?.type === "Identifier" && n.tag.name === "css") return literalToStaticValue(n.quasi, options);
1362
1606
  }
1363
- if (type === "ArrowFunctionExpression") {
1607
+ if (type === "ArrowFunctionExpression" && allowStaticArrowFunctions) {
1364
1608
  const n = node;
1365
- if (!n.params || n.params.length === 0) return literalToStaticValue(n.body);
1609
+ if (!n.params || n.params.length === 0) return literalToStaticValue(n.body, options);
1366
1610
  }
1367
1611
  return null;
1368
1612
  }
1369
1613
  /**
1614
+ * Extracts a static literal value from an AST node, distinguishing null literals
1615
+ * from extraction failure. Returns `undefined` when the node is not a recognized
1616
+ * static literal, and the actual value (including `null`) otherwise.
1617
+ *
1618
+ * Function expressions are not coerced by default: a function-valued expression
1619
+ * is runtime data, even if its body is a static literal.
1620
+ */
1621
+ function extractStaticLiteralValue(node, options = {}) {
1622
+ if (!node || typeof node !== "object") return;
1623
+ const typed = node;
1624
+ if (typed.type === "TSAsExpression" || typed.type === "TSSatisfiesExpression") return extractStaticLiteralValue(typed.expression, options);
1625
+ if (typed.type === "NullLiteral" || typed.type === "Literal" && typed.value === null) return null;
1626
+ const v = literalToStaticValue(node, {
1627
+ ...options,
1628
+ allowStaticArrowFunctions: options.allowStaticArrowFunctions ?? false
1629
+ });
1630
+ return v !== null ? v : void 0;
1631
+ }
1632
+ /**
1370
1633
  * Converts an AST literal node to a string value.
1371
1634
  * Returns null if the node is not a string literal.
1372
1635
  */
@@ -1741,6 +2004,11 @@ function toSuffixFromProp(propName) {
1741
2004
  return suffixes.join("");
1742
2005
  }
1743
2006
  }
2007
+ const defaultTruthyMatch = trimmed.match(/^(.+?) === undefined \|\| (.+)$/);
2008
+ if (defaultTruthyMatch) {
2009
+ const lhs = defaultTruthyMatch[1].replace(/^\$/, "");
2010
+ if (lhs === defaultTruthyMatch[2].replace(/^\$/, "")) return toSuffixFromProp(lhs);
2011
+ }
1744
2012
  if (trimmed.includes(" || ")) {
1745
2013
  const parts = trimmed.split(" || ").map((s) => s.trim()).filter(Boolean);
1746
2014
  if (parts.length) {
@@ -3498,7 +3766,7 @@ function specifierExportedName(spec) {
3498
3766
  * - Disjunction: `"a || b"` → `a || b`
3499
3767
  * - Grouped negation: `"!(a || b)"` → `!(a || b)`
3500
3768
  */
3501
- function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3769
+ function parseVariantWhenToAst(j, when, booleanProps, knownProps, nonPropRoots) {
3502
3770
  const buildMemberExpr = (raw) => {
3503
3771
  if (!raw.includes(".")) return null;
3504
3772
  const parts = raw.split(".").map((part) => part.trim()).filter(Boolean);
@@ -3533,7 +3801,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3533
3801
  }
3534
3802
  const memberExpr = buildMemberExpr(trimmedRaw);
3535
3803
  if (memberExpr) return {
3536
- propName: root && root !== "theme" && isConditionPropIdentifier(root) ? root : null,
3804
+ propName: root && root !== "theme" && !nonPropRoots?.has(root) && isConditionPropIdentifier(root) ? root : null,
3537
3805
  expr: memberExpr
3538
3806
  };
3539
3807
  return {
@@ -3542,7 +3810,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3542
3810
  };
3543
3811
  }
3544
3812
  return {
3545
- propName: trimmedRaw === "theme" || !isConditionPropIdentifier(trimmedRaw) ? null : trimmedRaw,
3813
+ propName: trimmedRaw === "theme" || nonPropRoots?.has(trimmedRaw) || !isConditionPropIdentifier(trimmedRaw) ? null : trimmedRaw,
3546
3814
  expr: j.identifier(trimmedRaw)
3547
3815
  };
3548
3816
  };
@@ -3553,7 +3821,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3553
3821
  isBoolean: true
3554
3822
  };
3555
3823
  if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
3556
- const innerParsed = parseVariantWhenToAst(j, trimmed.slice(2, -1).trim(), booleanProps, knownProps);
3824
+ const innerParsed = parseVariantWhenToAst(j, trimmed.slice(2, -1).trim(), booleanProps, knownProps, nonPropRoots);
3557
3825
  return {
3558
3826
  cond: j.unaryExpression("!", innerParsed.cond),
3559
3827
  props: innerParsed.props,
@@ -3561,7 +3829,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3561
3829
  };
3562
3830
  }
3563
3831
  if (trimmed.includes("&&")) {
3564
- const parsed = trimmed.split("&&").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps, knownProps));
3832
+ const parsed = trimmed.split("&&").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps, knownProps, nonPropRoots));
3565
3833
  const firstParsed = parsed[0];
3566
3834
  if (!firstParsed) return {
3567
3835
  cond: j.identifier("true"),
@@ -3575,7 +3843,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3575
3843
  };
3576
3844
  }
3577
3845
  if (trimmed.includes(" || ")) {
3578
- const parsed = trimmed.split(" || ").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps, knownProps));
3846
+ const parsed = trimmed.split(" || ").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps, knownProps, nonPropRoots));
3579
3847
  const firstParsedOr = parsed[0];
3580
3848
  if (!firstParsedOr) return {
3581
3849
  cond: j.identifier("true"),
@@ -3589,7 +3857,7 @@ function parseVariantWhenToAst(j, when, booleanProps, knownProps) {
3589
3857
  };
3590
3858
  }
3591
3859
  if (trimmed.startsWith("!")) {
3592
- const innerParsed = parseVariantWhenToAst(j, trimmed.slice(1).trim(), booleanProps, knownProps);
3860
+ const innerParsed = parseVariantWhenToAst(j, trimmed.slice(1).trim(), booleanProps, knownProps, nonPropRoots);
3593
3861
  return {
3594
3862
  cond: j.unaryExpression("!", innerParsed.cond),
3595
3863
  props: innerParsed.props,
@@ -3718,8 +3986,8 @@ function isConditionPropIdentifier(name, knownProps) {
3718
3986
  * function's parameter destructuring.
3719
3987
  */
3720
3988
  function collectConditionProps(j, args) {
3721
- const { when, destructureProps, booleanProps, knownProps } = args;
3722
- const parsed = parseVariantWhenToAst(j, when, booleanProps, knownProps);
3989
+ const { when, destructureProps, booleanProps, knownProps, nonPropRoots } = args;
3990
+ const parsed = parseVariantWhenToAst(j, when, booleanProps, knownProps, nonPropRoots);
3723
3991
  if (destructureProps) {
3724
3992
  for (const p of parsed.props) if (p && !destructureProps.includes(p)) destructureProps.push(p);
3725
3993
  }
@@ -4052,6 +4320,7 @@ function buildResolvedHandlerResult(result, cssProperty, payload) {
4052
4320
  type: "resolvedValue",
4053
4321
  expr: result.expr,
4054
4322
  imports: result.imports,
4323
+ cssValueText: result.expr,
4055
4324
  ...payload
4056
4325
  } : {
4057
4326
  type: "resolvedStyles",
@@ -4627,6 +4896,19 @@ function getPropertyNameFromKey(key) {
4627
4896
  * Core concepts: deep merge semantics, AST node detection, and media query resolution.
4628
4897
  */
4629
4898
  /**
4899
+ * Marks an emitted AST value node as proven to be a single CSS token (e.g. a
4900
+ * numeric stylex const that had a unit suffix). Shorthand properties holding
4901
+ * such values cannot expand to multiple tokens, so the opaque-shorthand
4902
+ * warning does not apply to them.
4903
+ */
4904
+ function markProvenSingleTokenValue(node) {
4905
+ if (node && typeof node === "object") provenSingleTokenValues.add(node);
4906
+ }
4907
+ function isProvenSingleTokenValue(node) {
4908
+ return !!node && typeof node === "object" && provenSingleTokenValues.has(node);
4909
+ }
4910
+ const provenSingleTokenValues = /* @__PURE__ */ new WeakSet();
4911
+ /**
4630
4912
  * Tries to resolve a CallExpression via the adapter's `resolveCall`.
4631
4913
  * Shared by both css-helper and process-rules slot resolution.
4632
4914
  *
@@ -5284,6 +5566,10 @@ function staticStringValue(value) {
5284
5566
  function invertWhen(when) {
5285
5567
  if (when.startsWith("!(") && when.endsWith(")")) return when.slice(2, -1);
5286
5568
  if (when.startsWith("!")) return when.slice(1);
5569
+ if (when.includes(" || ") || when.includes(" && ")) {
5570
+ if (when.includes(" || ") && when.includes(" && ")) return null;
5571
+ return `!(${when})`;
5572
+ }
5287
5573
  const match = when.match(/^(.+)\s+(===|!==)\s+(.+)$/);
5288
5574
  if (match) {
5289
5575
  const [, propName, op, rhs] = match;
@@ -5336,31 +5622,46 @@ const createPropTestHelpers = (bindings) => {
5336
5622
  }
5337
5623
  return null;
5338
5624
  };
5625
+ const applyDefaultToTruthyWhen = (whenName, propName) => {
5626
+ if (bindings.kind !== "destructured" || !bindings.defaults?.has(propName)) return whenName;
5627
+ if (whenName !== propName) return null;
5628
+ const defaultValue = literalToStaticValue(bindings.defaults.get(propName));
5629
+ if (defaultValue === null) return null;
5630
+ return defaultValue ? `${whenName} === undefined || ${whenName}` : whenName;
5631
+ };
5339
5632
  const parseTestInfo = (test) => {
5340
5633
  if (!test || typeof test !== "object") return null;
5341
5634
  if (test.type === "Identifier" && bindings.kind === "destructured") {
5342
5635
  const propAccess = readPropAccess(test);
5343
- return propAccess ? {
5344
- when: propAccess.whenName,
5636
+ if (!propAccess) return null;
5637
+ const when = applyDefaultToTruthyWhen(propAccess.whenName, propAccess.propName);
5638
+ return when === null ? null : {
5639
+ when,
5345
5640
  propName: propAccess.propName
5346
- } : null;
5641
+ };
5347
5642
  }
5348
5643
  if (isMemberExpression(test)) {
5349
5644
  const propAccess = readPropAccess(test);
5350
- return propAccess ? {
5351
- when: propAccess.whenName,
5645
+ if (!propAccess) return null;
5646
+ const when = applyDefaultToTruthyWhen(propAccess.whenName, propAccess.propName);
5647
+ return when === null ? null : {
5648
+ when,
5352
5649
  propName: propAccess.propName
5353
- } : null;
5650
+ };
5354
5651
  }
5355
5652
  if (test.type === "UnaryExpression" && test.operator === "!" && test.argument) {
5356
5653
  const propAccess = readPropAccess(test.argument);
5357
- return propAccess ? {
5358
- when: `!${propAccess.whenName}`,
5654
+ if (!propAccess) return null;
5655
+ const truthyWhen = applyDefaultToTruthyWhen(propAccess.whenName, propAccess.propName);
5656
+ if (truthyWhen === null) return null;
5657
+ return {
5658
+ when: truthyWhen === propAccess.whenName ? `!${truthyWhen}` : `!(${truthyWhen})`,
5359
5659
  propName: propAccess.propName
5360
- } : null;
5660
+ };
5361
5661
  }
5362
5662
  if (test.type === "BinaryExpression" && (test.operator === "===" || test.operator === "!==")) {
5363
5663
  const left = test.left;
5664
+ const operator = test.operator;
5364
5665
  const getRhsValue = () => {
5365
5666
  const rhsTyped = test.right;
5366
5667
  if (rhsTyped.type === "Identifier" && rhsTyped.name === "undefined") return "undefined";
@@ -5368,12 +5669,28 @@ const createPropTestHelpers = (bindings) => {
5368
5669
  if (rhs === null) return getMemberExpressionSource(test.right);
5369
5670
  return JSON.stringify(rhs);
5370
5671
  };
5672
+ const buildBinaryWhen = (propAccess, rhsValue) => {
5673
+ const base = `${propAccess.whenName} ${operator} ${rhsValue}`;
5674
+ if (bindings.kind !== "destructured" || !bindings.defaults?.has(propAccess.propName)) return base;
5675
+ if (propAccess.whenName !== propAccess.propName || rhsValue === "undefined") return null;
5676
+ const defaultValue = literalToStaticValue(bindings.defaults.get(propAccess.propName));
5677
+ if (defaultValue === null) return null;
5678
+ let rhsStatic;
5679
+ try {
5680
+ rhsStatic = JSON.parse(rhsValue);
5681
+ } catch {
5682
+ return null;
5683
+ }
5684
+ if (defaultValue !== rhsStatic) return base;
5685
+ return operator === "===" ? `${propAccess.whenName} === undefined || ${base}` : `${propAccess.whenName} !== undefined && ${base}`;
5686
+ };
5371
5687
  if (bindings.kind === "destructured" && left.type === "Identifier") {
5372
5688
  const propAccess = readPropAccess(left);
5373
5689
  const rhsValue = getRhsValue();
5374
5690
  if (!propAccess || rhsValue === null) return null;
5375
- return {
5376
- when: `${propAccess.whenName} ${test.operator} ${rhsValue}`,
5691
+ const when = buildBinaryWhen(propAccess, rhsValue);
5692
+ return when === null ? null : {
5693
+ when,
5377
5694
  propName: propAccess.propName
5378
5695
  };
5379
5696
  }
@@ -5381,8 +5698,9 @@ const createPropTestHelpers = (bindings) => {
5381
5698
  const propAccess = readPropAccess(left);
5382
5699
  const rhsValue = getRhsValue();
5383
5700
  if (!propAccess || rhsValue === null) return null;
5384
- return {
5385
- when: `${propAccess.whenName} ${test.operator} ${rhsValue}`,
5701
+ const when = buildBinaryWhen(propAccess, rhsValue);
5702
+ return when === null ? null : {
5703
+ when,
5386
5704
  propName: propAccess.propName
5387
5705
  };
5388
5706
  }
@@ -8513,10 +8831,10 @@ function collectDeclPropNames(root, j, decl, filter) {
8513
8831
  const addIfMatch = (name) => {
8514
8832
  if (filter(name)) result.add(name);
8515
8833
  };
8516
- for (const when of Object.keys(decl.variantStyleKeys ?? {})) for (const p of parseVariantWhenToAst(j, when).props) addIfMatch(p);
8834
+ for (const when of Object.keys(decl.variantStyleKeys ?? {})) for (const p of parseVariantWhenToAst(j, when, void 0, void 0, decl.nonPropConditionRoots).props) addIfMatch(p);
8517
8835
  for (const sf of decl.styleFnFromProps ?? []) {
8518
8836
  addIfMatch(sf.jsxProp);
8519
- if (sf.conditionWhen) for (const p of parseVariantWhenToAst(j, sf.conditionWhen).props) addIfMatch(p);
8837
+ if (sf.conditionWhen) for (const p of parseVariantWhenToAst(j, sf.conditionWhen, void 0, void 0, decl.nonPropConditionRoots).props) addIfMatch(p);
8520
8838
  }
8521
8839
  for (const isp of decl.inlineStyleProps ?? []) addIfMatch(isp.jsxProp ?? isp.prop);
8522
8840
  for (const cv of decl.compoundVariants ?? []) if (cv.kind === "3branch" || cv.kind === "4branch") {
@@ -12070,8 +12388,9 @@ function collectStyledDeclsImpl(args) {
12070
12388
  const key = prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "StringLiteral" ? prop.key.value : null;
12071
12389
  if (!key) continue;
12072
12390
  const v = prop.value;
12073
- if (v.type === "StringLiteral" || v.type === "NumericLiteral" || v.type === "BooleanLiteral") {
12074
- out.staticAttrs[key] = v.value;
12391
+ const literalValue = literalStaticValueFromNode(v);
12392
+ if (literalValue !== void 0) {
12393
+ out.staticAttrs[key] = literalValue;
12075
12394
  continue;
12076
12395
  }
12077
12396
  if (key === "as" && v.type === "Identifier" && v.name !== "undefined") {
@@ -13034,12 +13353,7 @@ function getAttrsParamInfo(params) {
13034
13353
  };
13035
13354
  }
13036
13355
  function literalStaticValueFromNode(node) {
13037
- if (!node || typeof node !== "object") return;
13038
- const typed = node;
13039
- if (typed.type === "StringLiteral" || typed.type === "NumericLiteral") return typeof typed.value === "string" || typeof typed.value === "number" ? typed.value : void 0;
13040
- if (typed.type === "BooleanLiteral") return typeof typed.value === "boolean" ? typed.value : void 0;
13041
- if (typed.type === "Literal" && (typeof typed.value === "string" || typeof typed.value === "number" || typeof typed.value === "boolean")) return typed.value;
13042
- if (typed.type === "TSAsExpression" || typed.type === "TSSatisfiesExpression") return literalStaticValueFromNode(typed.expression);
13356
+ return extractStaticLiteralValue(node, { allowCssTaggedTemplates: false });
13043
13357
  }
13044
13358
  function isStaticAttrExpression$1(node, attrsParamInfo) {
13045
13359
  if (!node || typeof node !== "object") return false;
@@ -14521,10 +14835,13 @@ function tryHandleAnimation(args) {
14521
14835
  for (let segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) {
14522
14836
  const tokens = segments[segmentIndex];
14523
14837
  if (!tokens.length) return false;
14524
- const m = tokens.shift().match(/^__SC_EXPR_(\d+)__$/);
14525
- if (!m) return false;
14838
+ const nameIdx = tokens.findIndex((t) => {
14839
+ const slotMatch = t.match(/^__SC_EXPR_(\d+)__$/);
14840
+ return slotMatch ? getKeyframeFromSlot(Number(slotMatch[1])) !== null : false;
14841
+ });
14842
+ if (nameIdx === -1) return false;
14843
+ const m = tokens.splice(nameIdx, 1)[0].match(/^__SC_EXPR_(\d+)__$/);
14526
14844
  const kf = getKeyframeFromSlot(Number(m[1]));
14527
- if (!kf) return false;
14528
14845
  animNames.push({
14529
14846
  kind: "ident",
14530
14847
  name: kf
@@ -17815,6 +18132,44 @@ function insertImportDeclarationNearStylex(root, decl) {
17815
18132
  insertAfterLastImport(body, decl);
17816
18133
  }
17817
18134
  //#endregion
18135
+ //#region src/internal/utilities/inline-keyframes-liveness.ts
18136
+ function pruneUnusedInlineKeyframes(args) {
18137
+ const { state, emittedStyleValues, styledDecls } = args;
18138
+ const inlineKeyframes = state.inlineKeyframes;
18139
+ if (!inlineKeyframes || inlineKeyframes.size === 0) return;
18140
+ const referenced = collectReferencedInlineKeyframes(inlineKeyframes, emittedStyleValues);
18141
+ collectReferencedTransformedVariantKeyframes(inlineKeyframes, styledDecls, referenced);
18142
+ deleteUnreferencedInlineKeyframes(state, referenced);
18143
+ }
18144
+ function collectReferencedInlineKeyframes(inlineKeyframes, values) {
18145
+ const referenced = /* @__PURE__ */ new Set();
18146
+ for (const value of values) collectReferencedInlineKeyframeNames(inlineKeyframes, value, referenced);
18147
+ return referenced;
18148
+ }
18149
+ function collectReferencedTransformedVariantKeyframes(inlineKeyframes, styledDecls, referenced) {
18150
+ for (const decl of styledDecls) {
18151
+ if (decl.skipTransform) continue;
18152
+ for (const dimension of decl.variantDimensions ?? []) collectReferencedInlineKeyframeNames(inlineKeyframes, dimension.variants, referenced);
18153
+ for (const variant of decl.staticBooleanVariants ?? []) collectReferencedInlineKeyframeNames(inlineKeyframes, variant.styles, referenced);
18154
+ for (const combined of decl.callSiteCombinedStyles ?? []) collectReferencedInlineKeyframeNames(inlineKeyframes, combined.styles, referenced);
18155
+ }
18156
+ }
18157
+ function collectReferencedInlineKeyframeNames(inlineKeyframes, value, referenced) {
18158
+ const identifiers = /* @__PURE__ */ new Set();
18159
+ collectIdentifiers(value, identifiers);
18160
+ for (const name of identifiers) if (inlineKeyframes.has(name)) referenced.add(name);
18161
+ }
18162
+ function deleteUnreferencedInlineKeyframes(state, referenced) {
18163
+ const inlineKeyframes = state.inlineKeyframes;
18164
+ if (!inlineKeyframes) return;
18165
+ for (const name of inlineKeyframes.keys()) if (!referenced.has(name)) inlineKeyframes.delete(name);
18166
+ if (!state.inlineKeyframeNameMap) return;
18167
+ for (const [cssName, jsName] of state.inlineKeyframeNameMap.entries()) if (!inlineKeyframes.has(jsName)) {
18168
+ state.inlineKeyframeNameMap.delete(cssName);
18169
+ state.keyframesNames.delete(cssName);
18170
+ }
18171
+ }
18172
+ //#endregion
17818
18173
  //#region src/internal/emit-styles.ts
17819
18174
  /**
17820
18175
  * CSS shorthands that must NEVER appear as property names in stylex.create() output.
@@ -18140,6 +18495,11 @@ function emitStylesAndImports(ctx) {
18140
18495
  stylesDecl.leadingComments = deduped;
18141
18496
  stylesDecl.comments = deduped;
18142
18497
  }
18498
+ pruneUnusedInlineKeyframes({
18499
+ state: ctx,
18500
+ emittedStyleValues: nonEmptyStyleEntries.map(([, value]) => value),
18501
+ styledDecls
18502
+ });
18143
18503
  const inlineKeyframeDecls = [];
18144
18504
  if (ctx.inlineKeyframes && ctx.inlineKeyframes.size > 0) for (const [name, frames] of ctx.inlineKeyframes) {
18145
18505
  const kfDecl = j.variableDeclaration("const", [j.variableDeclarator(j.identifier(name), j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("keyframes")), [objectToAst(j, frames)]))]);
@@ -19966,7 +20326,10 @@ function buildStaticAttrsFromRecord(j, staticAttrs, options) {
19966
20326
  }
19967
20327
  function buildStaticAttrFromValue(j, key, value, options) {
19968
20328
  const booleanTrueAsShorthand = options?.booleanTrueAsShorthand ?? true;
19969
- if (typeof value === "string") return j.jsxAttribute(j.jsxIdentifier(key), j.literal(value));
20329
+ if (typeof value === "string") {
20330
+ if (stringNeedsExpressionContainer(value)) return j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.literal(value)));
20331
+ return j.jsxAttribute(j.jsxIdentifier(key), j.literal(value));
20332
+ }
19970
20333
  if (typeof value === "boolean") return j.jsxAttribute(j.jsxIdentifier(key), value && booleanTrueAsShorthand ? null : j.jsxExpressionContainer(j.booleanLiteral(value)));
19971
20334
  if (typeof value === "number") return j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.literal(value)));
19972
20335
  if (value === void 0) return j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.identifier("undefined")));
@@ -19978,6 +20341,15 @@ function isStaticAttrExpression(value) {
19978
20341
  return !!value && typeof value === "object" && typeof value.type === "string";
19979
20342
  }
19980
20343
  /**
20344
+ * Check if a string contains characters that require escaping in a JS string literal.
20345
+ * Such strings must be emitted as JSX expression containers (`attr={"value"}`) rather
20346
+ * than direct JSX string attributes (`attr="value"`), because JSX string attributes
20347
+ * don't interpret JS escape sequences - they're literal strings.
20348
+ */
20349
+ function stringNeedsExpressionContainer(value) {
20350
+ return /[\u0000-\u001f\\]/.test(value);
20351
+ }
20352
+ /**
19981
20353
  * Build all attrs from attrsInfo in the correct order:
19982
20354
  * defaultAttrs, conditionalAttrs, invertedBoolAttrs, staticAttrs
19983
20355
  */
@@ -20459,7 +20831,7 @@ function buildVariantDimensionLookups(j, args) {
20459
20831
  }
20460
20832
  }
20461
20833
  function hasStyleSourceOrder(d) {
20462
- return !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0) || (d.pseudoAliasSelectors ?? []).some((entry) => entry.sourceOrder !== void 0);
20834
+ return !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0) || (d.pseudoAliasSelectors ?? []).some((entry) => entry.sourceOrder !== void 0) || (d.needsUseThemeHook ?? []).some((entry) => entry.sourceOrder !== void 0);
20463
20835
  }
20464
20836
  /**
20465
20837
  * Sort ordered entries by source order and append them to styleArgs.
@@ -20653,7 +21025,8 @@ function buildVariantStyleExprs(opts) {
20653
21025
  when: positiveWhen,
20654
21026
  destructureProps,
20655
21027
  booleanProps,
20656
- ...knownProps ? { knownProps } : {}
21028
+ ...knownProps ? { knownProps } : {},
21029
+ nonPropRoots: d.nonPropConditionRoots
20657
21030
  });
20658
21031
  if (onNewDestructureProp && prevLengthRef && destructureProps) for (let i = prevLengthRef.value; i < destructureProps.length; i++) onNewDestructureProp(destructureProps[i]);
20659
21032
  const isCurrentPositive = areEquivalentWhen(when, positiveWhen);
@@ -20668,7 +21041,8 @@ function buildVariantStyleExprs(opts) {
20668
21041
  when,
20669
21042
  destructureProps,
20670
21043
  booleanProps,
20671
- ...knownProps ? { knownProps } : {}
21044
+ ...knownProps ? { knownProps } : {},
21045
+ nonPropRoots: d.nonPropConditionRoots
20672
21046
  });
20673
21047
  if (onNewDestructureProp && prevLengthRef && destructureProps) for (let i = prevLengthRef.value; i < destructureProps.length; i++) onNewDestructureProp(destructureProps[i]);
20674
21048
  const styleExpr = styleRef(j, stylesIdentifier, variantKey);
@@ -20684,7 +21058,8 @@ function buildVariantStyleExprs(opts) {
20684
21058
  when,
20685
21059
  destructureProps,
20686
21060
  booleanProps,
20687
- ...knownProps ? { knownProps } : {}
21061
+ ...knownProps ? { knownProps } : {},
21062
+ nonPropRoots: d.nonPropConditionRoots
20688
21063
  });
20689
21064
  const styleExpr = styleRef(j, stylesIdentifier, variantKey);
20690
21065
  pushExpr(emitter.makeConditionalStyleExpr({
@@ -20698,7 +21073,7 @@ function buildVariantStyleExprs(opts) {
20698
21073
  * Appends conditional style args driven by theme boolean props (e.g., `theme.isDark`).
20699
21074
  * Returns `true` if the hook is needed (and calls `markNeedsUseThemeImport`).
20700
21075
  */
20701
- function appendThemeBooleanStyleArgs(hooks, styleArgs, j, stylesIdentifier, markNeedsUseThemeImport) {
21076
+ function appendThemeBooleanStyleArgs(hooks, styleArgs, j, stylesIdentifier, markNeedsUseThemeImport, orderedEntries) {
20702
21077
  if (!hooks || hooks.length === 0) return false;
20703
21078
  markNeedsUseThemeImport();
20704
21079
  for (const entry of hooks) {
@@ -20706,7 +21081,12 @@ function appendThemeBooleanStyleArgs(hooks, styleArgs, j, stylesIdentifier, mark
20706
21081
  const trueExpr = entry.trueStyleKey ? styleRef(j, stylesIdentifier, entry.trueStyleKey) : j.identifier("undefined");
20707
21082
  const falseExpr = entry.falseStyleKey ? styleRef(j, stylesIdentifier, entry.falseStyleKey) : j.identifier("undefined");
20708
21083
  const condition = entry.conditionExpr ? cloneAstNode(entry.conditionExpr) : j.memberExpression(j.identifier("theme"), j.identifier(entry.themeProp));
20709
- styleArgs.push(j.conditionalExpression(condition, trueExpr, falseExpr));
21084
+ const finalExpr = j.conditionalExpression(condition, trueExpr, falseExpr);
21085
+ if (orderedEntries && entry.sourceOrder !== void 0) orderedEntries.push({
21086
+ order: entry.sourceOrder,
21087
+ expr: finalExpr
21088
+ });
21089
+ else styleArgs.push(finalExpr);
20710
21090
  }
20711
21091
  return true;
20712
21092
  }
@@ -20791,11 +21171,12 @@ function appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier, orderedEntr
20791
21171
  * and emit-component.
20792
21172
  */
20793
21173
  function buildAllVariantAndStyleExprs(opts) {
20794
- const { d, emitter, j, stylesIdentifier, styleArgs, destructureProps, propDefaults, compoundVariantKeys, afterVariantStyleArgs, enableComplementaryMerging, buildCompoundVariantExpressions } = opts;
21174
+ const { d, emitter, j, stylesIdentifier, styleArgs, destructureProps, propDefaults, compoundVariantKeys, afterVariantStyleArgs, enableComplementaryMerging, markNeedsUseThemeImport, buildCompoundVariantExpressions } = opts;
20795
21175
  const booleanProps = collectBooleanPropNames(d);
20796
21176
  const knownProps = collectKnownConditionPropNames(emitter, d);
20797
21177
  const hasSourceOrder = hasStyleSourceOrder(d);
20798
21178
  const orderedEntries = [];
21179
+ const needsUseTheme = markNeedsUseThemeImport ? appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, markNeedsUseThemeImport, hasSourceOrder ? orderedEntries : void 0) : false;
20799
21180
  buildVariantStyleExprs({
20800
21181
  d,
20801
21182
  emitter,
@@ -20834,6 +21215,7 @@ function buildAllVariantAndStyleExprs(opts) {
20834
21215
  });
20835
21216
  mergeOrderedEntries(orderedEntries, styleArgs);
20836
21217
  if (afterVariantStyleArgs && afterVariantStyleArgs.length > 0) styleArgs.push(...afterVariantStyleArgs);
21218
+ return needsUseTheme;
20837
21219
  }
20838
21220
  /** Builds a `const theme = useTheme();` variable declaration. */
20839
21221
  function buildUseThemeDeclaration(j, themeHookLocalName) {
@@ -22725,7 +23107,7 @@ function emitComponentWrappers(emitter) {
22725
23107
  }
22726
23108
  const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => {
22727
23109
  needsUseThemeImport = true;
22728
- });
23110
+ }, hasSourceOrder ? orderedEntries : void 0);
22729
23111
  for (const gp of appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier, hasSourceOrder ? orderedEntries : void 0)) if (!destructureProps.includes(gp)) {
22730
23112
  destructureProps.push(gp);
22731
23113
  styleOnlyConditionProps.add(gp);
@@ -24437,7 +24819,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24437
24819
  }) : [];
24438
24820
  const { beforeBase: extraStyleArgs, afterBase: extraStyleArgsAfterBase, afterVariants: afterVariantStyleArgs } = emitter.buildInterleavedExtraStyleArgs(d, propsArgExprs);
24439
24821
  const styleArgs = buildInitialStyleArgs(j, stylesIdentifier, d, extraStyleArgs, extraStyleArgsAfterBase);
24440
- buildAllVariantAndStyleExprs({
24822
+ const needsUseTheme = buildAllVariantAndStyleExprs({
24441
24823
  d,
24442
24824
  emitter,
24443
24825
  j,
@@ -24447,6 +24829,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24447
24829
  propDefaults,
24448
24830
  compoundVariantKeys: collectCompoundVariantKeys(d.compoundVariants),
24449
24831
  afterVariantStyleArgs,
24832
+ markNeedsUseThemeImport: () => ctx.markNeedsUseThemeImport(),
24450
24833
  buildCompoundVariantExpressions
24451
24834
  });
24452
24835
  const isVoidTag = VOID_TAGS.has(tagName);
@@ -24470,6 +24853,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24470
24853
  dynamicAttrs: d.attrsInfo?.dynamicAttrs ?? [],
24471
24854
  staticAttrs: d.attrsInfo?.staticAttrs ?? {}
24472
24855
  });
24856
+ const destructurePropsForPattern = needsUseTheme ? destructureProps.filter((name) => name !== "theme") : destructureProps;
24473
24857
  const patternProps = emitter.buildDestructurePatternProps({
24474
24858
  baseProps: [
24475
24859
  ...allowAsProp ? [j.property.from({
@@ -24484,7 +24868,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24484
24868
  ...allowStyleProp ? [ctx.patternProp("style", styleId)] : [],
24485
24869
  ...allowSxProp ? [ctx.patternProp("sx", sxId)] : []
24486
24870
  ],
24487
- destructureProps,
24871
+ destructureProps: destructurePropsForPattern,
24488
24872
  propDefaults,
24489
24873
  includeRest: true,
24490
24874
  restId
@@ -24504,7 +24888,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24504
24888
  allowClassNameProp,
24505
24889
  allowStyleProp,
24506
24890
  allowSxProp,
24507
- inlineStyleProps: [],
24891
+ inlineStyleProps: d.inlineStyleProps ?? [],
24508
24892
  staticStyleExpr: attrsInfoWithoutForwardedAsStatic?.attrsStaticStyleExpr,
24509
24893
  staticClassNameExpr,
24510
24894
  isIntrinsicElement: false
@@ -24529,6 +24913,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
24529
24913
  childrenExpr: childrenId
24530
24914
  });
24531
24915
  const fnBodyStmts = [declStmt];
24916
+ if (needsUseTheme) fnBodyStmts.push(buildUseThemeDeclaration(j, emitter.themeHookLocalName));
24532
24917
  if (merging.sxDecl) fnBodyStmts.push(merging.sxDecl);
24533
24918
  fnBodyStmts.push(j.returnStatement(jsx));
24534
24919
  const polymorphicFnTypeParams = emitTypes && allowAsProp ? buildPolymorphicTypeParams(j, tagName) : void 0;
@@ -24569,7 +24954,8 @@ function emitShouldForwardPropWrappers(ctx) {
24569
24954
  for (const when of Object.keys(d.variantStyleKeys ?? {})) {
24570
24955
  const { props } = emitter.collectConditionProps({
24571
24956
  when,
24572
- ...knownConditionProps ? { knownProps: knownConditionProps } : {}
24957
+ ...knownConditionProps ? { knownProps: knownConditionProps } : {},
24958
+ nonPropRoots: d.nonPropConditionRoots
24573
24959
  });
24574
24960
  for (const p of props) if (p) extraProps.add(p);
24575
24961
  }
@@ -24691,12 +25077,12 @@ function emitShouldForwardPropWrappers(ctx) {
24691
25077
  const propsArgExprs = d.extraStylexPropsArgs ? emitter.buildExtraStylexPropsExprEntries({ entries: d.extraStylexPropsArgs }) : [];
24692
25078
  const { beforeBase: extraStyleArgs, afterBase: extraStyleArgsAfterBase, afterVariants: afterVariantStyleArgs } = emitter.buildInterleavedExtraStyleArgs(d, propsArgExprs);
24693
25079
  const styleArgs = buildInitialStyleArgs(j, stylesIdentifier, d, extraStyleArgs, extraStyleArgsAfterBase);
24694
- const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => ctx.markNeedsUseThemeImport());
24695
25080
  const compoundVariantKeys = collectCompoundVariantKeys(d.compoundVariants);
24696
25081
  const booleanProps = collectBooleanPropNames(d);
24697
25082
  const knownProps = collectKnownConditionPropNames(emitter, d);
24698
25083
  const hasSourceOrder = hasStyleSourceOrder(d);
24699
25084
  const orderedEntries = [];
25085
+ const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => ctx.markNeedsUseThemeImport(), hasSourceOrder ? orderedEntries : void 0);
24700
25086
  const pseudoGuardProps = appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier, hasSourceOrder ? orderedEntries : void 0);
24701
25087
  buildVariantStyleExprs({
24702
25088
  d,
@@ -24715,7 +25101,8 @@ function emitShouldForwardPropWrappers(ctx) {
24715
25101
  if (compoundVariantKeys.has(when)) continue;
24716
25102
  const { props } = emitter.collectConditionProps({
24717
25103
  when,
24718
- ...knownProps ? { knownProps } : {}
25104
+ ...knownProps ? { knownProps } : {},
25105
+ nonPropRoots: d.nonPropConditionRoots
24719
25106
  });
24720
25107
  for (const p of props) if (p && !dropProps.includes(p)) dropProps.push(p);
24721
25108
  }
@@ -24726,7 +25113,8 @@ function emitShouldForwardPropWrappers(ctx) {
24726
25113
  for (const extra of d.extraStylexPropsArgs) if (extra.when) {
24727
25114
  const { props } = emitter.collectConditionProps({
24728
25115
  when: extra.when,
24729
- ...knownProps ? { knownProps } : {}
25116
+ ...knownProps ? { knownProps } : {},
25117
+ nonPropRoots: d.nonPropConditionRoots
24730
25118
  });
24731
25119
  for (const p of props) if (p && !destructureParts.includes(p)) destructureParts.push(p);
24732
25120
  }
@@ -24760,7 +25148,8 @@ function emitShouldForwardPropWrappers(ctx) {
24760
25148
  when: p.conditionWhen,
24761
25149
  destructureProps: destructureParts,
24762
25150
  booleanProps,
24763
- ...knownProps ? { knownProps } : {}
25151
+ ...knownProps ? { knownProps } : {},
25152
+ nonPropRoots: d.nonPropConditionRoots
24764
25153
  });
24765
25154
  expr = emitter.makeConditionalStyleExpr({
24766
25155
  cond,
@@ -25059,7 +25448,8 @@ function emitSimpleWithConfigWrappers(ctx) {
25059
25448
  if (d.variantStyleKeys) for (const [when] of Object.entries(d.variantStyleKeys)) {
25060
25449
  const { props } = emitter.collectConditionProps({
25061
25450
  when,
25062
- ...knownProps ? { knownProps } : {}
25451
+ ...knownProps ? { knownProps } : {},
25452
+ nonPropRoots: d.nonPropConditionRoots
25063
25453
  });
25064
25454
  for (const p of props) if (p) variantProps.add(p);
25065
25455
  }
@@ -25073,7 +25463,8 @@ function emitSimpleWithConfigWrappers(ctx) {
25073
25463
  if (!extra.when) continue;
25074
25464
  const { props } = emitter.collectConditionProps({
25075
25465
  when: extra.when,
25076
- ...knownProps ? { knownProps } : {}
25466
+ ...knownProps ? { knownProps } : {},
25467
+ nonPropRoots: d.nonPropConditionRoots
25077
25468
  });
25078
25469
  for (const p of props) if (p) extraProps.add(p);
25079
25470
  }
@@ -25389,8 +25780,7 @@ function emitSimpleExportedIntrinsicWrappers(ctx) {
25389
25780
  }) : [];
25390
25781
  const { beforeBase: extraStyleArgs, afterBase: extraStyleArgsAfterBase, afterVariants: afterVariantStyleArgs } = emitter.buildInterleavedExtraStyleArgs(d, propsArgExprs);
25391
25782
  const styleArgs = buildInitialStyleArgs(j, stylesIdentifier, d, extraStyleArgs, extraStyleArgsAfterBase);
25392
- const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => ctx.markNeedsUseThemeImport());
25393
- buildAllVariantAndStyleExprs({
25783
+ const needsUseTheme = buildAllVariantAndStyleExprs({
25394
25784
  d,
25395
25785
  emitter,
25396
25786
  j,
@@ -25401,6 +25791,7 @@ function emitSimpleExportedIntrinsicWrappers(ctx) {
25401
25791
  compoundVariantKeys: collectCompoundVariantKeys(d.compoundVariants),
25402
25792
  afterVariantStyleArgs,
25403
25793
  enableComplementaryMerging: true,
25794
+ markNeedsUseThemeImport: () => ctx.markNeedsUseThemeImport(),
25404
25795
  buildCompoundVariantExpressions
25405
25796
  });
25406
25797
  for (const attr of d.attrsInfo?.defaultAttrs ?? []) if (destructureProps.includes(attr.jsxProp) && (typeof attr.value === "string" || typeof attr.value === "number")) propDefaults.set(attr.jsxProp, attr.value);
@@ -25668,7 +26059,7 @@ function collectPropsUsedOutsideExtraStyleConditionals(j, d, knownProps) {
25668
26059
  if (name) used.add(name);
25669
26060
  };
25670
26061
  for (const [when] of Object.entries(d.variantStyleKeys ?? {})) {
25671
- const parsed = parseVariantWhenToAst(j, when, void 0, knownProps);
26062
+ const parsed = parseVariantWhenToAst(j, when, void 0, knownProps, d.nonPropConditionRoots);
25672
26063
  for (const prop of parsed.props) add(prop);
25673
26064
  }
25674
26065
  for (const dim of d.variantDimensions ?? []) {
@@ -26348,6 +26739,485 @@ function getTransformedComponentNames(ctx) {
26348
26739
  return names && names.length > 0 ? names : void 0;
26349
26740
  }
26350
26741
  //#endregion
26742
+ //#region src/internal/transform-steps/inline-prop-conditional-css-helpers.ts
26743
+ /**
26744
+ * Inlines prop-conditional css`` helpers into consumers so their prop-dependent
26745
+ * styles are preserved. Helpers that cannot be safely inlined are left untouched
26746
+ * (their `${helper}` reference falls through to the existing mixin bail).
26747
+ */
26748
+ function inlinePropConditionalCssHelpersStep(ctx) {
26749
+ const styledDecls = ctx.styledDecls;
26750
+ const cssHelperNames = ctx.cssHelpers?.cssHelperNames;
26751
+ if (!styledDecls || !cssHelperNames || cssHelperNames.size === 0) return CONTINUE;
26752
+ const declByLocalName = /* @__PURE__ */ new Map();
26753
+ for (const decl of styledDecls) declByLocalName.set(decl.localName, decl);
26754
+ const fullyInlinedHelpers = /* @__PURE__ */ new Set();
26755
+ const retainedHelpers = /* @__PURE__ */ new Set();
26756
+ for (const consumer of styledDecls) {
26757
+ if (consumer.isCssHelper) continue;
26758
+ for (const reference of collectInlinableHelperReferences(consumer, declByLocalName)) {
26759
+ const helperDecl = reference.helperDecl;
26760
+ if (!inlinablePropDependentDeclaration(helperDecl) || inlineWouldContend(reference, consumer)) {
26761
+ retainedHelpers.add(helperDecl.localName);
26762
+ continue;
26763
+ }
26764
+ if (inlineHelperReference(consumer, reference)) {
26765
+ fullyInlinedHelpers.add(helperDecl.localName);
26766
+ ctx.markChanged();
26767
+ } else retainedHelpers.add(helperDecl.localName);
26768
+ }
26769
+ }
26770
+ for (const decl of styledDecls) {
26771
+ if (!decl.isCssHelper) continue;
26772
+ for (const rule of decl.rules) for (const declaration of rule.declarations) {
26773
+ const referencedName = referencedHelperName(declaration, decl);
26774
+ if (referencedName && declByLocalName.get(referencedName)?.isCssHelper) retainedHelpers.add(referencedName);
26775
+ }
26776
+ }
26777
+ for (const decl of styledDecls) if (decl.isCssHelper && fullyInlinedHelpers.has(decl.localName) && !retainedHelpers.has(decl.localName)) decl.rules = [];
26778
+ return CONTINUE;
26779
+ }
26780
+ /**
26781
+ * Finds property-less `${helper}` references (single-slot identifier interpolations)
26782
+ * that sit in the consumer's top-level `&` rule. Only top-level references are returned;
26783
+ * references nested under selectors/at-rules are left for the existing bail path because
26784
+ * merging a helper's own declarations under another selector is not generally safe.
26785
+ */
26786
+ function collectInlinableHelperReferences(consumer, declByLocalName) {
26787
+ const references = [];
26788
+ for (const rule of consumer.rules) {
26789
+ if (rule.selector.trim() !== "&" || rule.atRuleStack.length > 0) continue;
26790
+ for (const referenceDecl of rule.declarations) {
26791
+ const helperName = referencedHelperName(referenceDecl, consumer);
26792
+ if (!helperName) continue;
26793
+ const helperDecl = declByLocalName.get(helperName);
26794
+ if (helperDecl?.isCssHelper) references.push({
26795
+ rule,
26796
+ referenceDecl,
26797
+ helperDecl
26798
+ });
26799
+ }
26800
+ }
26801
+ return references;
26802
+ }
26803
+ /** Returns the helper identifier name if `d` is a standalone `${identifier}` interpolation. */
26804
+ function referencedHelperName(d, consumer) {
26805
+ if (d.property || d.value.kind !== "interpolated") return null;
26806
+ const parts = d.value.parts;
26807
+ if (parts.length !== 1 || parts[0]?.kind !== "slot") return null;
26808
+ const expr = consumer.templateExpressions[parts[0].slotId];
26809
+ return expr?.type === "Identifier" && typeof expr.name === "string" ? expr.name : null;
26810
+ }
26811
+ /**
26812
+ * Returns the helper's single prop-dependent declaration when the helper is structurally
26813
+ * inlinable — otherwise null. Inlinable means it carries a prop-based interpolation (the case
26814
+ * the mixin path bails on) and is shaped so its declarations can be spliced into the consumer's
26815
+ * `&` block:
26816
+ *
26817
+ * - private (not exported / preserved for cross-file use),
26818
+ * - every rule is the top-level `&` block (no nested selectors, no at-rules),
26819
+ * - no chained mixin references (a property-less `${otherMixin}` / `${parts.reset}` slot)
26820
+ * — those compose as separate style keys whose ordering we cannot preserve by splicing, and
26821
+ * - exactly one prop-dependent declaration. That single dynamic entry is the case the mixin
26822
+ * path bails on, and it has no intra-helper ordering ambiguity. Zero means a plain mixin
26823
+ * (handled by the shared-style-key path); two or more dynamic entries are emitted as
26824
+ * styleFns/variants whose precedence depends on per-declaration source order, which the
26825
+ * splice (which stamps the single reference order on every inlined declaration) cannot
26826
+ * preserve.
26827
+ *
26828
+ * Whether the inline is *override-safe* is decided per reference by `inlineWouldContend`, which
26829
+ * is independent of how the value lowers.
26830
+ */
26831
+ function inlinablePropDependentDeclaration(helperDecl) {
26832
+ if (helperDecl.isExported || helperDecl.preserveCssHelperDeclaration) return null;
26833
+ let propDependentDeclaration = null;
26834
+ let propDependentCount = 0;
26835
+ for (const rule of helperDecl.rules) {
26836
+ if (rule.selector.trim() !== "&" || rule.atRuleStack.length > 0) return null;
26837
+ for (const declaration of rule.declarations) {
26838
+ if (!declaration.property) return null;
26839
+ if (declarationReadsProps(declaration, helperDecl.templateExpressions)) {
26840
+ propDependentCount += 1;
26841
+ propDependentDeclaration = declaration;
26842
+ }
26843
+ }
26844
+ }
26845
+ return propDependentCount === 1 ? propDependentDeclaration : null;
26846
+ }
26847
+ /**
26848
+ * Splicing is override-safe only when the set of properties the helper sets is disjoint from
26849
+ * every other declaration in the merged block. When a property has a single contributor, however
26850
+ * the inlined value lowers (variant or style function) the result matches styled-components; when
26851
+ * two declarations contend, their relative precedence depends on the lowering path, which the
26852
+ * splice cannot guarantee — so bail. This checks:
26853
+ *
26854
+ * - helper-internal overlap: two helper declarations touching the same leaf (e.g.
26855
+ * `color: ${dyn}; color: red`) have order-dependent precedence the splice may invert;
26856
+ * - helper-vs-consumer overlap: any helper property (its prop-dependent one *or* a static, which
26857
+ * could override an earlier dynamic consumer declaration) overlapping a consumer declaration;
26858
+ * - any property-less consumer declaration — a sibling mixin (`${reset}`) or dynamic block whose
26859
+ * emitted properties are unknown here.
26860
+ *
26861
+ * Every consumer rule is scanned (not just the reference's), so a later top-level `&` rule or a
26862
+ * nested selector/at-rule the consumer authors is included.
26863
+ */
26864
+ function inlineWouldContend(reference, consumer) {
26865
+ const helperDeclarations = reference.helperDecl.rules.flatMap((rule) => rule.declarations);
26866
+ for (let i = 0; i < helperDeclarations.length; i += 1) for (let j = i + 1; j < helperDeclarations.length; j += 1) if (propertiesConflict(helperDeclarations[i].property, helperDeclarations[j].property)) return true;
26867
+ for (const rule of consumer.rules) for (const declaration of rule.declarations) {
26868
+ if (declaration === reference.referenceDecl) continue;
26869
+ if (!declaration.property) return true;
26870
+ if (helperDeclarations.some((hd) => propertiesConflict(hd.property, declaration.property))) return true;
26871
+ }
26872
+ return false;
26873
+ }
26874
+ /**
26875
+ * Whether two CSS properties can set a common atomic StyleX longhand — i.e. they are equal, or
26876
+ * one is a shorthand whose expansion overlaps the other. Each property is expanded to its set of
26877
+ * atomic leaf longhands (a shorthand to its leaves, a longhand to itself) and the sets are
26878
+ * intersected. This correctly distinguishes overlapping families (`borderColor` vs
26879
+ * `borderTopColor`) from disjoint ones (`borderRadius` vs `border`, `width` vs `padding`).
26880
+ *
26881
+ * Backstop for shorthands the leaf table does not model: most CSS shorthands name their longhands
26882
+ * with their own camelCase prefix (`font` → `fontVariantNumeric`, `overscrollBehavior` →
26883
+ * `overscrollBehaviorX`). When the table cannot vouch for *both* properties (one is neither a known
26884
+ * shorthand nor a known leaf), a word-prefix relationship is treated as contention so an unmodeled
26885
+ * shorthand/longhand pair conservatively bails. Fully-modeled families skip this (so `border` and
26886
+ * `borderRadius`, which share the `border` prefix but are disjoint, still inline).
26887
+ */
26888
+ function propertiesConflict(a, b) {
26889
+ const stylexA = cssPropertyToStylexProp(a);
26890
+ const stylexB = cssPropertyToStylexProp(b);
26891
+ const leavesA = leafLonghands(stylexA);
26892
+ const leavesB = leafLonghands(stylexB);
26893
+ for (const leaf of leavesA) if (leavesB.has(leaf)) return true;
26894
+ if (isModeledProperty(stylexA) && isModeledProperty(stylexB)) return false;
26895
+ return isWordPrefix(stylexA, stylexB) || isWordPrefix(stylexB, stylexA);
26896
+ }
26897
+ /** Whether the leaf table reliably classifies a StyleX property (a known shorthand or leaf). */
26898
+ function isModeledProperty(stylexProp) {
26899
+ return KNOWN_SHORTHANDS.has(stylexProp) || KNOWN_LEAVES.has(stylexProp);
26900
+ }
26901
+ /** Whether `prefix` is `full` truncated at a camelCase word boundary (`font` ⊂ `fontVariant`). */
26902
+ function isWordPrefix(prefix, full) {
26903
+ if (full.length <= prefix.length || !full.startsWith(prefix)) return false;
26904
+ const next = full[prefix.length] ?? "";
26905
+ return next !== next.toLowerCase() && next === next.toUpperCase();
26906
+ }
26907
+ /**
26908
+ * The atomic physical StyleX longhands a property can set. A shorthand expands to its leaves; a
26909
+ * longhand resolves to itself. A logical longhand resolves to *both* physical sides on its axis
26910
+ * (e.g. `marginInlineStart` → `marginLeft` and `marginRight`) because the writing direction is
26911
+ * unknown — in RTL `inline-start` is the right side — so a logical declaration conservatively
26912
+ * contends with either physical side it could map to.
26913
+ */
26914
+ function leafLonghands(stylexProp) {
26915
+ const canonical = CSS_ALIASES[stylexProp] ?? stylexProp;
26916
+ if (LOGICAL_LEAF_TO_PHYSICAL[canonical]) return new Set(LOGICAL_LEAF_TO_PHYSICAL[canonical]);
26917
+ const leaves = SHORTHAND_LEAVES[canonical] ?? LOGICAL_TO_PHYSICAL[canonical] ?? [canonical];
26918
+ return new Set(leaves.flatMap(physicalLeaves));
26919
+ }
26920
+ /**
26921
+ * Legacy CSS property aliases → their canonical StyleX property. `cssPropertyToStylexProp` only
26922
+ * camelCases authored names, so an alias and its modern name read as disjoint leaves unless
26923
+ * collapsed here. This is the standard set of legacy name aliases: `word-wrap` for `overflow-wrap`;
26924
+ * `grid-gap`/`grid-row-gap`/`grid-column-gap` for `gap`/`row-gap`/`column-gap`; and
26925
+ * `page-break-before`/`page-break-after`/`page-break-inside` for `break-before`/`break-after`/
26926
+ * `break-inside`.
26927
+ */
26928
+ const CSS_ALIASES = {
26929
+ wordWrap: "overflowWrap",
26930
+ gridGap: "gap",
26931
+ gridRowGap: "rowGap",
26932
+ gridColumnGap: "columnGap",
26933
+ pageBreakBefore: "breakBefore",
26934
+ pageBreakAfter: "breakAfter",
26935
+ pageBreakInside: "breakInside"
26936
+ };
26937
+ /**
26938
+ * Maps a logical atomic longhand to every physical longhand it could map to under any writing
26939
+ * mode and direction. Flow-relative sides are not just RTL-swapped: in vertical writing modes the
26940
+ * block axis is horizontal and the inline axis is vertical, so a logical side can land on *any*
26941
+ * physical side. The mapping is therefore the full physical family, which is conservative but safe.
26942
+ */
26943
+ function physicalLeaves(stylexProp) {
26944
+ return LOGICAL_LEAF_TO_PHYSICAL[stylexProp] ?? [stylexProp];
26945
+ }
26946
+ const PHYSICAL_SIDES = [
26947
+ "Top",
26948
+ "Right",
26949
+ "Bottom",
26950
+ "Left"
26951
+ ];
26952
+ const BORDER_KINDS = [
26953
+ "Width",
26954
+ "Style",
26955
+ "Color"
26956
+ ];
26957
+ const ALL_INSET_SIDES = [
26958
+ "top",
26959
+ "right",
26960
+ "bottom",
26961
+ "left"
26962
+ ];
26963
+ const ALL_RADIUS_CORNERS = [
26964
+ "borderTopLeftRadius",
26965
+ "borderTopRightRadius",
26966
+ "borderBottomLeftRadius",
26967
+ "borderBottomRightRadius"
26968
+ ];
26969
+ /** Logical atomic longhand → every physical longhand it could map to under any writing mode. */
26970
+ const LOGICAL_LEAF_TO_PHYSICAL = {
26971
+ inlineSize: ["width", "height"],
26972
+ blockSize: ["width", "height"],
26973
+ minInlineSize: ["minWidth", "minHeight"],
26974
+ minBlockSize: ["minWidth", "minHeight"],
26975
+ maxInlineSize: ["maxWidth", "maxHeight"],
26976
+ maxBlockSize: ["maxWidth", "maxHeight"],
26977
+ containIntrinsicInlineSize: ["containIntrinsicWidth", "containIntrinsicHeight"],
26978
+ containIntrinsicBlockSize: ["containIntrinsicWidth", "containIntrinsicHeight"],
26979
+ overflowBlock: ["overflowX", "overflowY"],
26980
+ overflowInline: ["overflowX", "overflowY"],
26981
+ overscrollBehaviorBlock: ["overscrollBehaviorX", "overscrollBehaviorY"],
26982
+ overscrollBehaviorInline: ["overscrollBehaviorX", "overscrollBehaviorY"],
26983
+ borderStartStartRadius: ALL_RADIUS_CORNERS,
26984
+ borderStartEndRadius: ALL_RADIUS_CORNERS,
26985
+ borderEndStartRadius: ALL_RADIUS_CORNERS,
26986
+ borderEndEndRadius: ALL_RADIUS_CORNERS
26987
+ };
26988
+ for (const axis of ["Block", "Inline"]) for (const end of ["Start", "End"]) {
26989
+ for (const base of [
26990
+ "margin",
26991
+ "padding",
26992
+ "scrollMargin",
26993
+ "scrollPadding"
26994
+ ]) LOGICAL_LEAF_TO_PHYSICAL[`${base}${axis}${end}`] = PHYSICAL_SIDES.map((side) => `${base}${side}`);
26995
+ LOGICAL_LEAF_TO_PHYSICAL[`inset${axis}${end}`] = ALL_INSET_SIDES;
26996
+ for (const kind of BORDER_KINDS) LOGICAL_LEAF_TO_PHYSICAL[`border${axis}${end}${kind}`] = PHYSICAL_SIDES.map((side) => `border${side}${kind}`);
26997
+ }
26998
+ /**
26999
+ * StyleX shorthand → its atomic leaf longhands (in physical form). Used to decide whether two
27000
+ * declarations contend for the same property. Mid-level shorthands (`borderTop`, `borderColor`,
27001
+ * `borderBlock`) are included so intersection captures partial overlap (e.g. `border` vs
27002
+ * `borderTopColor`). Directional families (margin/padding/inset/border) are generated for both
27003
+ * their physical and logical names; logical leaves are normalized to physical via `toPhysicalLeaf`.
27004
+ */
27005
+ const SHORTHAND_LEAVES = {
27006
+ gap: ["rowGap", "columnGap"],
27007
+ overflow: ["overflowX", "overflowY"],
27008
+ overscrollBehavior: ["overscrollBehaviorX", "overscrollBehaviorY"],
27009
+ containIntrinsicSize: ["containIntrinsicWidth", "containIntrinsicHeight"],
27010
+ textEmphasis: ["textEmphasisStyle", "textEmphasisColor"],
27011
+ mask: [
27012
+ "maskImage",
27013
+ "maskMode",
27014
+ "maskRepeat",
27015
+ "maskPosition",
27016
+ "maskClip",
27017
+ "maskOrigin",
27018
+ "maskSize",
27019
+ "maskComposite"
27020
+ ],
27021
+ offset: [
27022
+ "offsetPath",
27023
+ "offsetDistance",
27024
+ "offsetRotate",
27025
+ "offsetAnchor",
27026
+ "offsetPosition"
27027
+ ],
27028
+ borderRadius: [
27029
+ "borderTopLeftRadius",
27030
+ "borderTopRightRadius",
27031
+ "borderBottomRightRadius",
27032
+ "borderBottomLeftRadius"
27033
+ ],
27034
+ borderImage: [
27035
+ "borderImageSource",
27036
+ "borderImageSlice",
27037
+ "borderImageWidth",
27038
+ "borderImageOutset",
27039
+ "borderImageRepeat"
27040
+ ],
27041
+ outline: [
27042
+ "outlineWidth",
27043
+ "outlineStyle",
27044
+ "outlineColor"
27045
+ ],
27046
+ font: [
27047
+ "fontStyle",
27048
+ "fontVariant",
27049
+ "fontWeight",
27050
+ "fontStretch",
27051
+ "fontSize",
27052
+ "lineHeight",
27053
+ "fontFamily"
27054
+ ],
27055
+ background: [
27056
+ "backgroundColor",
27057
+ "backgroundImage",
27058
+ "backgroundPositionX",
27059
+ "backgroundPositionY",
27060
+ "backgroundSize",
27061
+ "backgroundRepeat",
27062
+ "backgroundOrigin",
27063
+ "backgroundClip",
27064
+ "backgroundAttachment"
27065
+ ],
27066
+ backgroundPosition: ["backgroundPositionX", "backgroundPositionY"],
27067
+ flex: [
27068
+ "flexGrow",
27069
+ "flexShrink",
27070
+ "flexBasis"
27071
+ ],
27072
+ flexFlow: ["flexDirection", "flexWrap"],
27073
+ placeItems: ["alignItems", "justifyItems"],
27074
+ placeContent: ["alignContent", "justifyContent"],
27075
+ placeSelf: ["alignSelf", "justifySelf"],
27076
+ gridArea: [
27077
+ "gridRowStart",
27078
+ "gridColumnStart",
27079
+ "gridRowEnd",
27080
+ "gridColumnEnd"
27081
+ ],
27082
+ gridColumn: ["gridColumnStart", "gridColumnEnd"],
27083
+ gridRow: ["gridRowStart", "gridRowEnd"],
27084
+ gridTemplate: [
27085
+ "gridTemplateRows",
27086
+ "gridTemplateColumns",
27087
+ "gridTemplateAreas"
27088
+ ],
27089
+ grid: [
27090
+ "gridTemplateRows",
27091
+ "gridTemplateColumns",
27092
+ "gridTemplateAreas",
27093
+ "gridAutoRows",
27094
+ "gridAutoColumns",
27095
+ "gridAutoFlow"
27096
+ ],
27097
+ columns: ["columnWidth", "columnCount"],
27098
+ columnRule: [
27099
+ "columnRuleWidth",
27100
+ "columnRuleStyle",
27101
+ "columnRuleColor"
27102
+ ],
27103
+ transition: [
27104
+ "transitionProperty",
27105
+ "transitionDuration",
27106
+ "transitionTimingFunction",
27107
+ "transitionDelay"
27108
+ ],
27109
+ animation: [
27110
+ "animationName",
27111
+ "animationDuration",
27112
+ "animationTimingFunction",
27113
+ "animationDelay",
27114
+ "animationIterationCount",
27115
+ "animationDirection",
27116
+ "animationFillMode",
27117
+ "animationPlayState"
27118
+ ],
27119
+ textDecoration: [
27120
+ "textDecorationLine",
27121
+ "textDecorationStyle",
27122
+ "textDecorationColor",
27123
+ "textDecorationThickness"
27124
+ ],
27125
+ whiteSpace: ["whiteSpaceCollapse", "textWrapMode"],
27126
+ textWrap: ["textWrapMode", "textWrapStyle"],
27127
+ listStyle: [
27128
+ "listStyleType",
27129
+ "listStylePosition",
27130
+ "listStyleImage"
27131
+ ]
27132
+ };
27133
+ const borderLeaf = (side, kind) => `border${side}${kind}`;
27134
+ const ALL_BORDER_LEAVES = PHYSICAL_SIDES.flatMap((side) => BORDER_KINDS.map((kind) => borderLeaf(side, kind)));
27135
+ for (const base of [
27136
+ "margin",
27137
+ "padding",
27138
+ "scrollMargin",
27139
+ "scrollPadding"
27140
+ ]) {
27141
+ const allSides = PHYSICAL_SIDES.map((side) => `${base}${side}`);
27142
+ SHORTHAND_LEAVES[base] = allSides;
27143
+ SHORTHAND_LEAVES[`${base}Block`] = allSides;
27144
+ SHORTHAND_LEAVES[`${base}Inline`] = allSides;
27145
+ }
27146
+ SHORTHAND_LEAVES.inset = ALL_INSET_SIDES;
27147
+ SHORTHAND_LEAVES.insetBlock = ALL_INSET_SIDES;
27148
+ SHORTHAND_LEAVES.insetInline = ALL_INSET_SIDES;
27149
+ SHORTHAND_LEAVES.border = [...ALL_BORDER_LEAVES, ...SHORTHAND_LEAVES.borderImage];
27150
+ SHORTHAND_LEAVES.borderBlock = ALL_BORDER_LEAVES;
27151
+ SHORTHAND_LEAVES.borderInline = ALL_BORDER_LEAVES;
27152
+ for (const side of PHYSICAL_SIDES) SHORTHAND_LEAVES[`border${side}`] = BORDER_KINDS.map((kind) => borderLeaf(side, kind));
27153
+ for (const kind of BORDER_KINDS) {
27154
+ const allOfKind = PHYSICAL_SIDES.map((side) => borderLeaf(side, kind));
27155
+ SHORTHAND_LEAVES[`border${kind}`] = allOfKind;
27156
+ SHORTHAND_LEAVES[`borderBlock${kind}`] = allOfKind;
27157
+ SHORTHAND_LEAVES[`borderInline${kind}`] = allOfKind;
27158
+ }
27159
+ for (const axis of ["Block", "Inline"]) for (const end of ["Start", "End"]) SHORTHAND_LEAVES[`border${axis}${end}`] = ALL_BORDER_LEAVES;
27160
+ const KNOWN_SHORTHANDS = new Set(Object.keys(SHORTHAND_LEAVES));
27161
+ const KNOWN_LEAVES = /* @__PURE__ */ new Set();
27162
+ for (const leaves of Object.values(SHORTHAND_LEAVES)) for (const leaf of leaves) KNOWN_LEAVES.add(leaf);
27163
+ for (const leaves of Object.values(LOGICAL_LEAF_TO_PHYSICAL)) for (const leaf of leaves) KNOWN_LEAVES.add(leaf);
27164
+ /** True when a declaration's interpolated value reads a non-theme component prop. */
27165
+ function declarationReadsProps(declaration, templateExpressions) {
27166
+ if (declaration.value.kind !== "interpolated") return false;
27167
+ for (const part of declaration.value.parts) if (part.kind === "slot" && expressionReadsNonThemeProps(templateExpressions[part.slotId])) return true;
27168
+ return false;
27169
+ }
27170
+ /** Mirrors the mixin-bail detection: an arrow/function interpolation that reads non-theme props. */
27171
+ function expressionReadsNonThemeProps(expr) {
27172
+ const node = expr;
27173
+ if (!node || node.type !== "ArrowFunctionExpression" && node.type !== "FunctionExpression") return false;
27174
+ const propsUsed = new Set([...collectPropsFromArrowFn(node), ...collectPropsFromArrowFnDestructured(node)]);
27175
+ propsUsed.delete("theme");
27176
+ return propsUsed.size > 0;
27177
+ }
27178
+ /**
27179
+ * Splices the helper's `&`-block declarations into the consumer at the reference site,
27180
+ * remapping the helper's interpolation slots onto freshly-appended consumer template
27181
+ * expressions. Returns false (without mutating) when the reference is no longer present.
27182
+ */
27183
+ function inlineHelperReference(consumer, reference) {
27184
+ const { rule, referenceDecl, helperDecl } = reference;
27185
+ const declIndex = rule.declarations.indexOf(referenceDecl);
27186
+ if (declIndex === -1) return false;
27187
+ const slotOffset = consumer.templateExpressions.length;
27188
+ const inheritedSourceOrder = referenceDecl.sourceOrder;
27189
+ const inlinedDecls = helperDecl.rules.flatMap((helperRule) => helperRule.declarations.map((d) => remapDeclaration(d, slotOffset, inheritedSourceOrder)));
27190
+ for (const expr of helperDecl.templateExpressions) consumer.templateExpressions.push(cloneAstNode(expr));
27191
+ rule.declarations.splice(declIndex, 1, ...inlinedDecls);
27192
+ return true;
27193
+ }
27194
+ /** Deep-clones a CSS declaration, offsetting every interpolation slot id by `slotOffset`. */
27195
+ function remapDeclaration(d, slotOffset, sourceOrder) {
27196
+ const value = d.value.kind === "interpolated" ? {
27197
+ kind: "interpolated",
27198
+ parts: d.value.parts.map((part) => part.kind === "slot" ? {
27199
+ kind: "slot",
27200
+ slotId: part.slotId + slotOffset
27201
+ } : {
27202
+ kind: "static",
27203
+ value: part.value
27204
+ })
27205
+ } : {
27206
+ kind: "static",
27207
+ value: d.value.value
27208
+ };
27209
+ return {
27210
+ ...d,
27211
+ value,
27212
+ valueRaw: offsetPlaceholders(d.valueRaw, slotOffset),
27213
+ sourceOrder
27214
+ };
27215
+ }
27216
+ /** Rewrites `__SC_EXPR_<n>__` placeholders in a raw value string by adding `slotOffset`. */
27217
+ function offsetPlaceholders(valueRaw, slotOffset) {
27218
+ return valueRaw.replace(/__SC_EXPR_(\d+)__/g, (_, n) => `__SC_EXPR_${Number(n) + slotOffset}__`);
27219
+ }
27220
+ //#endregion
26351
27221
  //#region src/internal/lower-rules/slot-utils.ts
26352
27222
  /**
26353
27223
  * Locate the slot interpolation in a `${...}` value and return its
@@ -26772,8 +27642,45 @@ function tryResolveConditionalValue(node, ctx) {
26772
27642
  const buildRuntimeCallResult = () => runtimeCallState.info ? {
26773
27643
  type: "runtimeCallOnly",
26774
27644
  resolveCallContext: runtimeCallState.info.resolveCallContext,
26775
- resolveCallResult: runtimeCallState.info.resolveCallResult
27645
+ resolveCallResult: runtimeCallState.info.resolveCallResult,
27646
+ ...runtimeCallState.info.cssValueText ? { cssValueText: runtimeCallState.info.cssValueText } : {}
26776
27647
  } : null;
27648
+ const markAsRuntimeCall = (call) => {
27649
+ runtimeCallState.info = {
27650
+ resolveCallContext: {
27651
+ callSiteFilePath: ctx.filePath,
27652
+ calleeImportedName: "<local>",
27653
+ calleeSource: {
27654
+ kind: "specifier",
27655
+ value: ctx.filePath
27656
+ },
27657
+ args: [],
27658
+ ...call.loc?.start ? { loc: {
27659
+ line: call.loc.start.line,
27660
+ column: call.loc.start.column
27661
+ } } : {}
27662
+ },
27663
+ resolveCallResult: { preserveRuntimeCall: true }
27664
+ };
27665
+ };
27666
+ const markFirstRuntimeCallInBranch = (branch) => {
27667
+ const pending = [branch];
27668
+ const seen = /* @__PURE__ */ new Set();
27669
+ while (pending.length > 0) {
27670
+ const current = pending.pop();
27671
+ if (!current || typeof current !== "object" || seen.has(current)) continue;
27672
+ seen.add(current);
27673
+ if (isCallExpressionNode(current)) {
27674
+ markAsRuntimeCall(current);
27675
+ return;
27676
+ }
27677
+ const node = current;
27678
+ if (node.type === "BinaryExpression" || node.type === "LogicalExpression") pending.push(node.left, node.right);
27679
+ else if (node.type === "TemplateLiteral") pending.push(...node.expressions ?? []);
27680
+ else if (node.type === "ConditionalExpression") pending.push(node.test, node.consequent, node.alternate);
27681
+ else if (node.expression) pending.push(node.expression);
27682
+ }
27683
+ };
26777
27684
  const body = getFunctionBodyExpr(expr);
26778
27685
  if (!body || body.type !== "ConditionalExpression") return null;
26779
27686
  const checkThemeBooleanTest = (test) => {
@@ -26820,93 +27727,41 @@ function tryResolveConditionalValue(node, ctx) {
26820
27727
  }
26821
27728
  return null;
26822
27729
  };
26823
- const resolveThemeBranchValue = (branch) => {
26824
- const themeInfo = resolveThemeFromMemberExpr(branch);
26825
- if (!themeInfo) return null;
26826
- const res = (ctx.resolveValueOptional ?? ctx.resolveValue)({
26827
- kind: "theme",
26828
- path: themeInfo.path,
26829
- filePath: ctx.filePath,
26830
- loc: getNodeLocStart(branch) ?? void 0
26831
- });
26832
- if (!res) return null;
26833
- const astNode = parseExpr(ctx.api, res.expr);
26834
- if (!astNode) return null;
26835
- return {
26836
- astNode,
26837
- imports: res.imports
26838
- };
26839
- };
26840
- const themeBoolInfo = checkThemeBooleanTest(body.test);
26841
- if (themeBoolInfo && node.css.property) {
26842
- const { consequent, alternate } = body;
26843
- const trueBranch = themeBoolInfo.isNegated ? alternate : consequent;
26844
- const falseBranch = themeBoolInfo.isNegated ? consequent : alternate;
26845
- const trueRaw = literalToStaticValue(trueBranch);
26846
- const falseRaw = literalToStaticValue(falseBranch);
26847
- let trueValue = trueRaw !== null && typeof trueRaw !== "boolean" ? trueRaw : null;
26848
- let falseValue = falseRaw !== null && typeof falseRaw !== "boolean" ? falseRaw : null;
26849
- const trueImports = [];
26850
- const falseImports = [];
26851
- if (trueValue === null) {
26852
- const resolved = resolveThemeBranchValue(trueBranch);
26853
- if (resolved) {
26854
- trueValue = resolved.astNode;
26855
- trueImports.push(...resolved.imports);
26856
- }
26857
- }
26858
- if (falseValue === null) {
26859
- const resolved = resolveThemeBranchValue(falseBranch);
26860
- if (resolved) {
26861
- falseValue = resolved.astNode;
26862
- falseImports.push(...resolved.imports);
26863
- }
26864
- }
26865
- if (trueValue !== null && falseValue !== null) return {
26866
- type: "splitThemeBooleanVariants",
26867
- cssProp: node.css.property,
26868
- themeProp: themeBoolInfo.themeProp,
26869
- trueValue,
26870
- falseValue,
26871
- trueImports,
26872
- falseImports
26873
- };
26874
- const inlineStyleFallback = tryBuildThemeBooleanInlineStyleFallback({
26875
- trueValue,
26876
- falseValue,
26877
- trueImports,
26878
- falseImports,
26879
- trueBranch,
26880
- falseBranch,
26881
- themeBoolInfo,
26882
- cssProp: node.css.property,
26883
- paramName,
26884
- info
26885
- });
26886
- if (inlineStyleFallback) return inlineStyleFallback;
26887
- }
26888
27730
  const expectedUsage = node.css.property ? "create" : "props";
26889
- const branchToExpr = (b) => {
27731
+ const branchToExpr = (b, mode = "default") => {
27732
+ const resolveValue = mode === "optional" ? ctx.resolveValueOptional ?? ctx.resolveValue : ctx.resolveValue;
27733
+ const resolverCtx = mode === "optional" ? {
27734
+ ...ctx,
27735
+ resolveValue,
27736
+ resolveCall: ctx.resolveCallOptional ?? ctx.resolveCall
27737
+ } : ctx;
26890
27738
  const v = literalToStaticValue(b);
26891
27739
  if (v !== null) {
26892
27740
  if (typeof v === "boolean") return null;
26893
27741
  return {
26894
27742
  usage: "create",
26895
27743
  expr: typeof v === "string" ? JSON.stringify(v) : String(v),
26896
- imports: []
27744
+ imports: [],
27745
+ ...typeof v === "string" ? { cssValueText: v } : {}
26897
27746
  };
26898
27747
  }
26899
27748
  if (!b || typeof b !== "object") return null;
26900
27749
  if (b.type === "BinaryExpression") {
26901
27750
  const binary = b;
26902
27751
  if (isCssCalcOperator$1(binary.operator)) {
26903
- const left = branchToExpr(binary.left);
26904
- const right = branchToExpr(binary.right);
26905
- if (left && right && left.usage === expectedUsage && right.usage === expectedUsage && (left.imports.length > 0 || right.imports.length > 0) && isCssCalcSafeOperand(left) && isCssCalcSafeOperand(right)) return {
26906
- usage: expectedUsage,
26907
- expr: buildCssCalcExprSource(left, binary.operator, right),
26908
- imports: [...left.imports, ...right.imports]
26909
- };
27752
+ const left = branchToExpr(binary.left, mode);
27753
+ const right = branchToExpr(binary.right, mode);
27754
+ if (left && right && left.usage === expectedUsage && right.usage === expectedUsage && (left.imports.length > 0 || right.imports.length > 0) && isCssCalcSafeOperand(left) && isCssCalcSafeOperand(right)) {
27755
+ if (left.dynamicArgUsage || right.dynamicArgUsage) {
27756
+ markFirstRuntimeCallInBranch(left.dynamicArgUsage ? binary.left : binary.right);
27757
+ return null;
27758
+ }
27759
+ return {
27760
+ usage: expectedUsage,
27761
+ expr: buildCssCalcExprSource(left, binary.operator, right),
27762
+ imports: [...left.imports, ...right.imports]
27763
+ };
27764
+ }
26910
27765
  }
26911
27766
  }
26912
27767
  const callHasThemeArg = (call) => (call.arguments ?? []).some((arg) => {
@@ -26921,28 +27776,17 @@ function tryResolveConditionalValue(node, ctx) {
26921
27776
  }
26922
27777
  return false;
26923
27778
  });
26924
- const markAsRuntimeCall = (call) => {
26925
- runtimeCallState.info = {
26926
- resolveCallContext: {
26927
- callSiteFilePath: ctx.filePath,
26928
- calleeImportedName: "<local>",
26929
- calleeSource: {
26930
- kind: "specifier",
26931
- value: ctx.filePath
26932
- },
26933
- args: [],
26934
- ...call.loc?.start ? { loc: {
26935
- line: call.loc.start.line,
26936
- column: call.loc.start.column
26937
- } } : {}
26938
- },
26939
- resolveCallResult: { preserveRuntimeCall: true }
26940
- };
26941
- };
26942
27779
  const resolveCallExpr = (call, cssProperty) => {
26943
- const res = resolveImportedHelperCall(call, ctx, propsParamName, cssProperty, themeBindingName);
27780
+ const res = resolveImportedHelperCall(call, resolverCtx, propsParamName, cssProperty, themeBindingName);
26944
27781
  if (res.kind === "resolved") {
26945
- if ("expr" in res.result) return res.result;
27782
+ if ("expr" in res.result) {
27783
+ if ("preserveRuntimeCall" in res.result && res.result.preserveRuntimeCall) runtimeCallState.info = {
27784
+ resolveCallContext: res.resolveCallContext,
27785
+ resolveCallResult: res.resolveCallResult,
27786
+ cssValueText: res.result.expr
27787
+ };
27788
+ return res.result;
27789
+ }
26946
27790
  if ("preserveRuntimeCall" in res.result && res.result.preserveRuntimeCall) {
26947
27791
  runtimeCallState.info = {
26948
27792
  resolveCallContext: res.resolveCallContext,
@@ -26954,10 +27798,17 @@ function tryResolveConditionalValue(node, ctx) {
26954
27798
  if (isCallExpressionNode(call.callee)) {
26955
27799
  const inner = call.callee;
26956
27800
  const outerArgs = call.arguments ?? [];
26957
- if (outerArgs.length === 1 && outerArgs[0] && typeof outerArgs[0] === "object") {
26958
- const innerRes = resolveImportedHelperCall(inner, ctx, propsParamName, cssProperty, themeBindingName);
27801
+ if (outerArgs.length === 1 && isCurrentCurriedHelperContextArg(outerArgs[0], propsParamName, themeBindingName)) {
27802
+ const innerRes = resolveImportedHelperCall(inner, resolverCtx, propsParamName, cssProperty, themeBindingName);
26959
27803
  if (innerRes.kind === "resolved") {
26960
- if ("expr" in innerRes.result) return innerRes.result;
27804
+ if ("expr" in innerRes.result) {
27805
+ if ("preserveRuntimeCall" in innerRes.result && innerRes.result.preserveRuntimeCall) runtimeCallState.info = {
27806
+ resolveCallContext: innerRes.resolveCallContext,
27807
+ resolveCallResult: innerRes.resolveCallResult,
27808
+ cssValueText: innerRes.result.expr
27809
+ };
27810
+ return innerRes.result;
27811
+ }
26961
27812
  if ("preserveRuntimeCall" in innerRes.result && innerRes.result.preserveRuntimeCall) {
26962
27813
  runtimeCallState.info = {
26963
27814
  resolveCallContext: innerRes.resolveCallContext,
@@ -26971,9 +27822,10 @@ function tryResolveConditionalValue(node, ctx) {
26971
27822
  if (callHasThemeArg(call)) markAsRuntimeCall(call);
26972
27823
  return null;
26973
27824
  };
27825
+ let templateHasDynamicArgUsage = false;
26974
27826
  const templateResult = resolveTemplateLiteralExpressions(b, (expr) => {
26975
27827
  const themeInfo = resolveThemeFromMemberExpr(expr);
26976
- if (themeInfo) return ctx.resolveValue({
27828
+ if (themeInfo) return resolveValue({
26977
27829
  kind: "theme",
26978
27830
  path: themeInfo.path,
26979
27831
  filePath: ctx.filePath,
@@ -26981,6 +27833,10 @@ function tryResolveConditionalValue(node, ctx) {
26981
27833
  }) ?? null;
26982
27834
  if (isCallExpressionNode(expr)) {
26983
27835
  const callRes = resolveCallExpr(expr, node.css.property);
27836
+ if (callRes?.dynamicArgUsage) {
27837
+ templateHasDynamicArgUsage = true;
27838
+ markAsRuntimeCall(expr);
27839
+ }
26984
27840
  return callRes ? {
26985
27841
  expr: callRes.expr,
26986
27842
  imports: callRes.imports
@@ -26988,22 +27844,29 @@ function tryResolveConditionalValue(node, ctx) {
26988
27844
  }
26989
27845
  return null;
26990
27846
  });
26991
- if (templateResult) return {
26992
- usage: "create",
26993
- ...templateResult
26994
- };
27847
+ if (templateResult) {
27848
+ if (templateHasDynamicArgUsage && runtimeCallState.info) runtimeCallState.info.cssValueText = templateResult.expr;
27849
+ return {
27850
+ usage: "create",
27851
+ ...templateResult,
27852
+ cssValueText: templateResult.expr,
27853
+ ...templateHasDynamicArgUsage ? { dynamicArgUsage: "call" } : {}
27854
+ };
27855
+ }
26995
27856
  if (isCallExpressionNode(b)) {
26996
27857
  const resolved = resolveCallExpr(b, node.css.property);
26997
27858
  if (resolved) return {
26998
27859
  usage: isAdapterResultCssValue(resolved, node.css.property) ? "create" : "props",
26999
27860
  expr: resolved.expr,
27000
- imports: resolved.imports
27861
+ imports: resolved.imports,
27862
+ cssValueText: resolved.expr,
27863
+ ...resolved.dynamicArgUsage ? { dynamicArgUsage: resolved.dynamicArgUsage } : {}
27001
27864
  };
27002
27865
  return null;
27003
27866
  }
27004
27867
  const themeInfo = resolveThemeFromMemberExpr(b);
27005
27868
  if (themeInfo) {
27006
- const res = ctx.resolveValue({
27869
+ const res = resolveValue({
27007
27870
  kind: "theme",
27008
27871
  path: themeInfo.path,
27009
27872
  filePath: ctx.filePath,
@@ -27013,14 +27876,15 @@ function tryResolveConditionalValue(node, ctx) {
27013
27876
  return {
27014
27877
  usage: expectedUsage,
27015
27878
  expr: res.expr,
27016
- imports: res.imports
27879
+ imports: res.imports,
27880
+ cssValueText: res.expr
27017
27881
  };
27018
27882
  }
27019
27883
  const importedInfo = extractRootAndPath(b);
27020
27884
  if (importedInfo) {
27021
27885
  const imp = ctx.resolveImport(importedInfo.rootName, importedInfo.rootNode);
27022
27886
  if (imp) {
27023
- const res = ctx.resolveValue({
27887
+ const res = resolveValue({
27024
27888
  kind: "importedValue",
27025
27889
  importedName: imp.importedName,
27026
27890
  source: imp.source,
@@ -27031,7 +27895,8 @@ function tryResolveConditionalValue(node, ctx) {
27031
27895
  if (res) return {
27032
27896
  usage: expectedUsage,
27033
27897
  expr: res.expr,
27034
- imports: res.imports
27898
+ imports: res.imports,
27899
+ cssValueText: res.expr
27035
27900
  };
27036
27901
  }
27037
27902
  }
@@ -27040,6 +27905,106 @@ function tryResolveConditionalValue(node, ctx) {
27040
27905
  const getBranch = (value) => {
27041
27906
  return branchToExpr(value);
27042
27907
  };
27908
+ const getBranchOptional = (value) => {
27909
+ return branchToExpr(value, "optional");
27910
+ };
27911
+ const isEmptyCssInterpolationBranch = (value) => isEmptyCssBranch(value);
27912
+ const resolveThemeBooleanStyleValue = (branch) => {
27913
+ if (isEmptyCssBranch(branch)) return null;
27914
+ const raw = literalToStaticValue(branch);
27915
+ if (raw !== null && typeof raw !== "boolean") return {
27916
+ value: raw,
27917
+ imports: [],
27918
+ ...typeof raw === "string" ? { cssValueText: raw } : {}
27919
+ };
27920
+ const themeInfo = resolveThemeFromMemberExpr(branch);
27921
+ if (themeInfo) {
27922
+ const res = (ctx.resolveValueOptional ?? ctx.resolveValue)({
27923
+ kind: "theme",
27924
+ path: themeInfo.path,
27925
+ filePath: ctx.filePath,
27926
+ loc: getNodeLocStart(branch) ?? void 0
27927
+ });
27928
+ if (!res) return null;
27929
+ const astNode = parseExpr(ctx.api, res.expr);
27930
+ return astNode ? {
27931
+ value: astNode,
27932
+ imports: res.imports,
27933
+ cssValueText: res.expr
27934
+ } : null;
27935
+ }
27936
+ const resolved = getBranchOptional(branch);
27937
+ if (!resolved || resolved.usage !== "create") return null;
27938
+ if (resolved.dynamicArgUsage) {
27939
+ if (isCallExpressionNode(branch)) markAsRuntimeCall(branch);
27940
+ return null;
27941
+ }
27942
+ const astNode = parseExpr(ctx.api, resolved.expr);
27943
+ return astNode ? {
27944
+ value: astNode,
27945
+ imports: resolved.imports,
27946
+ cssValueText: resolved.cssValueText ?? resolved.expr
27947
+ } : null;
27948
+ };
27949
+ const themeBoolInfo = checkThemeBooleanTest(body.test);
27950
+ if (themeBoolInfo && node.css.property) {
27951
+ const { consequent, alternate } = body;
27952
+ const trueBranch = themeBoolInfo.isNegated ? alternate : consequent;
27953
+ const falseBranch = themeBoolInfo.isNegated ? consequent : alternate;
27954
+ let runtimeCallBranch = null;
27955
+ const noteRuntimeCallBranch = (branch, before) => {
27956
+ if (runtimeCallState.info === before) return;
27957
+ runtimeCallBranch = runtimeCallBranch && runtimeCallBranch !== branch ? "both" : branch;
27958
+ };
27959
+ const beforeTrueResolve = runtimeCallState.info;
27960
+ const trueResolved = resolveThemeBooleanStyleValue(trueBranch);
27961
+ noteRuntimeCallBranch("true", beforeTrueResolve);
27962
+ const beforeFalseResolve = runtimeCallState.info;
27963
+ const falseResolved = resolveThemeBooleanStyleValue(falseBranch);
27964
+ noteRuntimeCallBranch("false", beforeFalseResolve);
27965
+ const trueValue = trueResolved?.value ?? null;
27966
+ const falseValue = falseResolved?.value ?? null;
27967
+ const trueImports = trueResolved?.imports ?? [];
27968
+ const falseImports = falseResolved?.imports ?? [];
27969
+ const trueCssValueText = trueResolved?.cssValueText;
27970
+ const falseCssValueText = falseResolved?.cssValueText;
27971
+ if (trueValue !== null && falseValue !== null) {
27972
+ const runtimeCallInfo = runtimeCallState.info;
27973
+ return {
27974
+ type: "splitThemeBooleanVariants",
27975
+ cssProp: node.css.property,
27976
+ themeProp: themeBoolInfo.themeProp,
27977
+ trueValue,
27978
+ falseValue,
27979
+ trueImports,
27980
+ falseImports,
27981
+ ...trueCssValueText ? { trueCssValueText } : {},
27982
+ ...falseCssValueText ? { falseCssValueText } : {},
27983
+ ...runtimeCallInfo?.resolveCallResult ? { runtimeResolveCallResult: runtimeCallInfo.resolveCallResult } : {},
27984
+ ...runtimeCallInfo?.cssValueText ? { runtimeCssValueText: runtimeCallInfo.cssValueText } : {}
27985
+ };
27986
+ }
27987
+ if (trueValue === null !== (falseValue === null) && isEmptyCssInterpolationBranch(trueValue === null ? trueBranch : falseBranch)) return null;
27988
+ const inlineStyleFallback = tryBuildThemeBooleanInlineStyleFallback({
27989
+ trueValue,
27990
+ falseValue,
27991
+ trueImports,
27992
+ falseImports,
27993
+ trueBranch,
27994
+ falseBranch,
27995
+ themeBoolInfo,
27996
+ cssProp: node.css.property,
27997
+ paramName,
27998
+ info
27999
+ });
28000
+ if (inlineStyleFallback) {
28001
+ if (inlineStyleFallback.type === "splitThemeBooleanWithInlineStyleFallback") {
28002
+ const resolvedRuntimeBranch = inlineStyleFallback.resolvedBranchIsTrue ? "true" : "false";
28003
+ if (runtimeCallBranch === resolvedRuntimeBranch || runtimeCallBranch === "both") return null;
28004
+ }
28005
+ return inlineStyleFallback;
28006
+ }
28007
+ }
27043
28008
  const buildOneSidedVariantResult = (args) => {
27044
28009
  const { cons, alt, alternate, truthyWhen } = args;
27045
28010
  if (!cons || alt || !isEmptyCssBranch(alternate)) return null;
@@ -27268,43 +28233,47 @@ function tryResolveConditionalValue(node, ctx) {
27268
28233
  }
27269
28234
  if (info?.kind === "themeBinding" && test.type === "Identifier" && typeof test.name === "string" && isDestructuredFromParam(expr, test.name)) {
27270
28235
  const destructuredProp = test.name;
27271
- const cons = getBranch(consequent);
27272
- const alt = getBranch(alternate);
27273
- if (cons && alt) {
27274
- if (new Set([cons.usage, alt.usage]).size === 1) {
27275
- const usage = cons.usage;
27276
- const variants = [{
27277
- nameHint: "truthy",
27278
- when: destructuredProp,
27279
- expr: cons.expr,
27280
- imports: cons.imports
27281
- }, {
27282
- nameHint: "falsy",
27283
- when: `!${destructuredProp}`,
27284
- expr: alt.expr,
27285
- imports: alt.imports
27286
- }];
27287
- return usage === "props" ? {
27288
- type: "splitVariantsResolvedStyles",
27289
- variants
27290
- } : {
27291
- type: "splitVariantsResolvedValue",
27292
- variants
27293
- };
28236
+ const whens = destructuredBooleanWhens(destructuredProp, getArrowFnParamBindings(expr));
28237
+ if (whens) {
28238
+ const cons = getBranch(consequent);
28239
+ const alt = getBranch(alternate);
28240
+ if (cons && alt) {
28241
+ if (new Set([cons.usage, alt.usage]).size === 1) {
28242
+ const usage = cons.usage;
28243
+ const variants = [{
28244
+ nameHint: "truthy",
28245
+ when: whens.truthy,
28246
+ expr: cons.expr,
28247
+ imports: cons.imports
28248
+ }, {
28249
+ nameHint: "falsy",
28250
+ when: whens.falsy,
28251
+ expr: alt.expr,
28252
+ imports: alt.imports
28253
+ }];
28254
+ return usage === "props" ? {
28255
+ type: "splitVariantsResolvedStyles",
28256
+ variants
28257
+ } : {
28258
+ type: "splitVariantsResolvedValue",
28259
+ variants
28260
+ };
28261
+ }
27294
28262
  }
28263
+ const oneSided = buildOneSidedVariantResult({
28264
+ cons,
28265
+ alt,
28266
+ alternate,
28267
+ truthyWhen: whens.truthy
28268
+ });
28269
+ if (oneSided) return oneSided;
28270
+ if (!cons || !alt) return buildRuntimeCallResult();
27295
28271
  }
27296
- const oneSided = buildOneSidedVariantResult({
27297
- cons,
27298
- alt,
27299
- alternate,
27300
- truthyWhen: destructuredProp
27301
- });
27302
- if (oneSided) return oneSided;
27303
- if (!cons || !alt) return buildRuntimeCallResult();
27304
28272
  }
27305
28273
  if (paramBindings?.kind === "destructured" && test.type === "Identifier" && typeof test.name === "string") {
27306
28274
  const resolvedProp = resolveIdentifierToPropName(test, paramBindings);
27307
- if (resolvedProp) {
28275
+ const resolvedWhens = resolvedProp ? destructuredBooleanWhens(resolvedProp, paramBindings) : null;
28276
+ if (resolvedProp && resolvedWhens) {
27308
28277
  const cons = getBranch(consequent);
27309
28278
  const alt = getBranch(alternate);
27310
28279
  if (cons && alt) {
@@ -27312,12 +28281,12 @@ function tryResolveConditionalValue(node, ctx) {
27312
28281
  const usage = cons.usage;
27313
28282
  const variants = [{
27314
28283
  nameHint: "truthy",
27315
- when: resolvedProp,
28284
+ when: resolvedWhens.truthy,
27316
28285
  expr: cons.expr,
27317
28286
  imports: cons.imports
27318
28287
  }, {
27319
28288
  nameHint: "falsy",
27320
- when: `!${resolvedProp}`,
28289
+ when: resolvedWhens.falsy,
27321
28290
  expr: alt.expr,
27322
28291
  imports: alt.imports
27323
28292
  }];
@@ -27342,7 +28311,7 @@ function tryResolveConditionalValue(node, ctx) {
27342
28311
  cons,
27343
28312
  alt,
27344
28313
  alternate,
27345
- truthyWhen: resolvedProp
28314
+ truthyWhen: resolvedWhens.truthy
27346
28315
  });
27347
28316
  if (oneSided) return oneSided;
27348
28317
  if (!cons || !alt) return buildRuntimeCallResult();
@@ -27419,6 +28388,8 @@ function tryResolveConditionalCssBlock(node, ctx) {
27419
28388
  const { left, right } = body;
27420
28389
  const testProp = paramName ? getSinglePropFromMemberExpr(left, paramName) : bindings?.kind === "destructured" ? resolveIdentifierToPropName(left, bindings) : null;
27421
28390
  if (!testProp) return null;
28391
+ const whens = destructuredBooleanWhens(testProp, bindings);
28392
+ if (!whens) return null;
27422
28393
  const cssText = literalToString(right);
27423
28394
  if (cssText !== null && cssText !== void 0) {
27424
28395
  const style = parseCssDeclarationBlock(cssText);
@@ -27427,7 +28398,7 @@ function tryResolveConditionalCssBlock(node, ctx) {
27427
28398
  type: "splitVariants",
27428
28399
  variants: [{
27429
28400
  nameHint: "truthy",
27430
- when: testProp,
28401
+ when: whens.truthy,
27431
28402
  style
27432
28403
  }]
27433
28404
  };
@@ -27435,7 +28406,7 @@ function tryResolveConditionalCssBlock(node, ctx) {
27435
28406
  if (!paramName) return null;
27436
28407
  return resolveThemeTemplateToCssVariant(right, paramName, ctx, {
27437
28408
  nameHint: "truthy",
27438
- when: testProp
28409
+ when: whens.truthy
27439
28410
  });
27440
28411
  }
27441
28412
  function tryResolveConditionalCssBlockTernary(node, ctx) {
@@ -27752,6 +28723,21 @@ function isDestructuredFromParam(arrowFn, name) {
27752
28723
  return p.key?.type === "Identifier" && p.key.name === name;
27753
28724
  });
27754
28725
  }
28726
+ function isCurrentCurriedHelperContextArg(arg, propsParamName, themeBindingName) {
28727
+ if (!arg || typeof arg !== "object") return false;
28728
+ const node = arg;
28729
+ if (node.type === "Identifier") return node.name === propsParamName || node.name === themeBindingName;
28730
+ if (node.type !== "ObjectExpression" || node.properties?.length !== 1) return false;
28731
+ const property = node.properties[0];
28732
+ if (property.type !== "Property" && property.type !== "ObjectProperty" || property.computed || property.key?.type !== "Identifier" || property.key.name !== "theme") return false;
28733
+ const value = property.value;
28734
+ if (value?.type === "Identifier" && value.name === themeBindingName) return true;
28735
+ if (propsParamName) {
28736
+ const valuePath = getMemberPathFromIdentifier(property.value, propsParamName);
28737
+ return valuePath?.length === 1 && valuePath[0] === "theme";
28738
+ }
28739
+ return false;
28740
+ }
27755
28741
  /**
27756
28742
  * Parses a template literal that contains a simple prop-based ternary expression.
27757
28743
  * Supports patterns like: `background: ${props.$primary ? "red" : "blue"}`
@@ -27800,7 +28786,6 @@ function tryBuildThemeBooleanInlineStyleFallback(args) {
27800
28786
  type: "splitThemeBooleanWithInlineStyleFallback",
27801
28787
  cssProp,
27802
28788
  themeProp: themeBoolInfo.themeProp,
27803
- isNegated: themeBoolInfo.isNegated,
27804
28789
  resolvedValue: resolvedBranchIsTrue ? trueValue : falseValue,
27805
28790
  resolvedImports: resolvedBranchIsTrue ? trueImports : falseImports,
27806
28791
  resolvedBranchIsTrue,
@@ -27887,6 +28872,35 @@ function replaceThemeRefsWithHookVar(expr, paramName, info) {
27887
28872
  };
27888
28873
  return replace(cloned);
27889
28874
  }
28875
+ /**
28876
+ * Builds truthy/falsy `when` condition strings for a destructured boolean-ish prop,
28877
+ * accounting for destructuring defaults. A default applies only when the prop is
28878
+ * `undefined`, so a statically-truthy default means the truthy branch must also
28879
+ * apply when the prop is unset (`prop === undefined || prop`).
28880
+ *
28881
+ * Returns null when the prop has a default whose truthiness cannot be determined
28882
+ * statically — callers should fall back to other handlers instead of emitting a
28883
+ * condition that ignores the default.
28884
+ */
28885
+ function destructuredBooleanWhens(propName, bindings) {
28886
+ if (bindings?.kind !== "destructured" || !bindings.defaults?.has(propName)) return {
28887
+ truthy: propName,
28888
+ falsy: `!${propName}`
28889
+ };
28890
+ const defaultValue = literalToStaticValue(bindings.defaults.get(propName));
28891
+ if (defaultValue === null) return null;
28892
+ if (defaultValue) {
28893
+ const truthy = `${propName} === undefined || ${propName}`;
28894
+ return {
28895
+ truthy,
28896
+ falsy: `!(${truthy})`
28897
+ };
28898
+ }
28899
+ return {
28900
+ truthy: propName,
28901
+ falsy: `!${propName}`
28902
+ };
28903
+ }
27890
28904
  //#endregion
27891
28905
  //#region src/internal/builtin-handlers.ts
27892
28906
  /**
@@ -28154,20 +29168,6 @@ function tryResolveArrowFnCallWithConditionalArgs(node, ctx) {
28154
29168
  };
28155
29169
  }
28156
29170
  /**
28157
- * Extracts a static literal value from an AST node, distinguishing null literals
28158
- * from extraction failure. Returns `undefined` when the node is not a recognized
28159
- * static literal, and the actual value (including `null`) otherwise.
28160
- */
28161
- function extractStaticLiteralValue(node) {
28162
- if (!node || typeof node !== "object") return;
28163
- const type = node.type;
28164
- if (type === "ArrowFunctionExpression" || type === "FunctionExpression") return;
28165
- if (type === "NullLiteral") return null;
28166
- if (type === "Literal" && node.value === null) return null;
28167
- const v = literalToStaticValue(node);
28168
- return v !== null ? v : void 0;
28169
- }
28170
- /**
28171
29171
  * Extracts the prop name from a conditional expression's test node.
28172
29172
  *
28173
29173
  * Supports:
@@ -29370,6 +30370,13 @@ function tryHandleInterpolatedStringValue(args) {
29370
30370
  }
29371
30371
  return true;
29372
30372
  }
30373
+ if (tryHandleTwoValueShorthandLeadingExpression({
30374
+ decl,
30375
+ d,
30376
+ resolveImportedValueExpr,
30377
+ addImport,
30378
+ setValue
30379
+ })) return true;
29373
30380
  const tl = buildInterpolatedTemplate({
29374
30381
  j,
29375
30382
  decl,
@@ -29386,7 +30393,9 @@ function tryHandleInterpolatedStringValue(args) {
29386
30393
  const outputs = cssDeclarationToStylexDeclarations(d);
29387
30394
  for (let i = 0; i < outputs.length; i++) {
29388
30395
  const out = outputs[i];
29389
- setValue(out.prop, maybeOmitPxUnitFromStylexValue(j, tl, out.prop, d.important, { numericIdentifiers: args.numericIdentifiers }));
30396
+ const emitted = maybeOmitPxUnitFromStylexValue(j, tl, out.prop, d.important, { numericIdentifiers: args.numericIdentifiers });
30397
+ if (emitted !== tl && hasSingleSlotUnitSuffix(d.value)) markProvenSingleTokenValue(emitted);
30398
+ setValue(out.prop, emitted);
29390
30399
  if (i === 0 && (d.leadingComment || d.leadingLineComment)) addPropComments(styleObj, out.prop, {
29391
30400
  leading: d.leadingComment,
29392
30401
  leadingLine: d.leadingLineComment
@@ -29394,6 +30403,48 @@ function tryHandleInterpolatedStringValue(args) {
29394
30403
  }
29395
30404
  return true;
29396
30405
  }
30406
+ function tryHandleTwoValueShorthandLeadingExpression(args) {
30407
+ const { decl, d, resolveImportedValueExpr, addImport, setValue } = args;
30408
+ const prop = (d.property ?? "").trim();
30409
+ if (prop !== "padding" && prop !== "margin") return false;
30410
+ if (!resolveImportedValueExpr || d.value?.kind !== "interpolated") return false;
30411
+ const parts = d.value.parts ?? [];
30412
+ if (parts.length !== 2 || parts[0]?.kind !== "slot" || parts[1]?.kind !== "static") return false;
30413
+ const slotId = parts[0].slotId;
30414
+ if (slotId === void 0) return false;
30415
+ const suffixMatch = (parts[1].value ?? "").match(/^([a-zA-Z%]+)\s+(.+)$/);
30416
+ if (!suffixMatch) return false;
30417
+ const expr = decl.templateExpressions[slotId];
30418
+ if (!expr || expr.type === "ArrowFunctionExpression") return false;
30419
+ const resolved = resolveImportedValueExpr(expr, {
30420
+ allowCssCalc: true,
30421
+ cssCalcUnit: suffixMatch[1]
30422
+ });
30423
+ if (!resolved || "bail" in resolved || !resolved.skipStaticWrap) return false;
30424
+ const entries = splitDirectionalProperty({
30425
+ prop,
30426
+ rawValue: (d.valueRaw ?? "").trim(),
30427
+ important: d.important,
30428
+ useLogical: getUseLogicalProperties()
30429
+ });
30430
+ if (!entries.length) return false;
30431
+ for (const imp of resolved.imports ?? []) addImport?.(imp);
30432
+ const placeholder = `__SC_EXPR_${slotId}__`;
30433
+ for (const entry of entries) {
30434
+ if (!entry.value.includes(placeholder)) {
30435
+ setValue(entry.prop, normalizeWhitespace(entry.value));
30436
+ continue;
30437
+ }
30438
+ if (resolvedValueCarriesUnit(resolved.resolved)) {
30439
+ setValue(entry.prop, resolved.resolved);
30440
+ continue;
30441
+ }
30442
+ const literalValue = literalToStaticValue(resolved.resolved);
30443
+ if (literalValue === null || typeof literalValue === "boolean") return false;
30444
+ setValue(entry.prop, normalizeWhitespace(entry.value.replace(placeholder, String(literalValue))));
30445
+ }
30446
+ return true;
30447
+ }
29397
30448
  function buildInterpolatedTemplate(args) {
29398
30449
  const { j, decl, cssValue, resolveCallExpr, resolveImportedValueExpr, addImport, multiline } = args;
29399
30450
  if (!cssValue || cssValue.kind !== "interpolated") return null;
@@ -29403,17 +30454,23 @@ function buildInterpolatedTemplate(args) {
29403
30454
  let allStatic = true;
29404
30455
  const quasis = [];
29405
30456
  let q = "";
30457
+ let staticPrefixToConsume = "";
29406
30458
  for (let partIndex = 0; partIndex < parts.length; partIndex++) {
29407
30459
  const part = parts[partIndex];
29408
30460
  if (part.kind === "static") {
29409
- q += part.value;
29410
- fullStaticValue += part.value;
30461
+ const rawValue = part.value ?? "";
30462
+ const value = staticPrefixToConsume && rawValue.startsWith(staticPrefixToConsume) ? rawValue.slice(staticPrefixToConsume.length) : rawValue;
30463
+ staticPrefixToConsume = "";
30464
+ q += value;
30465
+ fullStaticValue += value;
29411
30466
  continue;
29412
30467
  }
29413
30468
  if (part.kind === "slot") {
29414
30469
  const expr = decl.templateExpressions[part.slotId];
29415
30470
  if (!expr || expr.type === "ArrowFunctionExpression") return null;
29416
- if (expr.type === "CallExpression" && resolveCallExpr) {
30471
+ const adjacentUnit = getAdjacentUnitAfterParts(parts, partIndex);
30472
+ const negateResolvedUnit = Boolean(adjacentUnit && q.endsWith("-"));
30473
+ if (expr.type === "CallExpression" && resolveCallExpr && !adjacentUnit) {
29417
30474
  const resolved = resolveCallExpr(expr);
29418
30475
  if (resolved) {
29419
30476
  if (hasAdjacentUnitInParts(parts, partIndex)) return null;
@@ -29424,18 +30481,17 @@ function buildInterpolatedTemplate(args) {
29424
30481
  for (const imp of resolved.imports ?? []) addImport?.(imp);
29425
30482
  continue;
29426
30483
  }
29427
- quasis.push(j.templateElement({
29428
- raw: q,
29429
- cooked: q
29430
- }, false));
29431
- q = "";
29432
30484
  allStatic = false;
29433
30485
  for (const imp of resolved.imports ?? []) addImport?.(imp);
29434
- exprs.push(resolved.resolved);
30486
+ q = appendExpressionToTemplate(j, quasis, exprs, q, resolved.resolved);
29435
30487
  continue;
29436
30488
  }
29437
30489
  }
29438
- const importedResolved = resolveImportedValueExpr?.(expr);
30490
+ const importedResolved = resolveImportedValueExpr?.(expr, adjacentUnit ? {
30491
+ allowCssCalc: true,
30492
+ cssCalcUnit: adjacentUnit,
30493
+ negate: negateResolvedUnit
30494
+ } : void 0);
29439
30495
  if (importedResolved) {
29440
30496
  if ("bail" in importedResolved) return null;
29441
30497
  const resolved = importedResolved;
@@ -29443,7 +30499,13 @@ function buildInterpolatedTemplate(args) {
29443
30499
  for (const imp of resolved.imports ?? []) addImport?.(imp);
29444
30500
  return resolved.resolved;
29445
30501
  }
29446
- if (hasAdjacentUnitInParts(parts, partIndex) && !hasSingleSlotUnitSuffix(cssValue)) return null;
30502
+ if (hasAdjacentUnitInParts(parts, partIndex) && !hasSingleSlotUnitSuffix(cssValue)) {
30503
+ if (!adjacentUnit || !resolved.skipStaticWrap) return null;
30504
+ if (resolvedValueCarriesUnit(resolved.resolved)) {
30505
+ staticPrefixToConsume = adjacentUnit;
30506
+ if (negateResolvedUnit) q = q.slice(0, -1);
30507
+ }
30508
+ }
29447
30509
  if (resolved.resolved?.type === "StringLiteral" || resolved.resolved?.type === "Literal" && typeof resolved.resolved.value === "string") {
29448
30510
  const strValue = resolved.resolved.value;
29449
30511
  q += strValue;
@@ -29451,14 +30513,9 @@ function buildInterpolatedTemplate(args) {
29451
30513
  for (const imp of resolved.imports ?? []) addImport?.(imp);
29452
30514
  continue;
29453
30515
  }
29454
- quasis.push(j.templateElement({
29455
- raw: q,
29456
- cooked: q
29457
- }, false));
29458
- q = "";
29459
30516
  allStatic = false;
29460
30517
  for (const imp of resolved.imports ?? []) addImport?.(imp);
29461
- exprs.push(resolved.resolved);
30518
+ q = appendExpressionToTemplate(j, quasis, exprs, q, resolved.resolved);
29462
30519
  continue;
29463
30520
  }
29464
30521
  const literalValue = literalToStaticValue(expr);
@@ -29491,6 +30548,39 @@ function buildInterpolatedTemplate(args) {
29491
30548
  stylisValueRaw: multiline.stylisValueRaw
29492
30549
  });
29493
30550
  }
30551
+ function resolvedValueCarriesUnit(node) {
30552
+ if (!node || typeof node !== "object") return false;
30553
+ if (node.type === "NumericLiteral" || node.type === "Literal" && typeof node.value === "number") return false;
30554
+ if (node.type === "StringLiteral" || node.type === "Literal" && typeof node.value === "string") return /[a-zA-Z%]$/.test(String(node.value));
30555
+ return true;
30556
+ }
30557
+ const CSS_UNIT_PATTERN = /^(?:px|rem|em|ex|ch|cap|ic|lh|rlh|vw|vh|vi|vb|vmin|vmax|svw|svh|lvw|lvh|dvw|dvh|cqw|cqh|cqi|cqb|cqmin|cqmax|cm|mm|q|in|pt|pc|fr|%)$/i;
30558
+ function getAdjacentUnitAfterParts(parts, slotIndex) {
30559
+ const candidate = (parts[slotIndex + 1]?.kind === "static" ? parts[slotIndex + 1]?.value ?? "" : "").match(/^([a-zA-Z%]+)/)?.[1];
30560
+ return candidate && CSS_UNIT_PATTERN.test(candidate) ? candidate : null;
30561
+ }
30562
+ function appendExpressionToTemplate(j, quasis, expressions, currentQuasi, expression) {
30563
+ if (expression?.type !== "TemplateLiteral") {
30564
+ quasis.push(j.templateElement({
30565
+ raw: currentQuasi,
30566
+ cooked: currentQuasi
30567
+ }, false));
30568
+ expressions.push(expression);
30569
+ return "";
30570
+ }
30571
+ const nestedQuasis = expression.quasis ?? [];
30572
+ const nestedExpressions = expression.expressions ?? [];
30573
+ currentQuasi += nestedQuasis[0]?.value?.raw ?? nestedQuasis[0]?.value?.cooked ?? "";
30574
+ for (let index = 0; index < nestedExpressions.length; index++) {
30575
+ quasis.push(j.templateElement({
30576
+ raw: currentQuasi,
30577
+ cooked: currentQuasi
30578
+ }, false));
30579
+ expressions.push(nestedExpressions[index]);
30580
+ currentQuasi = nestedQuasis[index + 1]?.value?.raw ?? nestedQuasis[index + 1]?.value?.cooked ?? "";
30581
+ }
30582
+ return currentQuasi;
30583
+ }
29494
30584
  function hasAdjacentUnitInParts(parts, slotIndex) {
29495
30585
  const before = parts[slotIndex - 1]?.kind === "static" ? parts[slotIndex - 1]?.value ?? "" : "";
29496
30586
  const after = parts[slotIndex + 1]?.kind === "static" ? parts[slotIndex + 1]?.value ?? "" : "";
@@ -33494,7 +34584,12 @@ const createValuePatternHandlers = (ctx) => {
33494
34584
  callArg,
33495
34585
  condition: "always"
33496
34586
  });
33497
- } else styleFnFromProps.push({
34587
+ } else if (expr.body.operator === "||") styleFnFromProps.push({
34588
+ fnKey,
34589
+ jsxProp,
34590
+ condition: "truthy"
34591
+ });
34592
+ else styleFnFromProps.push({
33498
34593
  fnKey,
33499
34594
  jsxProp
33500
34595
  });
@@ -34201,6 +35296,89 @@ function createDeclProcessingState(state, decl) {
34201
35296
  };
34202
35297
  }
34203
35298
  //#endregion
35299
+ //#region src/internal/lower-rules/validate-decl-conflicts.ts
35300
+ /**
35301
+ * Returns the name of an imported runtime-condition root (recorded in
35302
+ * `nonPropConditionRoots`) that also appears as a genuine component prop. Such a
35303
+ * collision is unrepresentable: the decl-wide non-prop marking suppresses
35304
+ * destructuring of the prop, so a prop-based variant would silently read the
35305
+ * imported binding instead. Covers both typed props and props inferred from
35306
+ * `props.<name>` usage in styling.
35307
+ *
35308
+ * `variantWhens` must be sourced from the in-progress finalize state, since
35309
+ * `decl.variantStyleKeys` is not assigned until later in finalize.
35310
+ */
35311
+ function findImportedRootPropCollision(decl, variantWhens) {
35312
+ const roots = decl.nonPropConditionRoots;
35313
+ if (!roots || roots.size === 0) return null;
35314
+ const directProps = collectDirectPropReferences(decl);
35315
+ for (const root of roots) {
35316
+ if (directProps.has(root)) return root;
35317
+ const bareRef = new RegExp(`(?:^|[^\\w.])${escapeRegex(root)}(?:$|[^\\w.])`);
35318
+ if (variantWhens.some((when) => bareRef.test(when))) return root;
35319
+ }
35320
+ return null;
35321
+ }
35322
+ /**
35323
+ * Returns true when the component declares both a logical scroll longhand
35324
+ * (e.g. `scroll-padding-inline-start`) and a physical scroll side
35325
+ * (e.g. `scroll-padding-left`) in the same scroll family. StyleX's
35326
+ * logical/physical conflict normalization resolves these to physical sides
35327
+ * assuming horizontal-tb LTR, but the logical-to-physical mapping depends on
35328
+ * `writing-mode`/`direction` (e.g. `inline-start` is the right side in RTL),
35329
+ * so any such mix may silently preserve or override the wrong side — bail.
35330
+ */
35331
+ function hasConflictingLogicalPhysicalScrollProps(decl) {
35332
+ for (const family of SCROLL_FAMILIES) {
35333
+ let hasLogical = false;
35334
+ let hasPhysical = false;
35335
+ for (const rule of decl.rules) for (const declaration of rule.declarations) {
35336
+ const prop = declaration.property?.trim();
35337
+ if (!prop) continue;
35338
+ const camel = kebabToCamel(prop);
35339
+ if (!camel.startsWith(family)) continue;
35340
+ const side = camel.slice(family.length);
35341
+ if (/^(?:Inline|Block)/.test(side)) hasLogical = true;
35342
+ else if (side === "" || /^(?:Top|Right|Bottom|Left)$/.test(side)) hasPhysical = true;
35343
+ }
35344
+ if (hasLogical && hasPhysical) return true;
35345
+ }
35346
+ return false;
35347
+ }
35348
+ const SCROLL_FAMILIES = ["scrollMargin", "scrollPadding"];
35349
+ function collectDirectPropReferences(decl) {
35350
+ const props = /* @__PURE__ */ new Set();
35351
+ const add = (name) => {
35352
+ if (name && !name.startsWith("__")) props.add(name);
35353
+ };
35354
+ for (const name of decl.typeScriptExplicitPropNames ?? []) add(name);
35355
+ for (const entry of decl.styleFnFromProps ?? []) {
35356
+ add(entry.jsxProp);
35357
+ for (const extra of entry.extraCallArgs ?? []) add(extra.jsxProp);
35358
+ }
35359
+ for (const entry of decl.inlineStyleProps ?? []) add(entry.jsxProp);
35360
+ for (const dim of decl.variantDimensions ?? []) {
35361
+ add(dim.propName);
35362
+ add(dim.namespaceBooleanProp);
35363
+ }
35364
+ for (const cv of decl.compoundVariants ?? []) {
35365
+ add(cv.outerProp);
35366
+ add(cv.innerProp);
35367
+ }
35368
+ const attrs = decl.attrsInfo;
35369
+ if (attrs) {
35370
+ for (const entry of attrs.defaultAttrs ?? []) add(entry.jsxProp);
35371
+ for (const entry of attrs.dynamicAttrs ?? []) add(entry.jsxProp);
35372
+ for (const entry of attrs.conditionalAttrs ?? []) add(entry.jsxProp);
35373
+ for (const entry of attrs.invertedBoolAttrs ?? []) add(entry.jsxProp);
35374
+ for (const entry of attrs.attrsDynamicStyles ?? []) add(entry.jsxProp);
35375
+ }
35376
+ return props;
35377
+ }
35378
+ function kebabToCamel(prop) {
35379
+ return prop.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
35380
+ }
35381
+ //#endregion
34204
35382
  //#region src/internal/lower-rules/finalize-decl.ts
34205
35383
  /**
34206
35384
  * Finalizes per-declaration style objects after rule processing.
@@ -34209,6 +35387,14 @@ function createDeclProcessingState(state, decl) {
34209
35387
  function finalizeDeclProcessing(ctx) {
34210
35388
  const { state, decl, styleObj, perPropPseudo, perPropMedia, perPropComputedMedia, nestedSelectors, variantBuckets, variantStyleKeys, variantSourceOrder, extraStyleObjects, styleFnFromProps, styleFnDecls, attrBuckets, observedVariantFallbackFns, inlineStyleProps, localVarValues, cssHelperPropValues } = ctx;
34211
35389
  const { rewriteCssVarsInStyleObject, rewriteCssVarsInAstNode, relationOverridePseudoBuckets, relationOverrides, ancestorSelectorParents, resolvedStyleObjects, warnings } = state;
35390
+ if (findImportedRootPropCollision(decl, Object.keys(variantStyleKeys ?? {}))) {
35391
+ state.bailUnsupported(decl, "Imported runtime condition root collides with a component prop of the same name");
35392
+ return;
35393
+ }
35394
+ if (hasConflictingLogicalPhysicalScrollProps(decl)) {
35395
+ state.bailUnsupported(decl, "Mixed logical and physical scroll properties cannot be normalized without a known writing-mode");
35396
+ return;
35397
+ }
34212
35398
  mergeConditionBucket(styleObj, perPropPseudo);
34213
35399
  mergeConditionBucket(styleObj, perPropMedia);
34214
35400
  for (const [prop, entry] of perPropComputedMedia) {
@@ -36309,7 +37495,7 @@ const OPAQUE_SHORTHAND_PROPS = new Set([
36309
37495
  function warnOpaqueShorthands(styleObj, decl, warnings) {
36310
37496
  for (const prop of OPAQUE_SHORTHAND_PROPS) {
36311
37497
  const val = styleObj[prop];
36312
- if (val !== void 0 && isAstNode$1(val)) warnings.push({
37498
+ if (val !== void 0 && isAstNode$1(val) && !isProvenSingleTokenValue(val)) warnings.push({
36313
37499
  severity: "warning",
36314
37500
  type: "Shorthand property has an opaque value that StyleX will expand to longhands — use `directional` in resolveValue to return separate longhand tokens",
36315
37501
  loc: decl.loc,
@@ -36907,10 +38093,11 @@ function tryHandleInterpolatedBorder(ctx, args) {
36907
38093
  {
36908
38094
  const slotIndices = [];
36909
38095
  for (let i = 0; i < tokens.length; i++) {
36910
- const m = tokens[i].match(/^__SC_EXPR_(\d+)__$/);
38096
+ const m = tokens[i].match(/^__SC_EXPR_(\d+)__(?:([a-zA-Z%]+))?$/);
36911
38097
  if (m?.[1]) slotIndices.push({
36912
38098
  idx: i,
36913
- slotId: Number(m[1])
38099
+ slotId: Number(m[1]),
38100
+ ...m[2] ? { unit: m[2] } : {}
36914
38101
  });
36915
38102
  }
36916
38103
  if (slotIndices.length === 2 && tokens.length === 3) {
@@ -36938,7 +38125,7 @@ function tryHandleInterpolatedBorder(ctx, args) {
36938
38125
  return true;
36939
38126
  }
36940
38127
  const shouldSwap = slot0Role === "color" || slot1Role === "width";
36941
- const widthAst = shouldSwap ? slot1Ast : slot0Ast;
38128
+ const widthAst = withBorderWidthUnit(shouldSwap ? slot1Ast : slot0Ast, shouldSwap ? slot1.unit : slot0.unit);
36942
38129
  const colorAst = shouldSwap ? slot0Ast : slot1Ast;
36943
38130
  applyResolvedPropValue(widthProp, widthAst);
36944
38131
  applyResolvedPropValue(styleProp, middleStyle);
@@ -36985,6 +38172,11 @@ function tryHandleInterpolatedBorder(ctx, args) {
36985
38172
  if (width) applyResolvedPropValue(widthProp, width);
36986
38173
  if (style) applyResolvedPropValue(styleProp, style);
36987
38174
  if (color) applyResolvedPropValue(colorProp, color);
38175
+ const stripConsumedStaticParts = () => {
38176
+ const value = d.value;
38177
+ if (!staticRaw || value?.kind !== "interpolated" || !Array.isArray(value.parts)) return;
38178
+ for (const part of value.parts) if (part?.kind === "static") part.value = "";
38179
+ };
36988
38180
  const hasStaticWidthOrStyle = Boolean(width || style);
36989
38181
  const targetProp = interpolationTarget === "color" ? colorProp : interpolationTarget === "width" ? widthProp : styleProp;
36990
38182
  const targetCssProperty = interpolationTarget === "width" ? directionLower ? `border-${directionLower}-width` : "border-width" : interpolationTarget === "style" ? directionLower ? `border-${directionLower}-style` : "border-style" : directionLower ? `border-${directionLower}-color` : "border-color";
@@ -37046,6 +38238,7 @@ function tryHandleInterpolatedBorder(ctx, args) {
37046
38238
  const alt = expr.body.alternate;
37047
38239
  if (isMemberExpression(cons) || isMemberExpression(alt)) {
37048
38240
  d.property = targetCssProperty;
38241
+ stripConsumedStaticParts();
37049
38242
  return false;
37050
38243
  }
37051
38244
  }
@@ -37242,6 +38435,7 @@ function tryHandleInterpolatedBorder(ctx, args) {
37242
38435
  if (expr?.type === "ArrowFunctionExpression") {
37243
38436
  if (expr.body?.type === "MemberExpression") {
37244
38437
  d.property = targetCssProperty;
38438
+ stripConsumedStaticParts();
37245
38439
  return false;
37246
38440
  }
37247
38441
  }
@@ -37298,6 +38492,16 @@ function classifyBorderSlotRole(ast) {
37298
38492
  if ((node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string") return looksLikeLength(node.value) ? "width" : "color";
37299
38493
  return null;
37300
38494
  }
38495
+ function withBorderWidthUnit(expr, unit) {
38496
+ if (!unit) return expr;
38497
+ const staticValue = literalToStaticValue(expr);
38498
+ if (typeof staticValue === "number") return `${staticValue}${unit}`;
38499
+ if (typeof staticValue === "string" && looksLikeLength(staticValue)) {
38500
+ const trimmed = staticValue.trim();
38501
+ return /[a-zA-Z%]$/.test(trimmed) || Number.parseFloat(trimmed) === 0 ? staticValue : `${staticValue}${unit}`;
38502
+ }
38503
+ return expr;
38504
+ }
37301
38505
  function hasConflictingEarlierVariant(variantBuckets, borderEntries) {
37302
38506
  const borderProps = borderEntries.map(([prop]) => prop);
37303
38507
  return variantBuckets.some((bucket) => Object.keys(bucket).some((variantProp) => borderProps.some((borderProp) => borderLonghandsConflict(variantProp, borderProp))));
@@ -37318,6 +38522,61 @@ function parseBorderLonghand(prop) {
37318
38522
  };
37319
38523
  }
37320
38524
  //#endregion
38525
+ //#region src/internal/lower-rules/important-values.ts
38526
+ function appendImportantToStyleValue(j, valueAst, important) {
38527
+ if (!important) return valueAst;
38528
+ if (typeof valueAst === "string") return valueAst.includes("!important") ? valueAst : `${valueAst} !important`;
38529
+ if (typeof valueAst === "number") return `${valueAst} !important`;
38530
+ if (!valueAst || typeof valueAst !== "object") return valueAst;
38531
+ const node = valueAst;
38532
+ if (node.type === "ExpressionStatement") return appendImportantToStyleValue(j, node.expression, important);
38533
+ if (node.type === "StringLiteral" || node.type === "Literal" || node.type === "NumericLiteral") {
38534
+ if (typeof node.value === "string") return node.value.includes("!important") ? valueAst : j.literal(`${node.value} !important`);
38535
+ if (typeof node.value === "number") return j.literal(`${node.value} !important`);
38536
+ return valueAst;
38537
+ }
38538
+ if (node.type === "TemplateLiteral" && Array.isArray(node.quasis)) return appendImportantToTemplateLiteral(j, node.quasis, node.expressions, valueAst);
38539
+ return j.templateLiteral([j.templateElement({
38540
+ raw: "",
38541
+ cooked: ""
38542
+ }, false), j.templateElement({
38543
+ raw: " !important",
38544
+ cooked: " !important"
38545
+ }, true)], [valueAst]);
38546
+ }
38547
+ function cssValueIsImportant(value) {
38548
+ if (typeof value === "string") return value.includes("!important");
38549
+ if (!value || typeof value !== "object") return false;
38550
+ const node = value;
38551
+ if (node.type === "ExpressionStatement") return cssValueIsImportant(node.expression);
38552
+ if ((node.type === "StringLiteral" || node.type === "Literal") && typeof node.value === "string") return node.value.includes("!important");
38553
+ if (node.type === "TemplateLiteral" && Array.isArray(node.quasis)) return node.quasis.some((q) => {
38554
+ const raw = q?.value?.raw ?? "";
38555
+ const cooked = q?.value?.cooked ?? "";
38556
+ return raw.includes("!important") || cooked.includes("!important");
38557
+ });
38558
+ return false;
38559
+ }
38560
+ function appendImportantToTemplateLiteral(j, quasis, expressions, originalValue) {
38561
+ const lastIndex = quasis.length - 1;
38562
+ const last = quasis[lastIndex];
38563
+ const lastRaw = last?.value?.raw ?? last?.value?.cooked ?? "";
38564
+ const lastCooked = last?.value?.cooked ?? last?.value?.raw ?? "";
38565
+ if (lastRaw.includes("!important") || lastCooked.includes("!important")) return originalValue;
38566
+ const importantQuasis = quasis.map((quasi, i) => {
38567
+ const raw = quasi?.value?.raw ?? quasi?.value?.cooked ?? "";
38568
+ const cooked = quasi?.value?.cooked ?? quasi?.value?.raw ?? "";
38569
+ return i === lastIndex ? j.templateElement({
38570
+ raw: `${raw} !important`,
38571
+ cooked: `${cooked} !important`
38572
+ }, true) : j.templateElement({
38573
+ raw,
38574
+ cooked
38575
+ }, false);
38576
+ });
38577
+ return j.templateLiteral(importantQuasis, expressions ?? []);
38578
+ }
38579
+ //#endregion
37321
38580
  //#region src/internal/lower-rules/interpolated-variant-resolvers.ts
37322
38581
  function handleSplitVariantsResolvedValue(ctx) {
37323
38582
  const { j, decl, d, res, styleObj, variantBuckets, variantStyleKeys, pseudos, media, resolvedSelectorMedia, parseExpr, resolverImports, warnings, setBail, bailUnsupported } = ctx;
@@ -37435,7 +38694,8 @@ function handleSplitVariantsResolvedValue(ctx) {
37435
38694
  target[prop] = map;
37436
38695
  return map;
37437
38696
  };
37438
- const applyWithContext = (prop, valueAst) => {
38697
+ const applyWithContext = (prop, valueAstRaw) => {
38698
+ const valueAst = appendImportantToStyleValue(j, valueAstRaw, d.important);
37439
38699
  if (media) {
37440
38700
  const map = getOrCreateConditionMap(prop);
37441
38701
  map[media] = valueAst;
@@ -38025,7 +39285,7 @@ function emitPseudoMediaStyleFnFromProps(args) {
38025
39285
  //#endregion
38026
39286
  //#region src/internal/lower-rules/rule-interpolated-declaration.ts
38027
39287
  function handleInterpolatedDeclaration(args) {
38028
- const { ctx, rule, allRules, d, media, pseudos, pseudoElement, attrTarget, resolvedSelectorMedia, applyResolvedPropValue } = args;
39288
+ const { ctx, rule, allRules, d, media, pseudos, pseudoElement, attrTarget, resolvedSelectorMedia, hasAncestorAttributeScope, applyResolvedPropValue } = args;
38029
39289
  const { state, decl, styleObj, perPropPseudo, variantBuckets, variantStyleKeys, variantSourceOrder, observedVariantFallbackFns, extraStyleObjects, styleFnFromProps, styleFnDecls, inlineStyleProps, cssHelperPropValues, tryHandleMappedFunctionColor, tryHandleLogicalOrDefault, tryHandleConditionalPropCoalesceWithTheme, tryHandleEnumIfChainValue, tryHandleThemeIndexedLookup, handlerContext, componentInfo, tryHandlePropertyTernaryTemplateLiteral, tryHandleCssHelperFunctionSwitchBlock, tryHandleCssHelperConditionalBlock, findJsxPropTsType, findJsxPropTsTypeForVariantExtraction, annotateParamFromJsxProp, isJsxPropOptional, applyVariant, getBaseStyleTarget, notifyResolvedStylesArg } = ctx;
38030
39290
  const hasStaticPropsBeforeResolvedStylesArg = () => Object.keys(styleObj).length > 0 || getBaseStyleTarget() !== styleObj;
38031
39291
  const annotateScalarParams = (params, propNames) => {
@@ -38037,7 +39297,7 @@ function handleInterpolatedDeclaration(args) {
38037
39297
  if (isJsxPropOptional(propName)) addUndefinedToParamType(j, param);
38038
39298
  });
38039
39299
  };
38040
- const { api, j, filePath, warnings, resolverImports, keyframesNames, parseExpr, resolveValue, resolveCall, importMap, cssHelperNames, cssHelperObjectMembers, declByLocalName, cssHelperValuesByKey, staticPropertyValues, warnPropInlineStyle, applyCssHelperMixin, hasLocalThemeBinding, resolveThemeValue, resolveThemeValueFromFn, getOrCreateLocalStylexVar, resolveImportInScope, resolveImportForExpr } = state;
39300
+ const { api, j, filePath, warnings, resolverImports, keyframesNames, parseExpr, resolveValue, resolveCall, importMap, cssHelperNames, cssHelperObjectMembers, declByLocalName, cssHelperValuesByKey, staticPropertyValues, staticIdentifierValues, warnPropInlineStyle, applyCssHelperMixin, hasLocalThemeBinding, resolveThemeValue, resolveThemeValueFromFn, getOrCreateLocalStylexVar, resolveImportInScope, resolveImportForExpr } = state;
38041
39301
  const avoidNames = new Set(importMap.keys());
38042
39302
  if (state.bail) return;
38043
39303
  if (d.value.kind !== "interpolated") return;
@@ -38385,7 +39645,7 @@ function handleInterpolatedDeclaration(args) {
38385
39645
  return (observedNumericCssTextProps.has(jsxProp) || isNumberLikeTsType(findJsxPropTsType(jsxProp))) && getNumericCssEmissionMode(stylexProp) === "cssText";
38386
39646
  };
38387
39647
  const maybeEmitPreservedRuntimeCallOverride = (args) => {
38388
- const { resolveCallResult, originalExpr, loc } = args;
39648
+ const { resolveCallResult, originalExpr, loc, cssValueText } = args;
38389
39649
  if (!resolveCallResult || !("preserveRuntimeCall" in resolveCallResult) || !resolveCallResult.preserveRuntimeCall) return "not-requested";
38390
39650
  if (!d.property) {
38391
39651
  warnings.push({
@@ -38429,7 +39689,17 @@ function handleInterpolatedDeclaration(args) {
38429
39689
  const effectiveSuffix = d.important ? `${suffix} !important` : suffix;
38430
39690
  const runtimeCallArg = prefix || effectiveSuffix ? buildTemplateWithStaticParts(j, baseRuntimeExpr, prefix, effectiveSuffix) : baseRuntimeExpr;
38431
39691
  if (runtimeExprNeedsTheme) markDeclNeedsUseThemeHook(decl);
38432
- const outs = cssDeclarationToStylexDeclarations(d);
39692
+ const runtimeBackgroundProp = d.property === "background" ? resolveRuntimeBackgroundStylexProp(baseRuntimeExpr, cssValueText) : null;
39693
+ if (runtimeBackgroundProp === "unsupported") {
39694
+ warnings.push({
39695
+ severity: "error",
39696
+ type: "Arrow function: helper call body is not supported",
39697
+ loc
39698
+ });
39699
+ bail = true;
39700
+ return "failed";
39701
+ }
39702
+ const outs = runtimeBackgroundProp ? [{ prop: runtimeBackgroundProp }] : cssDeclarationToStylexDeclarations(d);
38433
39703
  if (outs.length !== 1 || !outs[0]?.prop) {
38434
39704
  warnings.push({
38435
39705
  severity: "error",
@@ -38439,21 +39709,38 @@ function handleInterpolatedDeclaration(args) {
38439
39709
  bail = true;
38440
39710
  return "failed";
38441
39711
  }
38442
- const out = outs[0];
38443
- const fnKey = styleKeyWithSuffix(decl.styleKey, out.prop);
38444
- if (!styleFnDecls.has(fnKey)) {
38445
- const outParamName = cssPropertyToIdentifier(out.prop, avoidNames);
38446
- const param = j.identifier(outParamName);
38447
- if (/\.(ts|tsx)$/.test(filePath)) param.typeAnnotation = j.tsTypeAnnotation(j.tsStringKeyword());
38448
- const body = j.objectExpression([makeCssProperty(j, out.prop, outParamName)]);
38449
- styleFnDecls.set(fnKey, j.arrowFunctionExpression([param], body));
39712
+ const runtimeProp = outs[0].prop;
39713
+ const runtimeStyle = { [runtimeProp]: runtimeCallArg };
39714
+ if (runtimeBackgroundProp) applyBackgroundShorthandLayerReset(j, runtimeStyle, runtimeBackgroundProp, d.important);
39715
+ if (!subtractLaterStaticOverrides({
39716
+ rule,
39717
+ allRules,
39718
+ currentDecl: d,
39719
+ branchStyles: [runtimeStyle],
39720
+ ignoreUnsafeOverlaps: true
39721
+ })) {
39722
+ warnings.push({
39723
+ severity: "error",
39724
+ type: "Arrow function: helper call body is not supported",
39725
+ loc
39726
+ });
39727
+ bail = true;
39728
+ return "failed";
38450
39729
  }
39730
+ if (Object.keys(runtimeStyle).length === 0) return "suppressed";
39731
+ const fnKey = styleKeyWithSuffix(decl.styleKey, runtimeProp);
39732
+ const outParamName = cssPropertyToIdentifier(runtimeProp, avoidNames);
39733
+ const param = j.identifier(outParamName);
39734
+ if (/\.(ts|tsx)$/.test(filePath)) param.typeAnnotation = j.tsTypeAnnotation(j.tsStringKeyword());
39735
+ const body = j.objectExpression(Object.entries(runtimeStyle).map(([prop, value]) => prop === runtimeProp ? makeCssProperty(j, runtimeProp, outParamName) : j.property("init", makeCssPropKey(j, prop), cloneAstNode(value))));
39736
+ styleFnDecls.set(fnKey, j.arrowFunctionExpression([param], body));
38451
39737
  const existingIdx = styleFnFromProps.findIndex((entry) => entry.fnKey === fnKey && entry.jsxProp === "__props" && entry.condition === "always");
38452
39738
  const newEntry = {
38453
39739
  fnKey,
38454
39740
  jsxProp: "__props",
38455
39741
  condition: "always",
38456
- callArg: cloneAstNode(runtimeCallArg)
39742
+ callArg: cloneAstNode(runtimeCallArg),
39743
+ sourceOrder: ctx.allocateSourceOrder()
38457
39744
  };
38458
39745
  if (existingIdx >= 0) styleFnFromProps[existingIdx] = newEntry;
38459
39746
  else styleFnFromProps.push(newEntry);
@@ -38586,7 +39873,10 @@ function handleInterpolatedDeclaration(args) {
38586
39873
  return null;
38587
39874
  };
38588
39875
  const allowCssCalcForImportedArithmetic = isEntireInterpolatedValueSingleSlot(d, decl);
38589
- const resolveImportedValueExpr = (expr, allowCssCalc = allowCssCalcForImportedArithmetic) => {
39876
+ const resolveImportedValueExpr = (expr, options = allowCssCalcForImportedArithmetic) => {
39877
+ const allowCssCalc = typeof options === "boolean" ? options : options.allowCssCalc ?? false;
39878
+ const cssCalcUnit = typeof options === "boolean" ? void 0 : options.cssCalcUnit;
39879
+ const forceNegate = typeof options === "boolean" ? false : options.negate === true;
38590
39880
  const resolveChildExpression = (child) => resolveImportedValueExpr(child, false);
38591
39881
  const isBailResolution = (result) => Boolean(result && "bail" in result);
38592
39882
  const resolvedOrOriginal = (result, original) => result && !isBailResolution(result) ? result.resolved : original;
@@ -38623,7 +39913,9 @@ function handleInterpolatedDeclaration(args) {
38623
39913
  prefix: "",
38624
39914
  suffix: ""
38625
39915
  };
38626
- if (staticParts.prefix) {
39916
+ const calcUnit = cssCalcUnit ?? staticParts.suffix;
39917
+ const hasNegativePrefix = !cssCalcUnit && staticParts.prefix === "-" && /^-?(?:[a-zA-Z%]+)$/.test(staticParts.suffix) && (expr.operator === "+" || expr.operator === "-");
39918
+ if (staticParts.prefix && !hasNegativePrefix && !cssCalcUnit) {
38627
39919
  warnings.push({
38628
39920
  severity: "warning",
38629
39921
  type: "Unsupported interpolation: call expression",
@@ -38635,7 +39927,9 @@ function handleInterpolatedDeclaration(args) {
38635
39927
  const calcExpr = buildCssCalcTemplateExpression({
38636
39928
  j,
38637
39929
  operator: expr.operator,
38638
- unit: expr.operator === "+" || expr.operator === "-" ? staticParts.suffix : "",
39930
+ unit: expr.operator === "+" || expr.operator === "-" ? calcUnit : "",
39931
+ negate: forceNegate || hasNegativePrefix,
39932
+ staticIdentifierValues,
38639
39933
  left: {
38640
39934
  node: resolvedLeft,
38641
39935
  allowExpression: Boolean(leftResult)
@@ -38648,9 +39942,9 @@ function handleInterpolatedDeclaration(args) {
38648
39942
  if (calcExpr) return {
38649
39943
  resolved: calcExpr,
38650
39944
  imports,
38651
- skipStaticWrap: staticParts.suffix !== ""
39945
+ skipStaticWrap: calcUnit !== ""
38652
39946
  };
38653
- if (staticParts.suffix && imports.length > 0) return bailResolvedUnitExpression(expr);
39947
+ if (calcUnit && imports.length > 0) return bailResolvedUnitExpression(expr);
38654
39948
  }
38655
39949
  return {
38656
39950
  resolved: j.binaryExpression(expr.operator, resolvedLeft, resolvedRight),
@@ -38758,7 +40052,25 @@ function handleInterpolatedDeclaration(args) {
38758
40052
  const imp = calleeInfo ? resolveImportInScope(calleeInfo.rootName, calleeInfo.rootNode) : null;
38759
40053
  if (!imp) return null;
38760
40054
  const resolvedCall = resolveCallExpr(expr);
38761
- if (resolvedCall) return resolvedCall;
40055
+ if (resolvedCall) {
40056
+ if (!cssCalcUnit) return resolvedCall;
40057
+ const literalValue = literalToStaticValue(resolvedCall.resolved);
40058
+ const numericLiteral = typeof literalValue === "number" ? literalValue : typeof literalValue === "string" && literalValue.trim() !== "" && Number.isFinite(Number(literalValue)) ? Number(literalValue) : null;
40059
+ if (numericLiteral !== null) return {
40060
+ resolved: j.literal(`${numericLiteral}${cssCalcUnit}`),
40061
+ imports: resolvedCall.imports,
40062
+ skipStaticWrap: true
40063
+ };
40064
+ if (forceNegate) return {
40065
+ resolved: buildNegatedCssTokenTemplate(j, resolvedCall.resolved),
40066
+ imports: resolvedCall.imports,
40067
+ skipStaticWrap: true
40068
+ };
40069
+ return {
40070
+ ...resolvedCall,
40071
+ skipStaticWrap: true
40072
+ };
40073
+ }
38762
40074
  warnings.push({
38763
40075
  severity: "warning",
38764
40076
  type: "Adapter resolveCall returned undefined for helper call",
@@ -38786,9 +40098,10 @@ function handleInterpolatedDeclaration(args) {
38786
40098
  };
38787
40099
  const resolveValueResult = resolveValue(resolveValueContext);
38788
40100
  if (!resolveValueResult) {
40101
+ const isPlainOwnedConstant = info.path.length === 0 && imp.source.kind === "absolutePath" && !isStylexImportSource(imp.source.value);
38789
40102
  warnings.push({
38790
40103
  severity: "error",
38791
- type: "Adapter resolveValue returned undefined for imported value",
40104
+ type: isPlainOwnedConstant ? "Imported constant cannot be referenced inside stylex.create() — move it into a `.stylex` defineConsts/defineVars group (or map it via adapter.resolveValue)" : "Adapter resolveValue returned undefined for imported value",
38792
40105
  loc: getNodeLocStart(expr) ?? decl.loc,
38793
40106
  context: {
38794
40107
  localName: decl.localName,
@@ -38888,7 +40201,8 @@ function handleInterpolatedDeclaration(args) {
38888
40201
  attrTarget,
38889
40202
  resolvedSelectorMedia
38890
40203
  })) continue;
38891
- if (isImportedShorthandUnitValue(d, decl, importMap)) {
40204
+ const numericIdentifiers = getNumericImportedStylexIdentifiers(j, filePath, importMap, resolverImports);
40205
+ if (isImportedShorthandUnitValue(d, decl, importMap, numericIdentifiers)) {
38892
40206
  bailUnsupportedLocal(decl, "Unsupported interpolation: call expression");
38893
40207
  continue;
38894
40208
  }
@@ -38901,7 +40215,7 @@ function handleInterpolatedDeclaration(args) {
38901
40215
  addImport,
38902
40216
  resolveImportedValueExpr,
38903
40217
  resolveThemeValue,
38904
- numericIdentifiers: getNumericImportedStylexIdentifiers(j, filePath, importMap, resolverImports),
40218
+ numericIdentifiers,
38905
40219
  setStyleValue: (prop, value) => applyResolvedPropValue(prop, value, null)
38906
40220
  })) continue;
38907
40221
  if (bail) break;
@@ -38910,9 +40224,31 @@ function handleInterpolatedDeclaration(args) {
38910
40224
  if (slot) {
38911
40225
  const expr = decl.templateExpressions[slot.slotId];
38912
40226
  if (tryEmitObservedCssBlockVariantBuckets(expr)) continue;
40227
+ const bailOnPropDependentCssHelper = (helperDecl) => {
40228
+ for (const helperExpr of helperDecl.templateExpressions ?? []) {
40229
+ if (!helperExpr || helperExpr.type !== "ArrowFunctionExpression" && helperExpr.type !== "FunctionExpression") continue;
40230
+ const propsUsed = new Set([...collectPropsFromArrowFn(helperExpr), ...collectPropsFromArrowFnDestructured(helperExpr)]);
40231
+ propsUsed.delete("theme");
40232
+ if (propsUsed.size > 0) {
40233
+ warnings.push({
40234
+ severity: "warning",
40235
+ type: "css helper with prop-based interpolation cannot be reused as a mixin",
40236
+ loc: decl.loc,
40237
+ context: {
40238
+ localName: decl.localName,
40239
+ mixin: helperDecl.localName
40240
+ }
40241
+ });
40242
+ bail = true;
40243
+ return true;
40244
+ }
40245
+ }
40246
+ return false;
40247
+ };
38913
40248
  if (expr?.type === "Identifier" && cssHelperNames.has(expr.name)) {
38914
40249
  const helperDecl = declByLocalName.get(expr.name);
38915
40250
  if (helperDecl) {
40251
+ if (bailOnPropDependentCssHelper(helperDecl)) break;
38916
40252
  applyCssHelperMixin(decl, helperDecl, cssHelperPropValues, inlineStyleProps);
38917
40253
  continue;
38918
40254
  }
@@ -38921,6 +40257,7 @@ function handleInterpolatedDeclaration(args) {
38921
40257
  const calleeName = expr.callee.name;
38922
40258
  const helperDecl = declByLocalName.get(calleeName);
38923
40259
  if (helperDecl?.isCssHelper) {
40260
+ if (bailOnPropDependentCssHelper(helperDecl)) break;
38924
40261
  applyCssHelperMixin(decl, helperDecl, cssHelperPropValues, inlineStyleProps);
38925
40262
  continue;
38926
40263
  }
@@ -39066,7 +40403,24 @@ function handleInterpolatedDeclaration(args) {
39066
40403
  })) continue;
39067
40404
  if (d.property && d.value.kind === "interpolated" && tryHandleMultiSlotTernary(ctx, d)) continue;
39068
40405
  if (tryHandleMultiSlotRuntimeValue(resolveImportedValueExpr)) continue;
39069
- const slotPart = d.value.parts.find((p) => p.kind === "slot");
40406
+ const remainingSlotParts = d.value.parts.filter((p) => p.kind === "slot");
40407
+ if (remainingSlotParts.filter((p) => {
40408
+ const slotExpr = decl.templateExpressions[p.slotId];
40409
+ return slotExpr?.type === "ArrowFunctionExpression" || slotExpr?.type === "FunctionExpression";
40410
+ }).length > 1) {
40411
+ warnings.push({
40412
+ severity: "error",
40413
+ type: "Unsupported interpolation: multiple dynamic slots in one declaration",
40414
+ loc: decl.loc,
40415
+ context: {
40416
+ localName: decl.localName,
40417
+ property: d.property
40418
+ }
40419
+ });
40420
+ bail = true;
40421
+ break;
40422
+ }
40423
+ const slotPart = remainingSlotParts[0];
39070
40424
  const slotId = slotPart && slotPart.kind === "slot" ? slotPart.slotId : 0;
39071
40425
  const expr = decl.templateExpressions[slotId];
39072
40426
  const loc = getNodeLocStart(expr);
@@ -39110,6 +40464,10 @@ function handleInterpolatedDeclaration(args) {
39110
40464
  bail = true;
39111
40465
  break;
39112
40466
  }
40467
+ if (hasSourceOrderedThemeStyleOverlap(decl, extraStyleObjects, res.cssText)) {
40468
+ bail = true;
40469
+ continue;
40470
+ }
39113
40471
  addResolverImports(res.imports);
39114
40472
  const exprAst = parseExpr(res.expr);
39115
40473
  if (!exprAst) {
@@ -39195,7 +40553,9 @@ function handleInterpolatedDeclaration(args) {
39195
40553
  addResolverImports(res.imports);
39196
40554
  const { prefix, suffix } = extractStaticPartsForDecl(d);
39197
40555
  const effectiveSuffix = d.important ? `${suffix} !important` : suffix;
39198
- const exprAst = parseExpr(wrapExprWithStaticParts(res.expr, prefix, effectiveSuffix));
40556
+ const wrappedExpr = wrapExprWithStaticParts(res.expr, prefix, effectiveSuffix);
40557
+ const cssValueTextForClassification = prefix || effectiveSuffix ? wrappedExpr : res.cssValueText;
40558
+ const exprAst = parseExpr(wrappedExpr);
39199
40559
  if (!exprAst) {
39200
40560
  const resolveCallMeta = res.resolveCallContext && res.resolveCallResult ? {
39201
40561
  resolveCallContext: res.resolveCallContext,
@@ -39217,7 +40577,7 @@ function handleInterpolatedDeclaration(args) {
39217
40577
  bail = true;
39218
40578
  break;
39219
40579
  }
39220
- const outs = cssDeclarationToStylexDeclarations(d);
40580
+ const outs = d.property === "background" && cssValueTextForClassification ? [{ prop: resolveBackgroundStylexProp(cssValueTextForClassification) }] : cssDeclarationToStylexDeclarations(d);
39221
40581
  for (let i = 0; i < outs.length; i++) {
39222
40582
  const out = outs[i];
39223
40583
  const commentSource = i === 0 ? {
@@ -39225,12 +40585,13 @@ function handleInterpolatedDeclaration(args) {
39225
40585
  leadingLine: d.leadingLineComment,
39226
40586
  trailingLine: d.trailingLineComment
39227
40587
  } : null;
39228
- applyResolvedPropValue(out.prop, exprAst, commentSource);
40588
+ applyResolvedPropValue(out.prop, exprAst, commentSource, d.property);
39229
40589
  }
39230
40590
  if (maybeEmitPreservedRuntimeCallOverride({
39231
40591
  resolveCallResult: res.resolveCallResult,
39232
40592
  originalExpr: expr,
39233
- loc
40593
+ loc,
40594
+ cssValueText: cssValueTextForClassification
39234
40595
  }) === "failed") break;
39235
40596
  continue;
39236
40597
  }
@@ -39238,43 +40599,89 @@ function handleInterpolatedDeclaration(args) {
39238
40599
  if (maybeEmitPreservedRuntimeCallOverride({
39239
40600
  resolveCallResult: res.resolveCallResult,
39240
40601
  originalExpr: expr,
39241
- loc
40602
+ loc,
40603
+ cssValueText: res.cssValueText
39242
40604
  }) === "failed") break;
39243
40605
  continue;
39244
40606
  }
39245
40607
  if (res && res.type === "splitThemeBooleanVariants") {
40608
+ if (pseudos?.length || media || pseudoElement || attrTarget || resolvedSelectorMedia || hasAncestorAttributeScope) {
40609
+ bail = true;
40610
+ continue;
40611
+ }
39246
40612
  addResolverImports(res.trueImports);
39247
40613
  addResolverImports(res.falseImports);
39248
- const { trueKey: trueStyleKey, falseKey: falseStyleKey } = buildThemeStyleKeys(decl.styleKey, res.themeProp);
39249
- if (!decl.needsUseThemeHook) decl.needsUseThemeHook = [];
39250
- let entry = decl.needsUseThemeHook.find((e) => e.themeProp === res.themeProp);
39251
- if (!entry) {
39252
- entry = {
39253
- themeProp: res.themeProp,
39254
- trueStyleKey,
39255
- falseStyleKey
39256
- };
39257
- decl.needsUseThemeHook.push(entry);
39258
- extraStyleObjects.set(trueStyleKey, {});
39259
- extraStyleObjects.set(falseStyleKey, {});
39260
- }
39261
- const trueStyle = extraStyleObjects.get(trueStyleKey) ?? {};
39262
- const falseStyle = extraStyleObjects.get(falseStyleKey) ?? {};
39263
- if (!applyThemeBooleanValue(j, res.cssProp, res.trueValue, trueStyle)) {
40614
+ const trueStyle = {};
40615
+ const falseStyle = {};
40616
+ if (!applyThemeBooleanValue(j, res.cssProp, res.trueValue, trueStyle, d.important, res.trueCssValueText)) {
39264
40617
  bail = true;
39265
40618
  continue;
39266
40619
  }
39267
- if (!applyThemeBooleanValue(j, res.cssProp, res.falseValue, falseStyle)) {
40620
+ if (!applyThemeBooleanValue(j, res.cssProp, res.falseValue, falseStyle, d.important, res.falseCssValueText)) {
39268
40621
  bail = true;
39269
40622
  continue;
39270
40623
  }
39271
- extraStyleObjects.set(trueStyleKey, trueStyle);
39272
- extraStyleObjects.set(falseStyleKey, falseStyle);
40624
+ const { trueKey: baseTrueStyleKey, falseKey: baseFalseStyleKey } = buildThemeStyleKeys(decl.styleKey, res.themeProp);
40625
+ if (!decl.needsUseThemeHook) decl.needsUseThemeHook = [];
40626
+ const latestSourceOrder = getLatestThemeInterleavableSourceOrder({
40627
+ decl,
40628
+ variantSourceOrder,
40629
+ styleFnFromProps
40630
+ });
40631
+ const matchingThemeEntries = decl.needsUseThemeHook.filter((entry) => entry.themeProp === res.themeProp && (entry.trueStyleKey || entry.falseStyleKey));
40632
+ let reusableEntry = null;
40633
+ for (let i = matchingThemeEntries.length - 1; i >= 0; i--) {
40634
+ const entry = matchingThemeEntries[i];
40635
+ if (entry.sourceOrder !== void 0 && entry.sourceOrder === latestSourceOrder) {
40636
+ reusableEntry = entry;
40637
+ break;
40638
+ }
40639
+ }
40640
+ const mergeExtraStyleObject = (styleKey, style) => {
40641
+ const existing = extraStyleObjects.get(styleKey);
40642
+ if (!existing) {
40643
+ extraStyleObjects.set(styleKey, style);
40644
+ return;
40645
+ }
40646
+ const merged = { ...existing };
40647
+ for (const [prop, value] of Object.entries(style)) {
40648
+ if (Object.hasOwn(merged, prop) && cssValueIsImportant(merged[prop]) && !cssValueIsImportant(value)) continue;
40649
+ merged[prop] = value;
40650
+ }
40651
+ extraStyleObjects.set(styleKey, merged);
40652
+ };
40653
+ if (reusableEntry) {
40654
+ const restoredTrueStyleKey = reusableEntry.trueStyleKey ?? restoreThemeStyleKeyFromPairedSide(baseTrueStyleKey, baseFalseStyleKey, reusableEntry.falseStyleKey);
40655
+ const restoredFalseStyleKey = reusableEntry.falseStyleKey ?? restoreThemeStyleKeyFromPairedSide(baseFalseStyleKey, baseTrueStyleKey, reusableEntry.trueStyleKey);
40656
+ reusableEntry.trueStyleKey = restoredTrueStyleKey;
40657
+ reusableEntry.falseStyleKey = restoredFalseStyleKey;
40658
+ mergeExtraStyleObject(restoredTrueStyleKey, trueStyle);
40659
+ mergeExtraStyleObject(restoredFalseStyleKey, falseStyle);
40660
+ } else {
40661
+ const sourceOrder = ctx.allocateSourceOrder();
40662
+ const hasExistingStyleBucketForThemeProp = matchingThemeEntries.length > 0;
40663
+ const trueStyleKey = hasExistingStyleBucketForThemeProp ? styleKeyWithSuffix(baseTrueStyleKey, `theme${sourceOrder}`) : baseTrueStyleKey;
40664
+ const falseStyleKey = hasExistingStyleBucketForThemeProp ? styleKeyWithSuffix(baseFalseStyleKey, `theme${sourceOrder}`) : baseFalseStyleKey;
40665
+ decl.needsUseThemeHook.push({
40666
+ themeProp: res.themeProp,
40667
+ trueStyleKey,
40668
+ falseStyleKey,
40669
+ sourceOrder
40670
+ });
40671
+ extraStyleObjects.set(trueStyleKey, trueStyle);
40672
+ extraStyleObjects.set(falseStyleKey, falseStyle);
40673
+ }
40674
+ if (maybeEmitPreservedRuntimeCallOverride({
40675
+ resolveCallResult: res.runtimeResolveCallResult,
40676
+ originalExpr: expr,
40677
+ loc,
40678
+ cssValueText: res.runtimeCssValueText
40679
+ }) === "failed") break;
39273
40680
  decl.needsWrapperComponent = true;
39274
40681
  continue;
39275
40682
  }
39276
40683
  if (res && res.type === "splitThemeBooleanWithInlineStyleFallback") {
39277
- if (pseudos?.length || media || pseudoElement) {
40684
+ if (pseudos?.length || media || pseudoElement || attrTarget || resolvedSelectorMedia || hasAncestorAttributeScope) {
39278
40685
  bail = true;
39279
40686
  continue;
39280
40687
  }
@@ -39282,9 +40689,14 @@ function handleInterpolatedDeclaration(args) {
39282
40689
  bail = true;
39283
40690
  continue;
39284
40691
  }
40692
+ const stylexDeclarations = cssDeclarationToStylexDeclarations(d);
40693
+ if (hasLaterDeclarationForStylexProps(d, allRules, new Set(stylexDeclarations.map((out) => out.prop).filter(Boolean)))) {
40694
+ bail = true;
40695
+ continue;
40696
+ }
39285
40697
  addResolverImports(res.resolvedImports);
39286
40698
  if (!decl.needsUseThemeHook) decl.needsUseThemeHook = [];
39287
- if (!decl.needsUseThemeHook.some((e) => e.themeProp === res.themeProp)) decl.needsUseThemeHook.push({
40699
+ if (!decl.needsUseThemeHook.some((e) => e.themeProp === res.themeProp && e.trueStyleKey === null && e.falseStyleKey === null)) decl.needsUseThemeHook.push({
39288
40700
  themeProp: res.themeProp,
39289
40701
  trueStyleKey: null,
39290
40702
  falseStyleKey: null
@@ -39292,8 +40704,8 @@ function handleInterpolatedDeclaration(args) {
39292
40704
  const themeCondition = j.memberExpression(j.identifier("theme"), j.identifier(res.themeProp));
39293
40705
  const undefinedExpr = j.identifier("undefined");
39294
40706
  const inlineExpr = res.inlineExpr;
39295
- const conditionalExpr = !res.resolvedBranchIsTrue !== res.isNegated ? j.conditionalExpression(themeCondition, inlineExpr, undefinedExpr) : j.conditionalExpression(themeCondition, undefinedExpr, inlineExpr);
39296
- for (const out of cssDeclarationToStylexDeclarations(d)) {
40707
+ const conditionalExpr = !res.resolvedBranchIsTrue ? j.conditionalExpression(themeCondition, inlineExpr, undefinedExpr) : j.conditionalExpression(themeCondition, undefinedExpr, inlineExpr);
40708
+ for (const out of stylexDeclarations) {
39297
40709
  if (!out.prop) continue;
39298
40710
  styleObj[out.prop] = res.resolvedValue;
39299
40711
  inlineStyleProps.push({
@@ -39592,11 +41004,11 @@ function handleInterpolatedDeclaration(args) {
39592
41004
  const scalarDynamic = shouldUseScalarDynamicArgs(d.property, d.valueRaw) && dynamicProps.length > 0 ? scalarizePropsObjectDynamicValue({
39593
41005
  j,
39594
41006
  valueExpr: dynamicValueExpr,
39595
- paramName: "props",
41007
+ paramName,
39596
41008
  propNames: dynamicProps
39597
41009
  }) : null;
39598
41010
  const dynamicStyleValueExpr = scalarDynamic?.valueExpr ?? dynamicValueExpr;
39599
- const dynamicStyleParams = scalarDynamic ? scalarDynamic.paramNames.map((propName) => j.identifier(propName)) : [j.identifier("props")];
41011
+ const dynamicStyleParams = scalarDynamic ? scalarDynamic.paramNames.map((propName) => j.identifier(propName)) : [j.identifier(paramName)];
39600
41012
  if (scalarDynamic) annotateScalarParams(dynamicStyleParams, scalarDynamic.paramNames);
39601
41013
  const callArg = j.objectExpression(dynamicProps.map((name) => {
39602
41014
  const prop = j.property("init", j.identifier(name), j.identifier(name));
@@ -39884,17 +41296,22 @@ function handleInterpolatedDeclaration(args) {
39884
41296
  const callArg = resolvedCallArg ?? scalarCallArg;
39885
41297
  const hasExplicitType = !!decl.propsType;
39886
41298
  const isOptional = ctx.isJsxPropOptional(jsxProp);
41299
+ const foldsStaticBaseIntoPseudoDefault = !media && !!pseudos?.length && staticBaseValueWouldFold(styleObj[out.prop]);
39887
41300
  styleFnFromProps.push({
39888
41301
  fnKey,
39889
41302
  jsxProp,
39890
41303
  ...callArg ? { callArg } : {},
39891
- ...hasExplicitType && !isOptional ? { condition: "always" } : {}
41304
+ ...hasExplicitType && !isOptional || foldsStaticBaseIntoPseudoDefault ? { condition: "always" } : {}
39892
41305
  });
39893
41306
  if (!styleFnDecls.has(fnKey)) {
39894
41307
  const param = j.identifier(outParamName);
39895
41308
  const valueId = j.identifier(outParamName);
39896
41309
  if (jsxProp !== "__props") annotateParamFromJsxProp(param, jsxProp);
39897
41310
  if (resolvedCallArg && /\.(ts|tsx)$/.test(filePath)) param.typeAnnotation = j.tsTypeAnnotation(j.tsStringKeyword());
41311
+ if (foldsStaticBaseIntoPseudoDefault && isOptional && jsxProp !== "__props" && /\.(ts|tsx)$/.test(filePath)) {
41312
+ const baseTypeNode = param.typeAnnotation?.typeAnnotation ?? j.tsStringKeyword();
41313
+ param.typeAnnotation = j.tsTypeAnnotation(j.tsUnionType([baseTypeNode, j.tsUndefinedKeyword()]));
41314
+ }
39898
41315
  if (jsxProp?.startsWith?.("$")) ensureShouldForwardPropDrop(decl, jsxProp);
39899
41316
  const buildValueExpr = () => {
39900
41317
  const transformed = (() => {
@@ -39959,7 +41376,28 @@ function handleInterpolatedDeclaration(args) {
39959
41376
  };
39960
41377
  const valueExpr = buildValueExpr();
39961
41378
  const getPropValue = () => {
41379
+ if (!media && !pseudos?.length) return valueExpr;
41380
+ if (!media && pseudos?.length) {
41381
+ const existingStatic = styleObj[out.prop];
41382
+ let defaultValue = j.literal(null);
41383
+ if (existingStatic !== void 0 && existingStatic !== null) if (typeof existingStatic === "object") {
41384
+ if ("type" in existingStatic) {
41385
+ defaultValue = cloneAstNode(existingStatic);
41386
+ delete styleObj[out.prop];
41387
+ }
41388
+ } else {
41389
+ defaultValue = staticValueToLiteral(j, existingStatic);
41390
+ delete styleObj[out.prop];
41391
+ }
41392
+ return j.objectExpression([j.property("init", j.identifier("default"), defaultValue), ...pseudos.map((ps) => j.property("init", j.literal(ps), valueExpr))]);
41393
+ }
39962
41394
  if (!media) return valueExpr;
41395
+ if (pseudos?.length) return buildPseudoMediaPropValue({
41396
+ j,
41397
+ valueExpr,
41398
+ pseudos,
41399
+ media
41400
+ });
39963
41401
  const existingFn = styleFnDecls.get(fnKey);
39964
41402
  let existingValue = null;
39965
41403
  if (existingFn?.type === "ArrowFunctionExpression") {
@@ -40105,13 +41543,23 @@ function handleInterpolatedDeclaration(args) {
40105
41543
  hint: "Expected: props.x && 'css-string'"
40106
41544
  }
40107
41545
  };
40108
- if (op === "||" || op === "??") return {
40109
- type: "Arrow function: indexed theme lookup pattern not matched",
40110
- context: {
40111
- property: d.property,
40112
- operator: op
40113
- }
40114
- };
41546
+ if (op === "||" || op === "??") {
41547
+ const left = body?.left;
41548
+ if (isMemberExpression(left) && !memberExpressionTouchesTheme(left)) return {
41549
+ type: "Unsupported interpolation: member expression",
41550
+ context: {
41551
+ memberExpression: left?.type,
41552
+ operator: op
41553
+ }
41554
+ };
41555
+ return {
41556
+ type: "Arrow function: indexed theme lookup pattern not matched",
41557
+ context: {
41558
+ property: d.property,
41559
+ operator: op
41560
+ }
41561
+ };
41562
+ }
40115
41563
  }
40116
41564
  if (bodyType === "CallExpression") return {
40117
41565
  type: "Arrow function: helper call body is not supported",
@@ -40166,6 +41614,18 @@ function handleInterpolatedDeclaration(args) {
40166
41614
  if (bail) state.markBail();
40167
41615
  }
40168
41616
  /**
41617
+ * Returns true if any part of a member/identifier chain references `theme`
41618
+ * (e.g. `props.theme.color[x]` or a destructured `theme.color[x]`). Used to
41619
+ * distinguish indexed theme lookups from prop-rooted member accesses.
41620
+ */
41621
+ function memberExpressionTouchesTheme(node) {
41622
+ if (!node || typeof node !== "object") return false;
41623
+ const n = node;
41624
+ if (n.type === "Identifier") return n.name === "theme";
41625
+ if (isMemberExpression(n)) return memberExpressionTouchesTheme(n.property) || memberExpressionTouchesTheme(n.object);
41626
+ return false;
41627
+ }
41628
+ /**
40169
41629
  * Searches the function body for a local variable with the given name whose
40170
41630
  * initializer references `fnParamName`. Returns a cloned expression with
40171
41631
  * `fnParamName` replaced by `jsxProp`, or null if no such variable is found.
@@ -40215,6 +41675,17 @@ function resolveDerivedLocalVariable(j, fnBody, fnParamName, localName, jsxProp)
40215
41675
  function isPseudoElementSelector(pseudoElement) {
40216
41676
  return pseudoElement === "::before" || pseudoElement === "::after" || pseudoElement === "::placeholder";
40217
41677
  }
41678
+ /**
41679
+ * Whether a base style value for a property would be folded into a pseudo-gated
41680
+ * dynamic style function's `default` (mirrors the fold logic in getPropValue):
41681
+ * plain primitives and AST-node values fold; existing pseudo/media condition
41682
+ * buckets (plain objects without a `type` discriminator) do not.
41683
+ */
41684
+ function staticBaseValueWouldFold(existingStatic) {
41685
+ if (existingStatic === void 0 || existingStatic === null) return false;
41686
+ if (typeof existingStatic === "object") return "type" in existingStatic;
41687
+ return true;
41688
+ }
40218
41689
  function tryHandleLocalCustomPropertyDefinition(args) {
40219
41690
  const { j, d, decl, expr, getOrCreateLocalStylexVar, inlineStyleProps } = args;
40220
41691
  if (!expr || typeof expr !== "object") return false;
@@ -40269,16 +41740,45 @@ function tryHandleRuntimeConditionalStaticBranches(ctx, args) {
40269
41740
  state.bailUnsupported(decl, "Unsupported interpolation: call expression");
40270
41741
  return true;
40271
41742
  }
40272
- if (hasLaterDeclarationOverlap(rule, allRules, d, new Set(Object.keys(consequentStyle)))) {
41743
+ if (!subtractLaterStaticOverrides({
41744
+ rule,
41745
+ allRules,
41746
+ currentDecl: d,
41747
+ branchStyles: [consequentStyle, alternateStyle]
41748
+ })) {
40273
41749
  state.bailUnsupported(decl, "Unsupported interpolation: call expression");
40274
41750
  return true;
40275
41751
  }
41752
+ if (!Object.keys(consequentStyle).length && !Object.keys(alternateStyle).length) return true;
40276
41753
  const target = getBaseStyleTarget();
40277
41754
  for (const [prop, value] of Object.entries(alternateStyle)) target[prop] = value;
40278
41755
  applyVariant({ when }, consequentStyle);
40279
41756
  decl.needsWrapperComponent = true;
41757
+ recordNonPropConditionRoots(decl, expr.test);
40280
41758
  return true;
40281
41759
  }
41760
+ /**
41761
+ * Records the root identifiers of an imported runtime condition on the decl so
41762
+ * wrapper emission treats them as module-scope bindings rather than component
41763
+ * props (which matters for lowercase roots like `browser.isTouchDevice`).
41764
+ */
41765
+ function recordNonPropConditionRoots(decl, test) {
41766
+ const roots = decl.nonPropConditionRoots ??= /* @__PURE__ */ new Set();
41767
+ const visit = (expr) => {
41768
+ if (expr.type === "LogicalExpression") {
41769
+ visit(expr.left);
41770
+ visit(expr.right);
41771
+ return;
41772
+ }
41773
+ if (expr.type === "UnaryExpression") {
41774
+ visit(expr.argument);
41775
+ return;
41776
+ }
41777
+ const info = extractRootAndPath(expr);
41778
+ if (info && info.path.length > 0) roots.add(info.rootName);
41779
+ };
41780
+ visit(test);
41781
+ }
40282
41782
  function buildStaticBranchStyle(d, rawValue) {
40283
41783
  if (d.property === "background" && isUnsupportedBackgroundShorthandValue(rawValue)) return null;
40284
41784
  const staticDecl = {
@@ -40303,24 +41803,140 @@ function sameStyleProps(left, right) {
40303
41803
  const rightKeys = new Set(Object.keys(right));
40304
41804
  return leftKeys.length === rightKeys.size && leftKeys.every((key) => rightKeys.has(key));
40305
41805
  }
40306
- function hasLaterDeclarationOverlap(rule, allRules, currentDecl, stylexProps) {
41806
+ /**
41807
+ * Removes branch properties that are unconditionally overridden by later static
41808
+ * declarations in the same selector context, so the runtime variant cannot
41809
+ * invert the original CSS cascade. Partially overridden directional props are
41810
+ * narrowed to the longhands that survive the override (e.g. `marginBlock`
41811
+ * overridden by a later `margin-top` becomes `marginBlockEnd`).
41812
+ *
41813
+ * Returns false when a later overlapping declaration cannot be subtracted
41814
+ * safely (conditional at-rule context, dynamic value, property-less helper, or
41815
+ * a multi-token branch value that cannot be split per longhand) — the caller
41816
+ * must bail in that case.
41817
+ */
41818
+ function subtractLaterStaticOverrides(args) {
41819
+ const { rule, allRules, currentDecl, branchStyles, ignoreUnsafeOverlaps = false } = args;
40307
41820
  const currentIndex = rule.declarations.indexOf(currentDecl);
40308
- if (currentIndex === -1) return false;
40309
- if (declarationsOverlap(rule.declarations.slice(currentIndex + 1), stylexProps)) return true;
41821
+ if (currentIndex === -1) return true;
41822
+ const laterContexts = [{
41823
+ declarations: rule.declarations.slice(currentIndex + 1),
41824
+ unconditional: true
41825
+ }];
40310
41826
  const currentRuleIndex = allRules.indexOf(rule);
40311
- if (currentRuleIndex === -1) return false;
40312
- for (const laterRule of allRules.slice(currentRuleIndex + 1)) {
40313
- if (rule.selector !== laterRule.selector) continue;
40314
- if (declarationsOverlap(laterRule.declarations, stylexProps)) return true;
41827
+ if (currentRuleIndex !== -1) for (const laterRule of allRules.slice(currentRuleIndex + 1)) {
41828
+ if (laterRule.selector !== rule.selector) continue;
41829
+ laterContexts.push({
41830
+ declarations: laterRule.declarations,
41831
+ unconditional: sameAtRuleStack(laterRule.atRuleStack, rule.atRuleStack)
41832
+ });
40315
41833
  }
40316
- return false;
41834
+ const branchProps = () => [...new Set(branchStyles.flatMap((style) => Object.keys(style)))];
41835
+ for (const context of laterContexts) for (const laterDecl of context.declarations) {
41836
+ if (!laterDecl.property) {
41837
+ if (branchProps().length) return false;
41838
+ continue;
41839
+ }
41840
+ if (isBorderShorthandProperty(laterDecl.property)) {
41841
+ const borderProps = new Set(cssDeclarationToStylexDeclarations(laterDecl).map((out) => out.prop));
41842
+ if (branchProps().some((prop) => [...borderProps].some((borderProp) => stylexPropsOverlap(prop, borderProp)))) return false;
41843
+ continue;
41844
+ }
41845
+ if (laterDecl.property.trim() === "background") {
41846
+ const overlapped = branchProps().filter((prop) => prop.startsWith("background"));
41847
+ if (!overlapped.length) continue;
41848
+ if (currentDecl.important && !laterDecl.important) {
41849
+ if (ignoreUnsafeOverlaps) continue;
41850
+ return false;
41851
+ }
41852
+ if (!context.unconditional || laterDecl.value.kind !== "static") {
41853
+ if (ignoreUnsafeOverlaps) continue;
41854
+ return false;
41855
+ }
41856
+ for (const branch of branchStyles) for (const prop of overlapped) delete branch[prop];
41857
+ continue;
41858
+ }
41859
+ for (const out of cssDeclarationToStylexDeclarations(laterDecl)) {
41860
+ const overrideProp = out.prop;
41861
+ const overlapped = branchProps().filter((prop) => stylexPropsOverlap(prop, overrideProp));
41862
+ if (!overlapped.length) continue;
41863
+ if (currentDecl.important && !laterDecl.important) {
41864
+ if (ignoreUnsafeOverlaps) continue;
41865
+ return false;
41866
+ }
41867
+ if (!context.unconditional || laterDecl.value.kind !== "static") {
41868
+ if (ignoreUnsafeOverlaps) continue;
41869
+ return false;
41870
+ }
41871
+ for (const branch of branchStyles) if (!subtractOverrideFromBranch(branch, overlapped, overrideProp)) return false;
41872
+ }
41873
+ }
41874
+ return true;
40317
41875
  }
40318
- function declarationsOverlap(declarations, stylexProps) {
40319
- for (const laterDecl of declarations) {
40320
- if (!laterDecl.property) return true;
40321
- for (const out of cssDeclarationToStylexDeclarations(laterDecl)) if ([...stylexProps].some((prop) => stylexPropsOverlap(prop, out.prop))) return true;
41876
+ function sameAtRuleStack(left, right) {
41877
+ return left.length === right.length && left.every((entry, i) => entry === right[i]);
41878
+ }
41879
+ /** True for the `border` / `border-<side>` shorthands (not the longhands). */
41880
+ function isBorderShorthandProperty(property) {
41881
+ return /^border(?:-(?:top|right|bottom|left))?$/.test(property.trim());
41882
+ }
41883
+ function subtractOverrideFromBranch(branch, overlappedProps, overrideProp) {
41884
+ const overridePhysical = new Set(physicalLonghandExpansion(overrideProp));
41885
+ const overrideIsLogical = isLogicalDirectionalProp(overrideProp);
41886
+ for (const branchProp of overlappedProps) {
41887
+ if (!(branchProp in branch)) continue;
41888
+ const branchPhysical = physicalLonghandExpansion(branchProp);
41889
+ const remainder = branchPhysical.filter((prop) => !overridePhysical.has(prop));
41890
+ if (remainder.length === branchPhysical.length) continue;
41891
+ if (isLogicalDirectionalProp(branchProp) !== overrideIsLogical) return false;
41892
+ const value = branch[branchProp];
41893
+ delete branch[branchProp];
41894
+ if (!remainder.length) continue;
41895
+ if (!isSingleCssToken(value)) return false;
41896
+ for (const physical of remainder) {
41897
+ const name = overrideIsLogical && LOGICAL_TO_PHYSICAL[branchProp] ? logicalFormForPhysical(branchProp, physical) : physical;
41898
+ if (!name) return false;
41899
+ branch[name] = value;
41900
+ }
40322
41901
  }
40323
- return false;
41902
+ return true;
41903
+ }
41904
+ /**
41905
+ * True for a logical directional longhand whose physical side(s) depend on the
41906
+ * writing mode — `marginInline`, `paddingBlockEnd`, `scrollMarginInlineStart`,
41907
+ * etc. The physical-neutral full shorthands (`margin`, `padding`) and physical
41908
+ * sides (`marginTop`) are not logical.
41909
+ */
41910
+ function isLogicalDirectionalProp(prop) {
41911
+ return LOGICAL_TO_PHYSICAL[prop] !== void 0;
41912
+ }
41913
+ /** Physical longhands covered by a StyleX directional/border property. */
41914
+ function physicalLonghandExpansion(prop) {
41915
+ const group = SHORTHAND_LONGHANDS[prop];
41916
+ if (group) return [...group.physical];
41917
+ const logical = LOGICAL_TO_PHYSICAL[prop];
41918
+ if (logical) return [...logical];
41919
+ const borderMatch = prop.match(/^border(Top|Right|Bottom|Left)?(Width|Style|Color)$/);
41920
+ if (borderMatch) {
41921
+ const side = borderMatch[1];
41922
+ const kind = borderMatch[2];
41923
+ return side ? [prop] : [
41924
+ "Top",
41925
+ "Right",
41926
+ "Bottom",
41927
+ "Left"
41928
+ ].map((s) => `border${s}${kind}`);
41929
+ }
41930
+ return [prop];
41931
+ }
41932
+ /** Maps a physical longhand back to the Start/End form of a logical branch prop. */
41933
+ function logicalFormForPhysical(logicalProp, physical) {
41934
+ for (const [name, physicalProps] of Object.entries(LOGICAL_TO_PHYSICAL)) if (physicalProps.length === 1 && physicalProps[0] === physical && name.startsWith(logicalProp)) return name;
41935
+ return null;
41936
+ }
41937
+ function isSingleCssToken(value) {
41938
+ if (typeof value === "number") return true;
41939
+ return typeof value === "string" && value.trim() !== "" && !/\s/.test(value.trim());
40324
41940
  }
40325
41941
  function stylexPropsOverlap(left, right) {
40326
41942
  const leftRelated = relatedDirectionalProps(left);
@@ -40356,21 +41972,20 @@ function addRelatedBorderLonghands(prop, related) {
40356
41972
  }
40357
41973
  function isImportedRuntimeCondition(expr, importMap) {
40358
41974
  const info = extractRootAndPath(expr);
40359
- if (info && info.path.length > 0 && importMap.has(info.rootName) && isRuntimeConditionImportRoot(info.rootName)) return true;
41975
+ if (info && info.path.length > 0 && importMap.has(info.rootName)) return true;
40360
41976
  if (expr.type === "LogicalExpression" && expr.operator === "&&") return isImportedRuntimeCondition(expr.left, importMap) && isImportedRuntimeCondition(expr.right, importMap);
40361
41977
  if (expr.type === "UnaryExpression" && expr.operator === "!") return isImportedRuntimeCondition(expr.argument, importMap);
40362
41978
  return false;
40363
41979
  }
40364
- function isRuntimeConditionImportRoot(rootName) {
40365
- return /^[A-Z]/.test(rootName);
40366
- }
40367
- function isImportedShorthandUnitValue(d, decl, importMap) {
41980
+ function isImportedShorthandUnitValue(d, decl, importMap, numericIdentifiers) {
40368
41981
  if (!d.property || !isCssShorthandProperty(d.property)) return false;
40369
41982
  const staticParts = getSingleSlotStaticParts(d, decl);
40370
41983
  if (!staticParts || !/^[a-zA-Z%]/.test(staticParts.suffix)) return false;
40371
41984
  const slotPart = d.value.kind === "interpolated" ? d.value.parts.find((part) => part.kind === "slot") : null;
40372
41985
  const info = extractRootAndPath(slotPart && slotPart.kind === "slot" ? decl.templateExpressions[slotPart.slotId] : void 0);
40373
- return !!info && importMap.has(info.rootName);
41986
+ if (!info || !importMap.has(info.rootName)) return false;
41987
+ if ((d.property === "margin" || d.property === "padding") && staticParts.prefix.trim() === "" && /^[a-zA-Z%]+$/.test(staticParts.suffix.trim()) && numericIdentifiers.has(info.rootName)) return false;
41988
+ return true;
40374
41989
  }
40375
41990
  function expressionToSource(j, expr) {
40376
41991
  try {
@@ -40684,20 +42299,22 @@ function buildCssCalcTemplateExpression(args) {
40684
42299
  const expressions = [];
40685
42300
  const quasis = [];
40686
42301
  let currentQuasi = "calc(";
40687
- const appendOperand = (operand) => {
40688
- const staticText = expressionToCalcStaticText(operand.node, args.unit);
42302
+ const appendOperand = (operand, options = {}) => {
42303
+ const staticText = expressionToCalcStaticText(operand.node, args.unit, args.staticIdentifierValues);
40689
42304
  if (staticText !== null) {
40690
- currentQuasi += staticText;
42305
+ currentQuasi += options.negate ? negateCalcStaticText(staticText) : staticText;
40691
42306
  return true;
40692
42307
  }
40693
42308
  if (!operand.allowExpression || !isStylexCalcExpression(operand.node)) return false;
42309
+ if (options.negate) currentQuasi += "-1 * ";
40694
42310
  quasis.push(currentQuasi);
40695
42311
  currentQuasi = "";
40696
42312
  expressions.push(operand.node);
40697
42313
  return true;
40698
42314
  };
40699
- if (!appendOperand(args.left)) return null;
40700
- currentQuasi += ` ${args.operator} `;
42315
+ if (!appendOperand(args.left, { negate: args.negate })) return null;
42316
+ const operator = args.negate ? negateCssCalcOperator(args.operator) : args.operator;
42317
+ currentQuasi += ` ${operator} `;
40701
42318
  if (!appendOperand(args.right)) return null;
40702
42319
  currentQuasi += ")";
40703
42320
  if (expressions.length === 0) return args.j.literal(currentQuasi);
@@ -40708,9 +42325,27 @@ function buildCssCalcTemplateExpression(args) {
40708
42325
  cooked: raw
40709
42326
  }, index === quasis.length - 1)), expressions);
40710
42327
  }
40711
- function expressionToCalcStaticText(node, unit = "") {
42328
+ function buildNegatedCssTokenTemplate(j, expression) {
42329
+ return j.templateLiteral([j.templateElement({
42330
+ raw: "calc(-1 * ",
42331
+ cooked: "calc(-1 * "
42332
+ }, false), j.templateElement({
42333
+ raw: ")",
42334
+ cooked: ")"
42335
+ }, true)], [expression]);
42336
+ }
42337
+ function negateCssCalcOperator(operator) {
42338
+ return operator === "+" ? "-" : operator === "-" ? "+" : operator;
42339
+ }
42340
+ function negateCalcStaticText(value) {
42341
+ return value.startsWith("-") ? value.slice(1) : `-${value}`;
42342
+ }
42343
+ function expressionToCalcStaticText(node, unit = "", staticIdentifierValues) {
40712
42344
  const staticValue = literalToStaticValue(node);
40713
42345
  if (typeof staticValue === "number") return `${staticValue}${unit}`;
42346
+ const identifierName = node && typeof node === "object" && node.type === "Identifier" ? node.name : void 0;
42347
+ const identifierValue = identifierName ? staticIdentifierValues?.get(identifierName) : void 0;
42348
+ if (typeof identifierValue === "number") return `${identifierValue}${unit}`;
40714
42349
  return null;
40715
42350
  }
40716
42351
  function hasAdjacentTemplateUnit(quasis, expressionIndex) {
@@ -40873,7 +42508,7 @@ function tryHandleDynamicPseudoElementStyleFunction(args) {
40873
42508
  * Apply a resolved theme boolean value to a style object, expanding CSS shorthands.
40874
42509
  * Returns false if the value cannot be expanded (caller should bail).
40875
42510
  */
40876
- function applyThemeBooleanValue(j, cssProp, value, target) {
42511
+ function applyThemeBooleanValue(j, cssProp, value, target, important, cssValueText) {
40877
42512
  const node = value;
40878
42513
  const unwrapped = node?.type === "ExpressionStatement" ? node.expression : node;
40879
42514
  const strValue = unwrapped && (unwrapped.type === "StringLiteral" || unwrapped.type === "Literal") && typeof unwrapped.value === "string" ? unwrapped.value : null;
@@ -40883,18 +42518,85 @@ function applyThemeBooleanValue(j, cssProp, value, target) {
40883
42518
  const direction = borderMatch[1] ? borderMatch[1].slice(1).charAt(0).toUpperCase() + borderMatch[1].slice(2) : "";
40884
42519
  const parsed = parseBorderShorthandParts(strValue);
40885
42520
  if (!parsed) return false;
40886
- if (parsed.width) target[`border${direction}Width`] = j.literal(parsed.width);
40887
- if (parsed.style) target[`border${direction}Style`] = j.literal(parsed.style);
40888
- if (parsed.color) target[`border${direction}Color`] = j.literal(parsed.color);
42521
+ if (parsed.width) target[`border${direction}Width`] = appendImportantToStyleValue(j, j.literal(parsed.width), important);
42522
+ if (parsed.style) target[`border${direction}Style`] = appendImportantToStyleValue(j, j.literal(parsed.style), important);
42523
+ if (parsed.color) target[`border${direction}Color`] = appendImportantToStyleValue(j, j.literal(parsed.color), important);
40889
42524
  return true;
40890
42525
  }
40891
42526
  if (cssProp === "background") {
40892
- target[resolveBackgroundStylexProp(strValue ?? "")] = value;
42527
+ const backgroundText = strValue ?? cssValueText ?? "";
42528
+ if (backgroundText.trim() === "none") {
42529
+ target.backgroundImage = appendImportantToStyleValue(j, j.literal("none"), important);
42530
+ target.backgroundColor = appendImportantToStyleValue(j, j.literal("transparent"), important);
42531
+ return true;
42532
+ }
42533
+ const backgroundProp = resolveBackgroundStylexProp(backgroundText);
42534
+ target[backgroundProp] = appendImportantToStyleValue(j, value, important);
42535
+ applyBackgroundShorthandLayerReset(j, target, backgroundProp, important);
40893
42536
  return true;
40894
42537
  }
40895
- target[cssPropertyToStylexProp(cssProp)] = value;
42538
+ if (isCssShorthandProperty(cssProp)) return false;
42539
+ target[cssPropertyToStylexProp(cssProp)] = appendImportantToStyleValue(j, value, important);
40896
42540
  return true;
40897
42541
  }
42542
+ function restoreThemeStyleKeyFromPairedSide(targetBaseKey, pairedBaseKey, pairedStyleKey) {
42543
+ if (pairedStyleKey?.startsWith(pairedBaseKey)) return `${targetBaseKey}${pairedStyleKey.slice(pairedBaseKey.length)}`;
42544
+ return targetBaseKey;
42545
+ }
42546
+ function getLatestThemeInterleavableSourceOrder(args) {
42547
+ const sourceOrders = Object.values(args.variantSourceOrder);
42548
+ appendSourceOrders(sourceOrders, args.styleFnFromProps);
42549
+ appendSourceOrders(sourceOrders, args.decl.needsUseThemeHook);
42550
+ appendSourceOrders(sourceOrders, args.decl.pseudoAliasSelectors);
42551
+ appendSourceOrders(sourceOrders, args.decl.variantDimensions);
42552
+ return sourceOrders.length > 0 ? Math.max(...sourceOrders) : -1;
42553
+ }
42554
+ function appendSourceOrders(sourceOrders, entries) {
42555
+ for (const entry of entries ?? []) if (entry.sourceOrder !== void 0) sourceOrders.push(entry.sourceOrder);
42556
+ }
42557
+ function applyBackgroundShorthandLayerReset(j, target, backgroundProp, important) {
42558
+ if (backgroundProp === "backgroundColor") {
42559
+ target.backgroundImage = appendImportantToStyleValue(j, j.literal("none"), important);
42560
+ return;
42561
+ }
42562
+ target.backgroundColor = appendImportantToStyleValue(j, j.literal("transparent"), important);
42563
+ }
42564
+ function resolveRuntimeBackgroundStylexProp(value, cssValueText) {
42565
+ const node = unwrapExpressionNode(value);
42566
+ if (node?.type !== "ConditionalExpression") {
42567
+ const staticText = getRuntimeBackgroundStaticText(node);
42568
+ if (staticText !== null) return resolveBackgroundStylexProp(staticText);
42569
+ return cssValueText ? resolveBackgroundStylexProp(cssValueText) : null;
42570
+ }
42571
+ const consequentProp = classifyRuntimeBackgroundBranch(node.consequent);
42572
+ const alternateProp = classifyRuntimeBackgroundBranch(node.alternate);
42573
+ if (consequentProp && alternateProp) return consequentProp === alternateProp ? consequentProp : "unsupported";
42574
+ const cssTextProp = cssValueText ? resolveBackgroundStylexProp(cssValueText) : null;
42575
+ const knownProp = consequentProp ?? alternateProp;
42576
+ if (knownProp) {
42577
+ if (knownProp === "backgroundImage") return "unsupported";
42578
+ if (cssTextProp && cssTextProp !== knownProp) return "unsupported";
42579
+ return "backgroundColor";
42580
+ }
42581
+ if (cssTextProp === "backgroundImage") return "unsupported";
42582
+ return "backgroundColor";
42583
+ }
42584
+ function classifyRuntimeBackgroundBranch(value) {
42585
+ const staticText = getRuntimeBackgroundStaticText(unwrapExpressionNode(value));
42586
+ return staticText === null ? null : resolveBackgroundStylexProp(staticText);
42587
+ }
42588
+ function unwrapExpressionNode(value) {
42589
+ if (!value || typeof value !== "object") return null;
42590
+ const node = value;
42591
+ if (node.type === "ExpressionStatement" || node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") return unwrapExpressionNode(node.expression);
42592
+ return node;
42593
+ }
42594
+ function getRuntimeBackgroundStaticText(value) {
42595
+ if (!value) return null;
42596
+ if ((value.type === "StringLiteral" || value.type === "Literal") && typeof value.value === "string") return value.value;
42597
+ if (value.type === "TemplateLiteral") return (value.quasis ?? []).map((quasi) => quasi.value?.cooked ?? quasi.value?.raw ?? "").join("") || null;
42598
+ return null;
42599
+ }
40898
42600
  function scalarizePropsObjectDynamicValue(args) {
40899
42601
  const propNames = uniqueScalarPropNames(args.propNames);
40900
42602
  if (propNames.length === 0) return null;
@@ -41538,6 +43240,84 @@ function tryHandleMultiSlotTernary(ctx, d) {
41538
43240
  function hasRuntimeImport(imports) {
41539
43241
  return (imports ?? []).some((imp) => !isStylexImportSource(imp.from.value));
41540
43242
  }
43243
+ function hasSourceOrderedThemeStyleOverlap(decl, extraStyleObjects, cssText) {
43244
+ const themeProps = /* @__PURE__ */ new Set();
43245
+ for (const entry of decl.needsUseThemeHook ?? []) {
43246
+ if (entry.sourceOrder === void 0) continue;
43247
+ collectStyleObjectProps(extraStyleObjects.get(entry.trueStyleKey ?? ""), themeProps);
43248
+ collectStyleObjectProps(extraStyleObjects.get(entry.falseStyleKey ?? ""), themeProps);
43249
+ }
43250
+ return cssTextMayOverlapStylexProps(cssText, themeProps);
43251
+ }
43252
+ function collectStyleObjectProps(style, props) {
43253
+ if (!style) return;
43254
+ for (const prop of Object.keys(style)) props.add(prop);
43255
+ }
43256
+ function cssTextMayOverlapStylexProps(cssText, props) {
43257
+ if (props.size === 0) return false;
43258
+ if (!cssText) return true;
43259
+ const chunks = cssText.split(";").map((chunk) => chunk.trim()).filter(Boolean);
43260
+ if (chunks.length === 0) return true;
43261
+ for (const chunk of chunks) {
43262
+ const match = chunk.match(/^([^:]+):([\s\S]+)$/);
43263
+ if (!match?.[1] || !match[2]) return true;
43264
+ const property = match[1].trim();
43265
+ const valueRaw = match[2].trim();
43266
+ if (laterDeclarationMayResetStylexProps(property, props)) return true;
43267
+ for (const out of cssDeclarationToStylexDeclarations({
43268
+ property,
43269
+ value: {
43270
+ kind: "static",
43271
+ value: valueRaw
43272
+ },
43273
+ important: false,
43274
+ valueRaw
43275
+ })) if (hasOverlappingStylexProp(props, out.prop)) return true;
43276
+ }
43277
+ return false;
43278
+ }
43279
+ function hasLaterDeclarationForStylexProps(current, rules, props) {
43280
+ if (props.size === 0) return false;
43281
+ let sawCurrent = false;
43282
+ for (const rule of rules) for (const candidate of rule.declarations) {
43283
+ if (candidate === current) {
43284
+ sawCurrent = true;
43285
+ continue;
43286
+ }
43287
+ if (!isDeclarationAfter(current, candidate, sawCurrent)) continue;
43288
+ if (!candidate.property) return true;
43289
+ if (laterDeclarationMayResetStylexProps(candidate.property, props)) return true;
43290
+ for (const out of cssDeclarationToStylexDeclarations(candidate)) if (hasOverlappingStylexProp(props, out.prop)) return true;
43291
+ }
43292
+ return false;
43293
+ }
43294
+ function isDeclarationAfter(current, candidate, sawCurrent) {
43295
+ if (current.sourceOrder !== void 0 && candidate.sourceOrder !== void 0) return candidate.sourceOrder > current.sourceOrder;
43296
+ return sawCurrent;
43297
+ }
43298
+ function hasOverlappingStylexProp(props, candidate) {
43299
+ for (const prop of props) if (stylexPropsOverlap(prop, candidate)) return true;
43300
+ return false;
43301
+ }
43302
+ function laterDeclarationMayResetStylexProps(cssProperty, props) {
43303
+ const property = cssProperty.trim();
43304
+ if (property === "background") return hasStylexPropWithPrefix(props, "background");
43305
+ if (!isBorderShorthandProperty(property)) return false;
43306
+ const side = property.match(/^border-(top|right|bottom|left)$/)?.[1];
43307
+ return hasBorderResetOverlap(props, side);
43308
+ }
43309
+ function hasStylexPropWithPrefix(props, prefix) {
43310
+ for (const prop of props) if (prop.startsWith(prefix)) return true;
43311
+ return false;
43312
+ }
43313
+ function hasBorderResetOverlap(props, side) {
43314
+ const sidePrefix = side ? `border${side.charAt(0).toUpperCase()}${side.slice(1)}` : "border";
43315
+ for (const prop of props) {
43316
+ if (!/^border(?:Top|Right|Bottom|Left)?(?:Width|Style|Color)$/.test(prop)) continue;
43317
+ if (!side || prop.startsWith(sidePrefix) || /^border(?:Width|Style|Color)$/.test(prop)) return true;
43318
+ }
43319
+ return false;
43320
+ }
41541
43321
  /**
41542
43322
  * If any variant `when` condition references the styled-components theme object,
41543
43323
  * mark the declaration as needing the `useTheme()` hook so the emitted wrapper
@@ -42109,7 +43889,7 @@ function findFirst(collection, predicate) {
42109
43889
  //#endregion
42110
43890
  //#region src/internal/lower-rules/process-rule-declarations.ts
42111
43891
  function processRuleDeclarations(args) {
42112
- const { ctx, rule, allRules, media, pseudos, pseudoElement, attrTarget, resolvedSelectorMedia, applyResolvedPropValue } = args;
43892
+ const { ctx, rule, allRules, media, pseudos, pseudoElement, attrTarget, resolvedSelectorMedia, hasAncestorAttributeScope, applyResolvedPropValue } = args;
42113
43893
  const { state } = ctx;
42114
43894
  for (const d of rule.declarations) {
42115
43895
  ctx.setCurrentDeclarationSourceOrder(d.sourceOrder);
@@ -42122,6 +43902,12 @@ function processRuleDeclarations(args) {
42122
43902
  d.property = resolvedProperty;
42123
43903
  }
42124
43904
  if (d.value.kind === "interpolated") {
43905
+ if (d.property && isLogicalScrollAxisShorthand(d.property)) {
43906
+ state.bailUnsupported(ctx.decl, "Dynamic logical scroll shorthand cannot be expanded — bind a specific longhand (e.g. scroll-padding-inline-start) instead");
43907
+ if (state.currentDecl === ctx.decl) continue;
43908
+ state.bail = true;
43909
+ break;
43910
+ }
42125
43911
  handleInterpolatedDeclaration({
42126
43912
  ctx,
42127
43913
  rule,
@@ -42132,6 +43918,7 @@ function processRuleDeclarations(args) {
42132
43918
  pseudoElement,
42133
43919
  attrTarget,
42134
43920
  resolvedSelectorMedia,
43921
+ hasAncestorAttributeScope,
42135
43922
  applyResolvedPropValue
42136
43923
  });
42137
43924
  if (state.bail) break;
@@ -42167,6 +43954,20 @@ function processRuleDeclarations(args) {
42167
43954
  }
42168
43955
  }
42169
43956
  if (d.property === "background" && isUnsupportedBackgroundShorthandValue(d.valueRaw)) {
43957
+ const expanded = d.value.kind === "static" && !d.important && !hasOtherBackgroundDeclaration(allRules, d) ? expandBackgroundShorthandComponents(d.valueRaw) : null;
43958
+ if (expanded) {
43959
+ const commentSource = {
43960
+ leading: d.leadingComment,
43961
+ leadingLine: d.leadingLineComment,
43962
+ trailingLine: d.trailingLineComment
43963
+ };
43964
+ let isFirst = true;
43965
+ for (const { prop, value } of expanded) {
43966
+ applyResolvedPropValue(prop, value, isFirst ? commentSource : null, d.property);
43967
+ isFirst = false;
43968
+ }
43969
+ continue;
43970
+ }
42170
43971
  state.bailUnsupported(ctx.decl, "Unsupported background shorthand: multiple components cannot be mapped to a single StyleX longhand");
42171
43972
  if (state.currentDecl === ctx.decl) break;
42172
43973
  state.bail = true;
@@ -42221,10 +44022,23 @@ function resolveInterpolatedPropertyName(property, ctx) {
42221
44022
  if (!resolved.startsWith("--")) return null;
42222
44023
  return resolved;
42223
44024
  }
44025
+ /**
44026
+ * True when any declaration other than `current` (across all of the component's
44027
+ * rules) targets a `background`/`background-*` property. A multi-component
44028
+ * background expansion only reproduces reset semantics in isolation, so the
44029
+ * presence of a sibling background declaration makes the expansion unsafe.
44030
+ */
44031
+ function hasOtherBackgroundDeclaration(allRules, current) {
44032
+ for (const rule of allRules) for (const declaration of rule.declarations) {
44033
+ if (declaration === current) continue;
44034
+ if (declaration.property && /^background(-|$)/.test(declaration.property)) return true;
44035
+ }
44036
+ return false;
44037
+ }
42224
44038
  //#endregion
42225
44039
  //#region src/internal/lower-rules/process-rules.ts
42226
44040
  function processDeclRules(ctx) {
42227
- const { state, decl, styleObj, perPropPseudo, perPropMedia, nestedSelectors, variantBuckets, styleFnDecls, attrBuckets, localVarValues, cssHelperPropValues, getComposedDefaultValue } = ctx;
44041
+ const { state, decl, styleObj, perPropPseudo, perPropMedia, nestedSelectors, variantBuckets, extraStyleObjects, styleFnDecls, attrBuckets, localVarValues, cssHelperPropValues, getComposedDefaultValue } = ctx;
42228
44042
  const { j, root, warnings, resolverImports, resolveSelector, parseExpr, cssHelperNames, declByLocalName, relationOverridePseudoBuckets, relationOverrides, ancestorSelectorParents, resolveThemeValue, resolveThemeValueFromFn, resolveImportInScope } = state;
42229
44043
  const getConditionDefaultValue = (propName) => cssHelperPropValues.has(propName) ? getComposedDefaultValue(propName) : ctx.getWrappedComponentBaseDefaultValue(propName) ?? null;
42230
44044
  /**
@@ -42864,6 +44678,73 @@ function processDeclRules(ctx) {
42864
44678
  for (const bucket of variantBuckets.values()) if (Object.hasOwn(bucket, prop)) wrapStyleConditionValue(bucket, prop, conditionKey, conditionValue);
42865
44679
  patchStyleFnConditionValue(prop, conditionKey, conditionValue);
42866
44680
  };
44681
+ /**
44682
+ * A base-scope declaration later in the CSS overrides any earlier conditional
44683
+ * assignment of the same property — within one styled template the generated
44684
+ * class contains both declarations, and the last one wins regardless of the
44685
+ * runtime condition. Drop the dead base-scope value from earlier variant
44686
+ * buckets so the emitted variant (applied after the base style in
44687
+ * stylex.props) cannot incorrectly win. Condition-scoped values (pseudo/media
44688
+ * maps) only lose their `default` layer.
44689
+ *
44690
+ * Exception: an earlier `!important` conditional value still wins over a later
44691
+ * non-important base declaration in the CSS cascade, so it must be preserved.
44692
+ * (When the later base is itself `!important`, source order decides and the
44693
+ * later one wins, so clearing is correct.)
44694
+ */
44695
+ const clearEarlierVariantBaseValues = (prop, laterBaseValue) => {
44696
+ const laterBaseIsImportant = cssValueIsImportant(laterBaseValue);
44697
+ for (const [when, bucket] of variantBuckets) {
44698
+ if (!Object.hasOwn(bucket, prop)) continue;
44699
+ const bucketValue = bucket[prop];
44700
+ if (bucketValue !== null && typeof bucketValue === "object" && !isAstNode$1(bucketValue) && "default" in bucketValue) {
44701
+ const conditionDefault = bucketValue.default;
44702
+ if (!laterBaseIsImportant && cssValueIsImportant(conditionDefault)) continue;
44703
+ bucketValue.default = null;
44704
+ continue;
44705
+ }
44706
+ if (!laterBaseIsImportant && cssValueIsImportant(bucketValue)) continue;
44707
+ delete bucket[prop];
44708
+ if (Object.keys(bucket).length === 0) {
44709
+ variantBuckets.delete(when);
44710
+ delete ctx.variantStyleKeys[when];
44711
+ delete ctx.variantSourceOrder[when];
44712
+ }
44713
+ }
44714
+ };
44715
+ const clearEarlierThemeBaseValues = (prop, laterBaseValue, sourceCssProperty) => {
44716
+ const hooks = decl.needsUseThemeHook;
44717
+ if (!hooks?.length) return;
44718
+ const propsToClear = sourceCssProperty === "background" ? ["backgroundColor", "backgroundImage"] : [prop];
44719
+ const laterBaseIsImportant = cssValueIsImportant(laterBaseValue);
44720
+ const clearHookStyleKey = (hook, side) => {
44721
+ const styleKey = hook[side];
44722
+ if (!styleKey) return false;
44723
+ const bucket = extraStyleObjects.get(styleKey);
44724
+ if (!bucket) return false;
44725
+ let changed = false;
44726
+ for (const propToClear of propsToClear) {
44727
+ if (!Object.hasOwn(bucket, propToClear)) continue;
44728
+ const bucketValue = bucket[propToClear];
44729
+ if (!laterBaseIsImportant && cssValueIsImportant(bucketValue)) continue;
44730
+ delete bucket[propToClear];
44731
+ changed = true;
44732
+ }
44733
+ if (!changed) return false;
44734
+ if (Object.keys(bucket).length === 0) {
44735
+ extraStyleObjects.delete(styleKey);
44736
+ hook[side] = null;
44737
+ }
44738
+ return true;
44739
+ };
44740
+ for (let i = hooks.length - 1; i >= 0; i--) {
44741
+ const hook = hooks[i];
44742
+ const hadStyleKeys = Boolean(hook.trueStyleKey || hook.falseStyleKey);
44743
+ const clearedTrue = clearHookStyleKey(hook, "trueStyleKey");
44744
+ const clearedFalse = clearHookStyleKey(hook, "falseStyleKey");
44745
+ if ((clearedTrue || clearedFalse) && hadStyleKeys && !hook.trueStyleKey && !hook.falseStyleKey) hooks.splice(i, 1);
44746
+ }
44747
+ };
42867
44748
  const applyResolvedPropValue = (prop, value, commentSource, sourceCssProperty) => {
42868
44749
  const noteSourceCssProperty = (target) => {
42869
44750
  if (sourceCssProperty) {
@@ -43078,6 +44959,8 @@ function processDeclRules(ctx) {
43078
44959
  }
43079
44960
  return;
43080
44961
  }
44962
+ clearEarlierVariantBaseValues(prop, value);
44963
+ clearEarlierThemeBaseValues(prop, value, sourceCssProperty);
43081
44964
  const target = ctx.getBaseStyleTarget();
43082
44965
  setStyleObjectValue(target, prop, value);
43083
44966
  noteSourceCssProperty(target);
@@ -43096,6 +44979,7 @@ function processDeclRules(ctx) {
43096
44979
  pseudoElement: pseudoElement ?? (pseudoElementsList ? pseudoElementsList[0] ?? null : null),
43097
44980
  attrTarget,
43098
44981
  resolvedSelectorMedia,
44982
+ hasAncestorAttributeScope: Boolean(ancestorAttrs?.length),
43099
44983
  applyResolvedPropValue
43100
44984
  });
43101
44985
  if (state.bail) break;
@@ -43608,7 +45492,9 @@ function recoverStandaloneInterpolationsInPseudoBlock(rule, decl) {
43608
45492
  }
43609
45493
  /** Negates a `when` condition string (e.g. `$active` → `!$active`, `!$x` → `$x`). */
43610
45494
  function negateWhen(when) {
45495
+ if (when.startsWith("!(") && when.endsWith(")")) return when.slice(2, -1);
43611
45496
  if (when.startsWith("!")) return when.slice(1);
45497
+ if (when.includes(" || ") || when.includes(" && ")) return `!(${when})`;
43612
45498
  if (when.includes(" === ")) return when.replace(" === ", " !== ");
43613
45499
  if (when.includes(" !== ")) return when.replace(" !== ", " === ");
43614
45500
  return `!${when}`;
@@ -44092,6 +45978,7 @@ function createLowerRulesState(ctx) {
44092
45978
  const resolveValueDirectional = ctx.resolveValueDirectionalSafe;
44093
45979
  const resolveCall = ctx.resolveCallSafe;
44094
45980
  const resolveValueOptional = (rvCtx) => {
45981
+ if (rvCtx.kind === "importedValue" && isStylexFileSource(rvCtx.source)) return resolveValue(rvCtx);
44095
45982
  const res = ctx.adapter.resolveValue(rvCtx);
44096
45983
  if (res && isDirectionalResult(res)) return;
44097
45984
  return res;
@@ -44158,6 +46045,30 @@ function createLowerRulesState(ctx) {
44158
46045
  }
44159
46046
  };
44160
46047
  const staticPropertyValues = /* @__PURE__ */ new Map();
46048
+ const staticIdentifierValues = /* @__PURE__ */ new Map();
46049
+ root.find(j.VariableDeclarator).forEach((p) => {
46050
+ if (!isTopLevelConstDeclarator(p)) return;
46051
+ const node = p.node;
46052
+ if (node.id?.type !== "Identifier" || !node.id.name) return;
46053
+ const staticValue = literalToStaticValue(node.init, { allowStaticArrowFunctions: false });
46054
+ if (staticValue !== null) staticIdentifierValues.set(node.id.name, staticValue);
46055
+ });
46056
+ if (staticIdentifierValues.size > 0) {
46057
+ const shadowingNames = /* @__PURE__ */ new Set();
46058
+ root.find(j.Function).forEach((fnPath) => {
46059
+ collectPatternBindingNames$2(fnPath.node.params, shadowingNames);
46060
+ const fnId = fnPath.node.id;
46061
+ if (fnId?.name) shadowingNames.add(fnId.name);
46062
+ });
46063
+ root.find(j.ClassDeclaration).forEach((classPath) => {
46064
+ const classId = classPath.node.id;
46065
+ if (classId?.name) shadowingNames.add(classId.name);
46066
+ });
46067
+ root.find(j.VariableDeclarator).forEach((declPath) => {
46068
+ if (!isTopLevelConstDeclarator(declPath)) collectPatternBindingNames$2(declPath.node.id, shadowingNames);
46069
+ });
46070
+ for (const name of shadowingNames) staticIdentifierValues.delete(name);
46071
+ }
44161
46072
  root.find(j.ExpressionStatement, { expression: {
44162
46073
  type: "AssignmentExpression",
44163
46074
  operator: "=",
@@ -44171,7 +46082,7 @@ function createLowerRulesState(ctx) {
44171
46082
  const ownerName = expr.left?.object?.name;
44172
46083
  const propName = expr.left?.property?.name;
44173
46084
  if (ownerName && propName) {
44174
- const staticValue = literalToStaticValue(expr.right);
46085
+ const staticValue = literalToStaticValue(expr.right, { allowStaticArrowFunctions: false });
44175
46086
  let ownerMap = staticPropertyValues.get(ownerName);
44176
46087
  if (!ownerMap) {
44177
46088
  ownerMap = /* @__PURE__ */ new Map();
@@ -44267,6 +46178,7 @@ function createLowerRulesState(ctx) {
44267
46178
  cssHelperValuesByKey,
44268
46179
  mixinValuesByKey,
44269
46180
  staticPropertyValues,
46181
+ staticIdentifierValues,
44270
46182
  usedCssHelperFunctions: /* @__PURE__ */ new Set(),
44271
46183
  warnPropInlineStyle,
44272
46184
  applyCssHelperMixin,
@@ -44353,6 +46265,20 @@ function clonePropUsageByComponent(source) {
44353
46265
  });
44354
46266
  return cloned;
44355
46267
  }
46268
+ function isTopLevelConstDeclarator(path) {
46269
+ const declarationPath = path.parentPath;
46270
+ if (!declarationPath) return false;
46271
+ const declaration = declarationPath?.node;
46272
+ if (declaration?.type !== "VariableDeclaration" || declaration.kind !== "const") return false;
46273
+ let current = declarationPath.parentPath;
46274
+ while (current?.node) {
46275
+ const type = current.node.type;
46276
+ if (type === "Program") return true;
46277
+ if (type !== "VariableDeclaration" && type !== "ExportNamedDeclaration") return false;
46278
+ current = current.parentPath;
46279
+ }
46280
+ return false;
46281
+ }
44356
46282
  function collectOpeningPropUsage(attributes) {
44357
46283
  const props = {};
44358
46284
  let hasSpread = false;
@@ -44382,6 +46308,10 @@ function getJsxIdentifierName(node) {
44382
46308
  const record = node;
44383
46309
  return record.type === "JSXIdentifier" && typeof record.name === "string" ? record.name : null;
44384
46310
  }
46311
+ const STYLEX_FILE_RE = /\.stylex(\.\w+)?$/;
46312
+ function isStylexFileSource(source) {
46313
+ return STYLEX_FILE_RE.test(source.value);
46314
+ }
44385
46315
  //#endregion
44386
46316
  //#region src/internal/transform-steps/lower-rules.ts
44387
46317
  /**
@@ -46095,6 +48025,10 @@ function wrappedComponentAcceptsSxProp(ctx, componentLocalName, visiting = /* @_
46095
48025
  visiting.delete(componentLocalName);
46096
48026
  return true;
46097
48027
  }
48028
+ if (localStyledDecl?.needsWrapperComponent && !localStyledDecl.skipTransform && localStyledDecl.supportsExternalStyles) {
48029
+ visiting.delete(componentLocalName);
48030
+ return true;
48031
+ }
46098
48032
  const componentInterface = wrappedComponentInterfaceFor(ctx, componentLocalName);
46099
48033
  if (componentInterface !== void 0) {
46100
48034
  visiting.delete(componentLocalName);
@@ -46342,8 +48276,9 @@ function rewriteJsxStep(ctx) {
46342
48276
  const mergeArgs = matchedCombinedStyleKey ? void 0 : opening.__promotedMergeArgs;
46343
48277
  const baseMember = j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(baseStyleKey));
46344
48278
  const baseExpr = mergeArgs ? j.callExpression(baseMember, mergeArgs) : baseMember;
48279
+ const rendersLocalWrapperBase = decl.base.kind === "component" && decl.base.ident === finalTag && (ctx.styledDecls?.some((d) => d.localName === finalTag && d.needsWrapperComponent && !d.skipTransform) ?? false);
46345
48280
  const styleArgs = [
46346
- ...decl.extendsStyleKey ? [j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(decl.extendsStyleKey))] : [],
48281
+ ...decl.extendsStyleKey && !rendersLocalWrapperBase ? [j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(decl.extendsStyleKey))] : [],
46347
48282
  ...extraMixinArgs,
46348
48283
  ...decl.skipBaseStyleRef ? [] : [baseExpr],
46349
48284
  ...extraAfterBaseArgs
@@ -47089,6 +49024,43 @@ function upgradePolymorphicAsPropTypesStep(ctx) {
47089
49024
  return CONTINUE;
47090
49025
  }
47091
49026
  //#endregion
49027
+ //#region src/internal/transform-steps/warn-partial-migration-incomplete.ts
49028
+ /**
49029
+ * Step: warn when partial migration leaves styled-components declarations behind.
49030
+ * Core concepts: partial migration diagnostics and converted declaration accounting.
49031
+ */
49032
+ function warnPartialMigrationIncompleteStep(ctx) {
49033
+ if (!shouldWarnForPartialMigration(ctx)) return CONTINUE;
49034
+ const skippedDecls = collectSkippedStyledDeclarations(ctx.styledDecls);
49035
+ const convertedDecls = collectConvertedStyleDeclarations(ctx.styledDecls);
49036
+ if (skippedDecls.length === 0 || convertedDecls.length === 0) return CONTINUE;
49037
+ ctx.warnings.push({
49038
+ severity: "warning",
49039
+ type: PARTIAL_MIGRATION_INCOMPLETE_WARNING,
49040
+ loc: skippedDecls[0]?.loc,
49041
+ context: {
49042
+ skippedDeclarationCount: skippedDecls.length,
49043
+ skippedDeclarations: declarationNames(skippedDecls),
49044
+ convertedDeclarationCount: convertedDecls.length,
49045
+ convertedDeclarations: declarationNames(convertedDecls)
49046
+ }
49047
+ });
49048
+ return CONTINUE;
49049
+ }
49050
+ const MAX_PARTIAL_MIGRATION_WARNING_NAMES = 20;
49051
+ function shouldWarnForPartialMigration(ctx) {
49052
+ return ctx.hasChanges && ctx.options.allowPartialMigration === true && ctx.options.transformMode !== "leavesOnly";
49053
+ }
49054
+ function collectSkippedStyledDeclarations(styledDecls) {
49055
+ return styledDecls?.filter((decl) => decl.skipTransform && !decl.isCssHelper && !decl.isDirectJsxResolution) ?? [];
49056
+ }
49057
+ function collectConvertedStyleDeclarations(styledDecls) {
49058
+ return styledDecls?.filter((decl) => !decl.skipTransform && !decl.isCssHelper) ?? [];
49059
+ }
49060
+ function declarationNames(decls) {
49061
+ return decls.slice(0, MAX_PARTIAL_MIGRATION_WARNING_NAMES).map((decl) => decl.localName);
49062
+ }
49063
+ //#endregion
47092
49064
  //#region src/transform.ts
47093
49065
  /**
47094
49066
  * Transform styled-components to StyleX
@@ -47098,8 +49070,9 @@ function upgradePolymorphicAsPropTypesStep(ctx) {
47098
49070
  */
47099
49071
  function transform(file, api, options) {
47100
49072
  try {
47101
- const result = transformWithWarnings(file, api, options);
47102
- Logger.logWarnings(result.warnings, file.path);
49073
+ const transformOptions = options;
49074
+ const result = transformWithWarnings(file, api, transformOptions);
49075
+ Logger.logWarnings(result.warnings, file.path, { silent: transformOptions.silent === true });
47103
49076
  if (result.sidecarFiles && result.sidecarFiles.length > 0) {
47104
49077
  const sidecarFilesMap = options.sidecarFiles;
47105
49078
  if (sidecarFilesMap) {
@@ -47147,6 +49120,7 @@ function transformWithWarnings(file, api, options) {
47147
49120
  extractCssHelpersStep,
47148
49121
  detectStringMappingFnsStep,
47149
49122
  collectStyledDeclsStep,
49123
+ inlinePropConditionalCssHelpersStep,
47150
49124
  resolveBaseComponentsStep,
47151
49125
  applyLeavesOnlyPolicyStep,
47152
49126
  markPartialImportedRootsStep,
@@ -47169,7 +49143,8 @@ function transformWithWarnings(file, api, options) {
47169
49143
  reinsertStaticPropsStep,
47170
49144
  postProcessStep,
47171
49145
  cleanupCssImportStep,
47172
- ensureReactImportStep
49146
+ ensureReactImportStep,
49147
+ warnPartialMigrationIncompleteStep
47173
49148
  ];
47174
49149
  for (const step of pipeline) {
47175
49150
  const outcome = step(ctx);