@drskillissue/ganko 0.2.61 → 0.2.72

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.
@@ -67,9 +67,29 @@ function canonicalPath(path) {
67
67
  return canonical;
68
68
  }
69
69
  var LOG_LEVELS = ["trace", "debug", "info", "warning", "error", "critical", "off"];
70
+ var Level = {
71
+ Trace: 0,
72
+ Debug: 1,
73
+ Info: 2,
74
+ Warning: 3,
75
+ Error: 4,
76
+ Critical: 5,
77
+ Off: 6
78
+ };
79
+ var LOG_LEVEL_ORDER = {
80
+ trace: Level.Trace,
81
+ debug: Level.Debug,
82
+ info: Level.Info,
83
+ warning: Level.Warning,
84
+ error: Level.Error,
85
+ critical: Level.Critical,
86
+ off: Level.Off
87
+ };
70
88
  var noopLogger = {
71
- enabled: false,
72
89
  level: "off",
90
+ isLevelEnabled() {
91
+ return false;
92
+ },
73
93
  trace() {
74
94
  },
75
95
  debug() {
@@ -3995,6 +4015,7 @@ function getStaticStringFromJSXValue(node) {
3995
4015
  const expression = node.expression;
3996
4016
  if (!expression) return null;
3997
4017
  if (ts7.isStringLiteral(expression)) return expression.text;
4018
+ if (ts7.isNumericLiteral(expression)) return expression.text;
3998
4019
  if (ts7.isNoSubstitutionTemplateLiteral(expression)) return expression.text;
3999
4020
  if (ts7.isTemplateExpression(expression) && expression.templateSpans.length === 0) {
4000
4021
  return expression.head.text;
@@ -4893,6 +4914,9 @@ function typeIncludesString(graph, node) {
4893
4914
  function typeIsArray(graph, node) {
4894
4915
  return graph.typeResolver.isArrayType(node);
4895
4916
  }
4917
+ function typeIsStrictArray(graph, node) {
4918
+ return graph.typeResolver.isStrictArrayType(node);
4919
+ }
4896
4920
  function getArrayElementKind(graph, node) {
4897
4921
  return graph.typeResolver.getArrayElementKind(node);
4898
4922
  }
@@ -15167,6 +15191,7 @@ var preferSetLookupInLoop = defineSolidRule({
15167
15191
  options: options77,
15168
15192
  check(graph, emit) {
15169
15193
  const reported = /* @__PURE__ */ new Set();
15194
+ const graphHasTypes = hasTypeInfo(graph);
15170
15195
  for (const method of LINEAR_SEARCH_METHODS) {
15171
15196
  const calls = getCallsByMethodName(graph, method);
15172
15197
  for (let i = 0, len = calls.length; i < len; i++) {
@@ -15184,6 +15209,7 @@ var preferSetLookupInLoop = defineSolidRule({
15184
15209
  const loop = getEnclosingLoop(call.node);
15185
15210
  if (!loop) continue;
15186
15211
  if (!isDeclaredOutsideLoop2(loop, variable)) continue;
15212
+ if (graphHasTypes && !typeIsStrictArray(graph, callee.expression)) continue;
15187
15213
  if (isStringLikeReceiver(graph, callee.expression, variable)) continue;
15188
15214
  const key = `${loop.pos}:var:${variable.id}`;
15189
15215
  if (reported.has(key)) continue;
@@ -18271,6 +18297,35 @@ var TypeResolver = class {
18271
18297
  return false;
18272
18298
  }
18273
18299
  }
18300
+ /**
18301
+ * Strict array check: only matches Array<T>, T[], ReadonlyArray<T>, and tuples.
18302
+ * Does NOT match typed arrays (Uint8Array, Buffer, etc.) or other types with
18303
+ * a numeric index signature.
18304
+ */
18305
+ isStrictArrayType(node) {
18306
+ try {
18307
+ const tsType = this.checker.getTypeAtLocation(node);
18308
+ return this.checkIsStrictArrayType(tsType);
18309
+ } catch {
18310
+ return false;
18311
+ }
18312
+ }
18313
+ checkIsStrictArrayType(tsType) {
18314
+ if (tsType.flags & 524288) {
18315
+ const objFlags = getObjectFlags(tsType);
18316
+ if (objFlags & 8) return true;
18317
+ if (objFlags & 4) {
18318
+ const name = tsType.getSymbol()?.getName();
18319
+ if (name === "Array" || name === "ReadonlyArray") return true;
18320
+ }
18321
+ }
18322
+ if (tsType.isUnion()) {
18323
+ for (const t of tsType.types) {
18324
+ if (this.checkIsStrictArrayType(t)) return true;
18325
+ }
18326
+ }
18327
+ return false;
18328
+ }
18274
18329
  checkIsArrayType(tsType) {
18275
18330
  if (tsType.flags & 524288) {
18276
18331
  const objFlags = getObjectFlags(tsType);
@@ -18322,7 +18377,7 @@ var TypeResolver = class {
18322
18377
  if (exprTsType.flags & ts101.TypeFlags.Any) return false;
18323
18378
  if (targetTsType.flags & ts101.TypeFlags.Any) return false;
18324
18379
  const result = this.checker.isTypeAssignableTo(exprTsType, targetTsType);
18325
- if (this.logger.enabled) {
18380
+ if (this.logger.isLevelEnabled(Level.Debug)) {
18326
18381
  const exprStr = this.checker.typeToString(exprTsType);
18327
18382
  const targetStr = this.checker.typeToString(targetTsType);
18328
18383
  this.logger.debug(`isUnnecessaryCast: expr="${exprStr.slice(0, 120)}" target="${targetStr.slice(0, 120)}" assignable=${result} exprFlags=${exprTsType.flags} targetFlags=${targetTsType.flags}`);
@@ -25205,148 +25260,8 @@ function checkParagraphSpacing(graph, emit, policy, name) {
25205
25260
  }
25206
25261
  }
25207
25262
 
25208
- // src/css/rules/a11y/css-policy-touch-target.ts
25209
- var messages125 = {
25210
- heightTooSmall: "`{{property}}` of `{{value}}` ({{resolved}}px) is below the minimum `{{min}}px` for `{{element}}` elements in policy `{{policy}}`.",
25211
- widthTooSmall: "`{{property}}` of `{{value}}` ({{resolved}}px) is below the minimum `{{min}}px` for `{{element}}` elements in policy `{{policy}}`.",
25212
- paddingTooSmall: "Horizontal padding `{{value}}` ({{resolved}}px) is below the minimum `{{min}}px` for `{{element}}` elements in policy `{{policy}}`."
25213
- };
25214
- function classifyRule(rule) {
25215
- if (rule.elementKinds.has("button")) return "button";
25216
- if (rule.elementKinds.has("input")) return "input";
25217
- return null;
25218
- }
25219
- var HEIGHT_PROPERTIES = /* @__PURE__ */ new Set(["height", "min-height"]);
25220
- var WIDTH_PROPERTIES = /* @__PURE__ */ new Set(["width", "min-width"]);
25221
- var HPADDING_PROPERTIES = /* @__PURE__ */ new Set(["padding-left", "padding-right", "padding-inline", "padding-inline-start", "padding-inline-end"]);
25222
- var cssPolicyTouchTarget = defineCSSRule({
25223
- id: "css-policy-touch-target",
25224
- severity: "warn",
25225
- messages: messages125,
25226
- meta: {
25227
- description: "Enforce minimum interactive element sizes per accessibility policy.",
25228
- fixable: false,
25229
- category: "css-a11y"
25230
- },
25231
- options: {},
25232
- check(graph, emit) {
25233
- const policy = getActivePolicy();
25234
- if (policy === null) return;
25235
- const name = getActivePolicyName() ?? "";
25236
- const decls = graph.declarationsForProperties(
25237
- "height",
25238
- "min-height",
25239
- "width",
25240
- "min-width",
25241
- "padding-left",
25242
- "padding-right",
25243
- "padding-inline",
25244
- "padding-inline-start",
25245
- "padding-inline-end"
25246
- );
25247
- for (let i = 0; i < decls.length; i++) {
25248
- const d = decls[i];
25249
- if (!d) continue;
25250
- if (!d.rule) continue;
25251
- const prop = d.property.toLowerCase();
25252
- const kind = classifyRule(d.rule);
25253
- if (!kind) continue;
25254
- if (isVisuallyHiddenInput(d.rule)) continue;
25255
- const px = parsePxValue(d.value);
25256
- if (px === null) continue;
25257
- if (HEIGHT_PROPERTIES.has(prop)) {
25258
- const min = kind === "button" ? policy.minButtonHeight : policy.minInputHeight;
25259
- if (px >= min) continue;
25260
- emitCSSDiagnostic(
25261
- emit,
25262
- d.file.path,
25263
- d.startLine,
25264
- d.startColumn,
25265
- cssPolicyTouchTarget,
25266
- "heightTooSmall",
25267
- resolveMessage(messages125.heightTooSmall, {
25268
- property: d.property,
25269
- value: d.value.trim(),
25270
- resolved: String(Math.round(px * 100) / 100),
25271
- min: String(min),
25272
- element: kind,
25273
- policy: name
25274
- })
25275
- );
25276
- continue;
25277
- }
25278
- if (WIDTH_PROPERTIES.has(prop)) {
25279
- const min = kind === "button" ? policy.minButtonWidth : policy.minTouchTarget;
25280
- if (px >= min) continue;
25281
- emitCSSDiagnostic(
25282
- emit,
25283
- d.file.path,
25284
- d.startLine,
25285
- d.startColumn,
25286
- cssPolicyTouchTarget,
25287
- "widthTooSmall",
25288
- resolveMessage(messages125.widthTooSmall, {
25289
- property: d.property,
25290
- value: d.value.trim(),
25291
- resolved: String(Math.round(px * 100) / 100),
25292
- min: String(min),
25293
- element: kind,
25294
- policy: name
25295
- })
25296
- );
25297
- continue;
25298
- }
25299
- if (kind === "button" && HPADDING_PROPERTIES.has(prop)) {
25300
- if (px >= policy.minButtonHorizontalPadding) continue;
25301
- emitCSSDiagnostic(
25302
- emit,
25303
- d.file.path,
25304
- d.startLine,
25305
- d.startColumn,
25306
- cssPolicyTouchTarget,
25307
- "paddingTooSmall",
25308
- resolveMessage(messages125.paddingTooSmall, {
25309
- value: d.value.trim(),
25310
- resolved: String(Math.round(px * 100) / 100),
25311
- min: String(policy.minButtonHorizontalPadding),
25312
- element: kind,
25313
- policy: name
25314
- })
25315
- );
25316
- }
25317
- }
25318
- }
25319
- });
25320
- function isVisuallyHiddenInput(rule) {
25321
- if (!hasPositionAbsoluteOrFixed(rule)) return false;
25322
- if (!hasOpacityZero(rule)) return false;
25323
- return true;
25324
- }
25325
- function hasPositionAbsoluteOrFixed(rule) {
25326
- const positionDecls = rule.declarationIndex.get("position");
25327
- if (!positionDecls || positionDecls.length === 0) return false;
25328
- for (let i = 0; i < positionDecls.length; i++) {
25329
- const decl = positionDecls[i];
25330
- if (!decl) continue;
25331
- const v = decl.value.trim().toLowerCase();
25332
- if (v === "absolute" || v === "fixed") return true;
25333
- }
25334
- return false;
25335
- }
25336
- function hasOpacityZero(rule) {
25337
- const opacityDecls = rule.declarationIndex.get("opacity");
25338
- if (!opacityDecls || opacityDecls.length === 0) return false;
25339
- for (let i = 0; i < opacityDecls.length; i++) {
25340
- const decl = opacityDecls[i];
25341
- if (!decl) continue;
25342
- const v = decl.value.trim();
25343
- if (v === "0") return true;
25344
- }
25345
- return false;
25346
- }
25347
-
25348
25263
  // src/css/rules/a11y/css-policy-typography.ts
25349
- var messages126 = {
25264
+ var messages125 = {
25350
25265
  fontTooSmall: "Font size `{{value}}` ({{resolved}}px) is below the `{{context}}` minimum of `{{min}}px` for policy `{{policy}}`.",
25351
25266
  lineHeightTooSmall: "Line height `{{value}}` is below the `{{context}}` minimum of `{{min}}` for policy `{{policy}}`."
25352
25267
  };
@@ -25382,7 +25297,7 @@ function resolveLineHeightContext(d, p) {
25382
25297
  var cssPolicyTypography = defineCSSRule({
25383
25298
  id: "css-policy-typography",
25384
25299
  severity: "warn",
25385
- messages: messages126,
25300
+ messages: messages125,
25386
25301
  meta: {
25387
25302
  description: "Enforce minimum font sizes and line heights per accessibility policy.",
25388
25303
  fixable: false,
@@ -25409,7 +25324,7 @@ var cssPolicyTypography = defineCSSRule({
25409
25324
  d.startColumn,
25410
25325
  cssPolicyTypography,
25411
25326
  "fontTooSmall",
25412
- resolveMessage(messages126.fontTooSmall, {
25327
+ resolveMessage(messages125.fontTooSmall, {
25413
25328
  value: d.value.trim(),
25414
25329
  resolved: String(Math.round(px * 100) / 100),
25415
25330
  context,
@@ -25436,7 +25351,7 @@ var cssPolicyTypography = defineCSSRule({
25436
25351
  d.startColumn,
25437
25352
  cssPolicyTypography,
25438
25353
  "lineHeightTooSmall",
25439
- resolveMessage(messages126.lineHeightTooSmall, {
25354
+ resolveMessage(messages125.lineHeightTooSmall, {
25440
25355
  value: d.value.trim(),
25441
25356
  context,
25442
25357
  min: String(min),
@@ -25454,7 +25369,7 @@ var ZERO_S = /(^|\s|,)0s($|\s|,)/;
25454
25369
  var TIME_VALUE_G = /([0-9]*\.?[0-9]+)(ms|s)/g;
25455
25370
  var AMPERSAND_G = /&/g;
25456
25371
  var WHITESPACE_G = /\s+/g;
25457
- var messages127 = {
25372
+ var messages126 = {
25458
25373
  missingReducedMotion: "Animated selector `{{selector}}` lacks prefers-reduced-motion override."
25459
25374
  };
25460
25375
  function isAnimationDecl(p) {
@@ -25558,7 +25473,7 @@ function normalizeSelector(s) {
25558
25473
  var cssRequireReducedMotionOverride = defineCSSRule({
25559
25474
  id: "css-require-reduced-motion-override",
25560
25475
  severity: "warn",
25561
- messages: messages127,
25476
+ messages: messages126,
25562
25477
  meta: {
25563
25478
  description: "Require reduced-motion override for animated selectors.",
25564
25479
  fixable: false,
@@ -25621,20 +25536,20 @@ var cssRequireReducedMotionOverride = defineCSSRule({
25621
25536
  d.startColumn,
25622
25537
  cssRequireReducedMotionOverride,
25623
25538
  "missingReducedMotion",
25624
- resolveMessage(messages127.missingReducedMotion, { selector: r.selectorText })
25539
+ resolveMessage(messages126.missingReducedMotion, { selector: r.selectorText })
25625
25540
  );
25626
25541
  }
25627
25542
  }
25628
25543
  });
25629
25544
 
25630
25545
  // src/css/rules/structure/css-no-empty-rule.ts
25631
- var messages128 = {
25546
+ var messages127 = {
25632
25547
  emptyRule: "Empty rule `{{selector}}` should be removed."
25633
25548
  };
25634
25549
  var cssNoEmptyRule = defineCSSRule({
25635
25550
  id: "css-no-empty-rule",
25636
25551
  severity: "warn",
25637
- messages: messages128,
25552
+ messages: messages127,
25638
25553
  meta: {
25639
25554
  description: "Disallow empty CSS rules.",
25640
25555
  fixable: false,
@@ -25652,20 +25567,20 @@ var cssNoEmptyRule = defineCSSRule({
25652
25567
  rule.startColumn,
25653
25568
  cssNoEmptyRule,
25654
25569
  "emptyRule",
25655
- resolveMessage(messages128.emptyRule, { selector: rule.selectorText })
25570
+ resolveMessage(messages127.emptyRule, { selector: rule.selectorText })
25656
25571
  );
25657
25572
  }
25658
25573
  }
25659
25574
  });
25660
25575
 
25661
25576
  // src/css/rules/structure/css-no-unknown-container-name.ts
25662
- var messages129 = {
25577
+ var messages128 = {
25663
25578
  unknownContainer: "Unknown container name `{{name}}` in @container query."
25664
25579
  };
25665
25580
  var cssNoUnknownContainerName = defineCSSRule({
25666
25581
  id: "css-no-unknown-container-name",
25667
25582
  severity: "error",
25668
- messages: messages129,
25583
+ messages: messages128,
25669
25584
  meta: {
25670
25585
  description: "Disallow unknown named containers in @container queries.",
25671
25586
  fixable: false,
@@ -25685,20 +25600,20 @@ var cssNoUnknownContainerName = defineCSSRule({
25685
25600
  1,
25686
25601
  cssNoUnknownContainerName,
25687
25602
  "unknownContainer",
25688
- resolveMessage(messages129.unknownContainer, { name })
25603
+ resolveMessage(messages128.unknownContainer, { name })
25689
25604
  );
25690
25605
  }
25691
25606
  }
25692
25607
  });
25693
25608
 
25694
25609
  // src/css/rules/structure/css-no-unused-container-name.ts
25695
- var messages130 = {
25610
+ var messages129 = {
25696
25611
  unusedContainer: "Container name `{{name}}` is declared but never queried."
25697
25612
  };
25698
25613
  var cssNoUnusedContainerName = defineCSSRule({
25699
25614
  id: "css-no-unused-container-name",
25700
25615
  severity: "warn",
25701
- messages: messages130,
25616
+ messages: messages129,
25702
25617
  meta: {
25703
25618
  description: "Disallow unused named containers.",
25704
25619
  fixable: false,
@@ -25721,7 +25636,7 @@ var cssNoUnusedContainerName = defineCSSRule({
25721
25636
  d.startColumn,
25722
25637
  cssNoUnusedContainerName,
25723
25638
  "unusedContainer",
25724
- resolveMessage(messages130.unusedContainer, { name })
25639
+ resolveMessage(messages129.unusedContainer, { name })
25725
25640
  );
25726
25641
  }
25727
25642
  }
@@ -25729,13 +25644,13 @@ var cssNoUnusedContainerName = defineCSSRule({
25729
25644
  });
25730
25645
 
25731
25646
  // src/css/rules/structure/layer-requirement-for-component-rules.ts
25732
- var messages131 = {
25647
+ var messages130 = {
25733
25648
  missingLayer: "Rule `{{selector}}` is not inside any @layer block while this file uses @layer. Place component rules inside an explicit layer."
25734
25649
  };
25735
25650
  var layerRequirementForComponentRules = defineCSSRule({
25736
25651
  id: "layer-requirement-for-component-rules",
25737
25652
  severity: "warn",
25738
- messages: messages131,
25653
+ messages: messages130,
25739
25654
  meta: {
25740
25655
  description: "Require style rules to be inside @layer when the file defines layers.",
25741
25656
  fixable: false,
@@ -25754,7 +25669,7 @@ var layerRequirementForComponentRules = defineCSSRule({
25754
25669
  rule.startColumn,
25755
25670
  layerRequirementForComponentRules,
25756
25671
  "missingLayer",
25757
- resolveMessage(messages131.missingLayer, {
25672
+ resolveMessage(messages130.missingLayer, {
25758
25673
  selector: rule.selectorText
25759
25674
  })
25760
25675
  );
@@ -25794,7 +25709,6 @@ var rules2 = [
25794
25709
  selectorMaxAttributeAndUniversal,
25795
25710
  selectorMaxSpecificity,
25796
25711
  cssPolicyTypography,
25797
- cssPolicyTouchTarget,
25798
25712
  cssPolicySpacing,
25799
25713
  cssPolicyContrast
25800
25714
  ];
@@ -30319,21 +30233,34 @@ function detectTailwindEntry(files) {
30319
30233
  }
30320
30234
  return themeOnlyFallback;
30321
30235
  }
30322
- async function resolveTailwindValidator(files) {
30236
+ async function resolveTailwindValidator(files, logger) {
30323
30237
  const entry = detectTailwindEntry(files);
30324
- if (!entry) return null;
30238
+ if (!entry) {
30239
+ logger?.info('tailwind: no entry file detected (no @import "tailwindcss" or @theme block found in CSS files)');
30240
+ return null;
30241
+ }
30242
+ logger?.info(`tailwind: entry file detected: ${entry.path}`);
30325
30243
  try {
30326
30244
  const base = dirname2(entry.path);
30327
30245
  const resolved = resolveTailwindNodePath(base);
30328
- if (resolved === null) return null;
30246
+ if (resolved === null) {
30247
+ logger?.warning(`tailwind: @tailwindcss/node not resolvable walking up from ${base}`);
30248
+ return null;
30249
+ }
30250
+ logger?.info(`tailwind: @tailwindcss/node resolved to ${resolved}`);
30329
30251
  const mod = await import(resolved);
30330
- if (typeof mod.__unstable__loadDesignSystem !== "function") return null;
30252
+ if (typeof mod.__unstable__loadDesignSystem !== "function") {
30253
+ logger?.warning("tailwind: @tailwindcss/node module missing __unstable__loadDesignSystem export");
30254
+ return null;
30255
+ }
30331
30256
  const design = await mod.__unstable__loadDesignSystem(
30332
30257
  entry.content,
30333
30258
  { base }
30334
30259
  );
30260
+ logger?.info("tailwind: design system loaded successfully");
30335
30261
  return createLiveValidator(design);
30336
- } catch {
30262
+ } catch (err) {
30263
+ logger?.warning(`tailwind: failed to load design system: ${err instanceof Error ? err.message : String(err)}`);
30337
30264
  return null;
30338
30265
  }
30339
30266
  }
@@ -31201,7 +31128,7 @@ function publishLayoutPerfStatsForTest(stats) {
31201
31128
  }
31202
31129
  function maybeLogLayoutPerf(stats, log) {
31203
31130
  if (process.env["SOLID_LINT_LAYOUT_PROFILE"] !== "1") return;
31204
- if (!log || !log.enabled) return;
31131
+ if (!log || !log.isLevelEnabled(Level.Debug)) return;
31205
31132
  const view = snapshotLayoutPerfStats(stats);
31206
31133
  log.debug(
31207
31134
  `[layout] elements=${view.elementsScanned} candidates=${view.selectorCandidatesChecked} compiledSelectors=${view.compiledSelectorCount} unsupportedSelectors=${view.selectorsRejectedUnsupported} conditionalSelectors=${view.selectorsGuardedConditional} ancestryChecks=${view.ancestryChecks} edges=${view.matchEdgesCreated} collected=${view.casesCollected} cases=${view.casesScored} rejectLowEvidence=${view.casesRejectedLowEvidence} rejectThreshold=${view.casesRejectedThreshold} rejectUndecidable=${view.casesRejectedUndecidable} rejectIdentifiability=${view.casesRejectedIdentifiability} undecidableInterval=${view.undecidableInterval} conditionalSignalRatio=${Math.round(view.conditionalSignalRatio * 1e3) / 1e3} conditionalSignals=${view.conditionalSignals} totalSignals=${view.totalSignals} cohortUnimodalFalse=${view.cohortUnimodalFalse} factorCoverageMean=${Math.round(view.factorCoverageMean * 1e3) / 1e3} posteriorWidthP95=${Math.round(view.posteriorWidthP95 * 1e3) / 1e3} uncertaintyEscalations=${view.uncertaintyEscalations} snapshots=${view.signalSnapshotsBuilt} snapshotHits=${view.signalSnapshotCacheHits} measurementIndexHits=${view.measurementIndexHits} contexts=${view.contextsClassified} diagnostics=${view.diagnosticsEmitted} selectorIndexMs=${Math.round(view.selectorIndexMs * 100) / 100} selectorMatchMs=${Math.round(view.selectorMatchMs * 100) / 100} cascadeBuildMs=${Math.round(view.cascadeBuildMs * 100) / 100} caseBuildMs=${Math.round(view.caseBuildMs * 100) / 100} scoringMs=${Math.round(view.scoringMs * 100) / 100} elapsedMs=${Math.round(view.elapsedMs * 100) / 100}`
@@ -31249,17 +31176,17 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31249
31176
  if (cached !== void 0) return cached;
31250
31177
  const binding = resolveTagBinding(normalizedFile, tag);
31251
31178
  if (binding === null) {
31252
- if (logger.enabled) logger.trace(`[component-host] resolveHost(${tag}): binding=null`);
31179
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolveHost(${tag}): binding=null`);
31253
31180
  hostByTagCache.set(cacheKey, null);
31254
31181
  return null;
31255
31182
  }
31256
31183
  if (binding.kind === "component") {
31257
- if (logger.enabled) logger.trace(`[component-host] resolveHost(${tag}): component, tagName=${binding.host.tagName}, attrs=[${[...binding.host.staticAttributes.keys()]}]`);
31184
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolveHost(${tag}): component, tagName=${binding.host.descriptor.tagName}, attrs=[${[...binding.host.descriptor.staticAttributes.keys()]}]`);
31258
31185
  hostByTagCache.set(cacheKey, binding.host);
31259
31186
  return binding.host;
31260
31187
  }
31261
31188
  const host = binding.base ? binding.base.host : null;
31262
- if (logger.enabled) logger.trace(`[component-host] resolveHost(${tag}): namespace, base=${host?.tagName ?? "null"}`);
31189
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolveHost(${tag}): namespace, base=${host?.descriptor.tagName ?? "null"}`);
31263
31190
  hostByTagCache.set(cacheKey, host);
31264
31191
  return host;
31265
31192
  },
@@ -31272,26 +31199,26 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31272
31199
  }
31273
31200
  };
31274
31201
  function resolveComponentHostEntry(entry) {
31275
- if (entry.resolution === "resolved") return entry.descriptor;
31276
- if (logger.enabled) logger.trace(`[component-host] resolveComponentHostEntry: deferred innerTag=${entry.innerTag}, file=${entry.filePath}, attrs=[${[...entry.staticAttributes.keys()]}]`);
31202
+ if (entry.resolution === "resolved") {
31203
+ return { descriptor: entry.descriptor, hostElementRef: entry.hostElementRef };
31204
+ }
31205
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolveComponentHostEntry: deferred innerTag=${entry.innerTag}, file=${entry.filePath}, attrs=[${[...entry.staticAttributes.keys()]}]`);
31277
31206
  const innerBinding = resolveLocalIdentifierBinding(entry.filePath, entry.innerTag);
31278
- if (logger.enabled) logger.trace(`[component-host] innerBinding=${innerBinding === null ? "null" : innerBinding.kind}`);
31207
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] innerBinding=${innerBinding === null ? "null" : innerBinding.kind}`);
31279
31208
  const innerHost = extractHostFromBinding(innerBinding);
31280
- if (logger.enabled) logger.trace(`[component-host] innerHost=${innerHost === null ? "null" : `tagName=${innerHost.tagName}, attrs=[${[...innerHost.staticAttributes.keys()]}]`}`);
31281
- let tagName = innerHost !== null ? innerHost.tagName : null;
31209
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] innerHost=${innerHost === null ? "null" : `tagName=${innerHost.descriptor.tagName}, attrs=[${[...innerHost.descriptor.staticAttributes.keys()]}]`}`);
31210
+ let tagName = innerHost !== null ? innerHost.descriptor.tagName : null;
31282
31211
  if (tagName === null) {
31283
31212
  tagName = resolveTagNameFromPolymorphicProp(entry.staticAttributes);
31284
- if (logger.enabled) logger.trace(`[component-host] polymorphic fallback: tagName=${tagName}`);
31213
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] polymorphic fallback: tagName=${tagName}`);
31285
31214
  }
31286
- const staticAttributes = innerHost !== null ? mergeStaticAttributes(entry.staticAttributes, innerHost.staticAttributes) : entry.staticAttributes;
31287
- const staticClassTokens = innerHost !== null ? mergeStaticClassTokens(entry.staticClassTokens, innerHost.staticClassTokens) : entry.staticClassTokens;
31288
- const forwardsChildren = entry.forwardsChildren || innerHost !== null && innerHost.forwardsChildren;
31289
- if (logger.enabled) logger.trace(`[component-host] resolved: tagName=${tagName}, attrs=[${[...staticAttributes.keys()]}], classes=[${staticClassTokens}]`);
31215
+ const staticAttributes = innerHost !== null ? mergeStaticAttributes(entry.staticAttributes, innerHost.descriptor.staticAttributes) : entry.staticAttributes;
31216
+ const staticClassTokens = innerHost !== null ? mergeStaticClassTokens(entry.staticClassTokens, innerHost.descriptor.staticClassTokens) : entry.staticClassTokens;
31217
+ const forwardsChildren = entry.forwardsChildren || innerHost !== null && innerHost.descriptor.forwardsChildren;
31218
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolved: tagName=${tagName}, attrs=[${[...staticAttributes.keys()]}], classes=[${staticClassTokens}]`);
31290
31219
  return {
31291
- tagName,
31292
- staticAttributes,
31293
- staticClassTokens,
31294
- forwardsChildren
31220
+ descriptor: { tagName, staticAttributes, staticClassTokens, forwardsChildren },
31221
+ hostElementRef: innerHost?.hostElementRef ?? null
31295
31222
  };
31296
31223
  }
31297
31224
  function extractHostFromBinding(binding) {
@@ -31332,10 +31259,7 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31332
31259
  if (hostEntry) {
31333
31260
  const resolved = resolveComponentHostEntry(hostEntry);
31334
31261
  if (resolved !== null) {
31335
- const binding = {
31336
- kind: "component",
31337
- host: resolved
31338
- };
31262
+ const binding = { kind: "component", host: resolved };
31339
31263
  localBindingCache.set(key, binding);
31340
31264
  resolvingLocal.delete(key);
31341
31265
  return binding;
@@ -31396,7 +31320,7 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31396
31320
  const baseExpression = toExpressionArgument(firstArg);
31397
31321
  if (baseExpression === null) return null;
31398
31322
  const baseBinding = resolveBindingFromExpression(filePath, baseExpression);
31399
- if (logger.enabled) logger.trace(`[component-host] Object.assign base: ${baseBinding === null ? "null" : baseBinding.kind}${baseBinding?.kind === "component" ? `, tagName=${baseBinding.host.tagName}` : ""}`);
31323
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] Object.assign base: ${baseBinding === null ? "null" : baseBinding.kind}${baseBinding?.kind === "component" ? `, tagName=${baseBinding.host.descriptor.tagName}` : ""}`);
31400
31324
  let baseComponent = null;
31401
31325
  const members = /* @__PURE__ */ new Map();
31402
31326
  if (baseBinding && baseBinding.kind === "component") {
@@ -31422,7 +31346,7 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31422
31346
  if (!ts123.isObjectLiteralExpression(argument)) continue;
31423
31347
  appendObjectExpressionMembers(filePath, argument, members);
31424
31348
  }
31425
- if (logger.enabled) logger.trace(`[component-host] Object.assign result: base=${baseComponent === null ? "null" : `tagName=${baseComponent.host.tagName}`}, members=[${[...members.keys()]}]`);
31349
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] Object.assign result: base=${baseComponent === null ? "null" : `tagName=${baseComponent.host.descriptor.tagName}`}, members=[${[...members.keys()]}]`);
31426
31350
  if (baseComponent === null && members.size === 0) return null;
31427
31351
  return {
31428
31352
  kind: "namespace",
@@ -31464,7 +31388,7 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31464
31388
  }
31465
31389
  function resolveBindingFromImport(filePath, importBinding) {
31466
31390
  const resolvedModule = moduleResolver.resolveSolid(filePath, importBinding.source) ?? resolveAndIndexExternalModule(filePath, importBinding.source);
31467
- if (logger.enabled) logger.trace(`[component-host] resolveBindingFromImport: source=${importBinding.source}, kind=${importBinding.kind}, resolvedModule=${resolvedModule}`);
31391
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] resolveBindingFromImport: source=${importBinding.source}, kind=${importBinding.kind}, resolvedModule=${resolvedModule}`);
31468
31392
  if (resolvedModule === null) return null;
31469
31393
  const normalized = resolve4(resolvedModule);
31470
31394
  if (importBinding.kind === "namespace") {
@@ -31473,7 +31397,7 @@ function createLayoutComponentHostResolver(solids, moduleResolver, logger = noop
31473
31397
  const exportName = importBinding.kind === "default" ? "default" : importBinding.importedName;
31474
31398
  if (exportName === null) return null;
31475
31399
  const result = resolveExportBinding(normalized, exportName);
31476
- if (logger.enabled) logger.trace(`[component-host] export ${exportName}: ${result === null ? "null" : result.kind}`);
31400
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[component-host] export ${exportName}: ${result === null ? "null" : result.kind}`);
31477
31401
  return result;
31478
31402
  }
31479
31403
  function resolveAndIndexExternalModule(importerFile, importSource) {
@@ -31667,6 +31591,7 @@ function collectComponentHosts(graph) {
31667
31591
  }
31668
31592
  function resolveComponentHostEntryForFunction(graph, fn) {
31669
31593
  let entry = null;
31594
+ let hostElementRefAgreed = true;
31670
31595
  const bodyEntry = resolveHostEntryFromFunctionBody(graph, fn);
31671
31596
  if (bodyEntry !== null) {
31672
31597
  entry = bodyEntry;
@@ -31682,9 +31607,17 @@ function resolveComponentHostEntryForFunction(graph, fn) {
31682
31607
  entry = returnEntry;
31683
31608
  continue;
31684
31609
  }
31685
- if (areComponentHostEntriesEqual(entry, returnEntry)) continue;
31610
+ if (areComponentHostEntriesEqual(entry, returnEntry)) {
31611
+ if (hostElementRefAgreed && entry.resolution === "resolved" && returnEntry.resolution === "resolved" && entry.hostElementRef !== returnEntry.hostElementRef) {
31612
+ hostElementRefAgreed = false;
31613
+ }
31614
+ continue;
31615
+ }
31686
31616
  return null;
31687
31617
  }
31618
+ if (!hostElementRefAgreed && entry !== null && entry.resolution === "resolved") {
31619
+ return { resolution: "resolved", descriptor: entry.descriptor, hostElementRef: null };
31620
+ }
31688
31621
  return entry;
31689
31622
  }
31690
31623
  function resolveHostEntryFromFunctionBody(graph, fn) {
@@ -31712,7 +31645,8 @@ function resolveHostEntryFromJSXElement(graph, node) {
31712
31645
  staticAttributes: collectStaticAttributes(element),
31713
31646
  staticClassTokens: getStaticClassTokensForElementEntity(graph, element),
31714
31647
  forwardsChildren: detectChildrenForwarding(element)
31715
- }
31648
+ },
31649
+ hostElementRef: { solid: graph, element }
31716
31650
  };
31717
31651
  }
31718
31652
  if (isContextProviderTag(element.tag)) {
@@ -32881,7 +32815,7 @@ function matchesChain(matcher, node, index, perf, fileRootElements, logger) {
32881
32815
  ancestor = ancestor.parentElementNode;
32882
32816
  }
32883
32817
  if (fileRootElements !== null) {
32884
- if (logger.enabled) {
32818
+ if (logger.isLevelEnabled(Level.Trace)) {
32885
32819
  const compoundDesc = describeCompound(targetCompound);
32886
32820
  logger.trace(`[selector-match] fallback: node=${node.key} tag=${node.tagName} checking ${fileRootElements.length} roots for compound=${compoundDesc}`);
32887
32821
  }
@@ -32892,11 +32826,11 @@ function matchesChain(matcher, node, index, perf, fileRootElements, logger) {
32892
32826
  if (root.solidFile !== node.solidFile) continue;
32893
32827
  perf.ancestryChecks++;
32894
32828
  const compoundResult = matchesCompound(root, targetCompound);
32895
- if (logger.enabled && compoundResult === "no-match") {
32829
+ if (logger.isLevelEnabled(Level.Trace) && compoundResult === "no-match") {
32896
32830
  logger.trace(`[selector-match] fallback MISS: root=${root.key} tag=${root.tagName} attrs=[${[...root.attributes.entries()].map(([k, v]) => `${k}=${v}`).join(",")}]`);
32897
32831
  }
32898
32832
  if (compoundResult !== "no-match") {
32899
- if (logger.enabled) {
32833
+ if (logger.isLevelEnabled(Level.Debug)) {
32900
32834
  const compoundDesc = describeCompound(targetCompound);
32901
32835
  logger.debug(`[selector-match] fallback HIT: node=${node.key} tag=${node.tagName} matched root=${root.key} tag=${root.tagName} compound=${compoundDesc} isFinal=${isFinal}`);
32902
32836
  }
@@ -34019,6 +33953,9 @@ function readBaselineOffsetFacts(graph, node) {
34019
33953
  function readElementRef(graph, node) {
34020
33954
  return readElementRefById(graph, node.solidFile, node.elementId);
34021
33955
  }
33956
+ function readHostElementRef(graph, node) {
33957
+ return graph.hostElementRefsByNode.get(node) ?? null;
33958
+ }
34022
33959
  function readElementRefById(graph, solidFile, elementId) {
34023
33960
  const refs = graph.elementRefsBySolidFileAndId.get(solidFile);
34024
33961
  if (!refs) return null;
@@ -36717,7 +36654,7 @@ function appendMatchingEdgesFromSelectorIds(ctx, selectorIds, node, applies, app
36717
36654
  };
36718
36655
  applies.push(edge);
36719
36656
  ctx.perf.matchEdgesCreated++;
36720
- if (ctx.logger.enabled) {
36657
+ if (ctx.logger.isLevelEnabled(Level.Trace)) {
36721
36658
  ctx.logger.trace(
36722
36659
  `[cascade] edge node=${node.key} selector=${selector.id} match=${matchResult} conditional=${edge.conditionalMatch} selector-raw=${selector.raw.slice(0, 80)}`
36723
36660
  );
@@ -37160,7 +37097,7 @@ function getTextualContentState(element, memo, compositionMetaByElementId, logge
37160
37097
  if (!child) continue;
37161
37098
  if (child.kind === "expression") {
37162
37099
  if (isStructuralExpression(child.node)) {
37163
- if (logger.enabled) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 unknown (structural expression child)`);
37100
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 unknown (structural expression child)`);
37164
37101
  memo.set(element.id, 2 /* Unknown */);
37165
37102
  return 2 /* Unknown */;
37166
37103
  }
@@ -37182,11 +37119,11 @@ function getTextualContentState(element, memo, compositionMetaByElementId, logge
37182
37119
  if (!child.isDomElement) {
37183
37120
  const childMeta = compositionMetaByElementId.get(child.id);
37184
37121
  if (childMeta !== void 0 && isControlTag(childMeta.tagName)) {
37185
- if (logger.enabled) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id}: non-DOM child ${child.tag}#${child.id} resolves to control tag=${childMeta.tagName}, skipping`);
37122
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id}: non-DOM child ${child.tag}#${child.id} resolves to control tag=${childMeta.tagName}, skipping`);
37186
37123
  continue;
37187
37124
  }
37188
37125
  if (childState !== 1 /* No */) {
37189
- if (logger.enabled) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id}: non-DOM child ${child.tag ?? child.id}#${child.id} has state=${childState} \u2192 childHasUnknown`);
37126
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id}: non-DOM child ${child.tag ?? child.id}#${child.id} has state=${childState} \u2192 childHasUnknown`);
37190
37127
  childHasUnknown = true;
37191
37128
  }
37192
37129
  continue;
@@ -37199,12 +37136,12 @@ function getTextualContentState(element, memo, compositionMetaByElementId, logge
37199
37136
  if (childState === 3 /* DynamicText */) childHasDynamicText = true;
37200
37137
  }
37201
37138
  if (childHasUnknown) {
37202
- if (logger.enabled) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 unknown (child has unknown)`);
37139
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 unknown (child has unknown)`);
37203
37140
  memo.set(element.id, 2 /* Unknown */);
37204
37141
  return 2 /* Unknown */;
37205
37142
  }
37206
37143
  if (hasTextOnlyExpression || childHasDynamicText) {
37207
- if (logger.enabled) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 dynamic-text`);
37144
+ if (logger.isLevelEnabled(Level.Trace)) logger.trace(`[textual-content] element=${element.tagName ?? element.tag}#${element.id} \u2192 dynamic-text`);
37208
37145
  memo.set(element.id, 3 /* DynamicText */);
37209
37146
  return 3 /* DynamicText */;
37210
37147
  }
@@ -37226,15 +37163,16 @@ function collectLayoutElementRecordsForSolid(solid, selectorRequirements, inline
37226
37163
  const meta = compositionMetaByElementId.get(element.id);
37227
37164
  if (!meta || !meta.participates) continue;
37228
37165
  const localClassTokens = selectorRequirements.needsClassTokens ? getStaticClassTokensForElementEntity(solid, element) : EMPTY_STRING_LIST3;
37229
- const classTokens = mergeClassTokens(localClassTokens, meta.hostDescriptor?.staticClassTokens);
37166
+ const classTokens = mergeClassTokens(localClassTokens, meta.resolvedHost?.descriptor.staticClassTokens);
37230
37167
  const classTokenSet = classTokens.length === 0 ? EMPTY_CLASS_TOKEN_SET : createClassTokenSet(classTokens);
37231
37168
  const inlineStyleKeys = getStaticStyleKeysForElement(solid, element.id);
37232
37169
  const localAttributes = selectorRequirements.needsAttributes ? collectStaticAttributes(element) : EMPTY_ATTRIBUTES2;
37233
- const attributes = mergeAttributes(localAttributes, meta.hostDescriptor?.staticAttributes);
37170
+ const attributes = mergeAttributes(localAttributes, meta.resolvedHost?.descriptor.staticAttributes);
37234
37171
  const selectorDispatchKeys = buildSelectorDispatchKeys(attributes, classTokens);
37235
37172
  const inlineStyleValues = inlineStyleValuesByElementId.get(element.id) ?? EMPTY_INLINE_STYLE_VALUES;
37236
37173
  const textualContent = getTextualContentState(element, textContentMemo, compositionMetaByElementId, logger);
37237
37174
  const parentElementId = resolveComposedParentElementId(element, compositionMetaByElementId);
37175
+ const hostElementRef = meta.resolvedHost?.hostElementRef ?? null;
37238
37176
  out.push({
37239
37177
  element,
37240
37178
  key: toLayoutElementKey(solid.file, element.id),
@@ -37247,7 +37185,8 @@ function collectLayoutElementRecordsForSolid(solid, selectorRequirements, inline
37247
37185
  selectorDispatchKeys,
37248
37186
  inlineStyleValues,
37249
37187
  textualContent,
37250
- parentElementId
37188
+ parentElementId,
37189
+ hostElementRef
37251
37190
  });
37252
37191
  }
37253
37192
  return out;
@@ -37257,7 +37196,7 @@ function collectCompositionMetaByElementId(solid, componentHostResolver) {
37257
37196
  for (let i = 0; i < solid.jsxElements.length; i++) {
37258
37197
  const element = solid.jsxElements[i];
37259
37198
  if (!element) continue;
37260
- const hostDescriptor = resolveHostDescriptorForElement(
37199
+ const resolvedHost = resolveHostForElement(
37261
37200
  componentHostResolver,
37262
37201
  solid.file,
37263
37202
  element
@@ -37266,30 +37205,30 @@ function collectCompositionMetaByElementId(solid, componentHostResolver) {
37266
37205
  componentHostResolver,
37267
37206
  solid.file,
37268
37207
  element,
37269
- hostDescriptor
37208
+ resolvedHost
37270
37209
  );
37271
37210
  const participates = element.tag !== null && !isTransparentPrimitive;
37272
- const tag = resolveEffectiveTag(element, hostDescriptor);
37211
+ const tag = resolveEffectiveTag(element, resolvedHost?.descriptor ?? null);
37273
37212
  const tagName = tag ? tag.toLowerCase() : null;
37274
37213
  out.set(element.id, {
37275
37214
  element,
37276
37215
  participates,
37277
37216
  tag,
37278
37217
  tagName,
37279
- hostDescriptor
37218
+ resolvedHost
37280
37219
  });
37281
37220
  }
37282
37221
  return out;
37283
37222
  }
37284
- function resolveHostDescriptorForElement(componentHostResolver, solidFile, element) {
37223
+ function resolveHostForElement(componentHostResolver, solidFile, element) {
37285
37224
  if (element.tag === null) return null;
37286
37225
  if (element.isDomElement) return null;
37287
37226
  return componentHostResolver.resolveHost(solidFile, element.tag);
37288
37227
  }
37289
- function resolveTransparentPrimitiveStatus(componentHostResolver, solidFile, element, hostDescriptor) {
37228
+ function resolveTransparentPrimitiveStatus(componentHostResolver, solidFile, element, resolvedHost) {
37290
37229
  if (element.tag === null) return false;
37291
37230
  if (element.isDomElement) return false;
37292
- if (hostDescriptor !== null) return false;
37231
+ if (resolvedHost !== null) return false;
37293
37232
  return componentHostResolver.isTransparentPrimitive(solidFile, element.tag);
37294
37233
  }
37295
37234
  function resolveEffectiveTag(element, hostDescriptor) {
@@ -37407,6 +37346,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37407
37346
  const childrenByParentNodeMutable = /* @__PURE__ */ new Map();
37408
37347
  const elementBySolidFileAndIdMutable = /* @__PURE__ */ new Map();
37409
37348
  const elementRefsBySolidFileAndIdMutable = /* @__PURE__ */ new Map();
37349
+ const hostElementRefsByNodeMutable = /* @__PURE__ */ new Map();
37410
37350
  const appliesByElementNodeMutable = /* @__PURE__ */ new Map();
37411
37351
  const selectorsById = /* @__PURE__ */ new Map();
37412
37352
  const monitoredDeclarationsBySelectorId = /* @__PURE__ */ new Map();
@@ -37443,7 +37383,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37443
37383
  const moduleResolver = createLayoutModuleResolver(solids, css);
37444
37384
  const componentHostResolver = createLayoutComponentHostResolver(solids, moduleResolver, logger);
37445
37385
  const cssScopeBySolidFile = collectCSSScopeBySolidFile(solids, css, moduleResolver);
37446
- if (logger.enabled) {
37386
+ if (logger.isLevelEnabled(Level.Trace)) {
37447
37387
  for (const [solidFile, scopePaths] of cssScopeBySolidFile) {
37448
37388
  if (scopePaths.length > 0) {
37449
37389
  let names = "";
@@ -37538,6 +37478,9 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37538
37478
  isControl: isControlTag(record.tagName),
37539
37479
  isReplaced: isReplacedTag(record.tagName)
37540
37480
  };
37481
+ if (record.hostElementRef !== null) {
37482
+ hostElementRefsByNodeMutable.set(node, record.hostElementRef);
37483
+ }
37541
37484
  elements.push(node);
37542
37485
  elementById.set(record.element.id, node);
37543
37486
  nodeByElementId.set(record.element.id, node);
@@ -37559,7 +37502,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37559
37502
  }
37560
37503
  }
37561
37504
  }
37562
- if (logger.enabled) {
37505
+ if (logger.isLevelEnabled(Level.Debug)) {
37563
37506
  for (const [file, roots] of rootElementsByFile) {
37564
37507
  const descs = roots.map((r) => `${r.key}(tag=${r.tagName}, attrs=[${[...r.attributes.entries()].map(([k, v]) => `${k}=${v}`).join(",")}])`);
37565
37508
  logger.debug(`[build] rootElementsByFile file=${file} count=${roots.length}: ${descs.join(", ")}`);
@@ -37602,7 +37545,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37602
37545
  appliesByNode.set(node, edges);
37603
37546
  }
37604
37547
  perf.cascadeBuildMs = performance.now() - cascadeStartedAt;
37605
- if (logger.enabled) {
37548
+ if (logger.isLevelEnabled(Level.Trace)) {
37606
37549
  for (let i = 0; i < elements.length; i++) {
37607
37550
  const node = elements[i];
37608
37551
  if (!node) continue;
@@ -37658,6 +37601,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37658
37601
  childrenByParentNode: childrenByParentNodeMutable,
37659
37602
  elementBySolidFileAndId: elementBySolidFileAndIdMutable,
37660
37603
  elementRefsBySolidFileAndId: elementRefsBySolidFileAndIdMutable,
37604
+ hostElementRefsByNode: hostElementRefsByNodeMutable,
37661
37605
  appliesByNode,
37662
37606
  selectorCandidatesByNode,
37663
37607
  selectorsById,
@@ -38058,7 +38002,7 @@ function computeFlowParticipationFact(snapshot) {
38058
38002
  }
38059
38003
  function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf, logger) {
38060
38004
  const out = /* @__PURE__ */ new Map();
38061
- const trace = logger.enabled;
38005
+ const trace = logger.isLevelEnabled(Level.Trace);
38062
38006
  for (const [parent, children] of childrenByParentNode) {
38063
38007
  if (children.length < 2) continue;
38064
38008
  const snapshot = snapshotByElementNode.get(parent);
@@ -38928,7 +38872,7 @@ function runLayoutDetector(context, detector) {
38928
38872
  result.evidence.posteriorLower,
38929
38873
  result.evidence.posteriorUpper
38930
38874
  );
38931
- if (log.enabled) {
38875
+ if (log.isLevelEnabled(Level.Debug)) {
38932
38876
  log.debug(
38933
38877
  `[${detector.id}] accept case=${i} severity=${result.evidence.severity.toFixed(2)} confidence=${result.evidence.confidence.toFixed(2)} posterior=[${result.evidence.posteriorLower.toFixed(3)},${result.evidence.posteriorUpper.toFixed(3)}] evidenceMass=${result.evidence.evidenceMass.toFixed(3)} context=${result.evidence.contextKind} offset=${result.evidence.estimatedOffsetPx?.toFixed(2) ?? "null"} topFactors=[${result.evidence.topFactors.join(",")}] causes=[${result.evidence.causes.join("; ")}]`
38934
38878
  );
@@ -38937,7 +38881,7 @@ function runLayoutDetector(context, detector) {
38937
38881
  continue;
38938
38882
  }
38939
38883
  recordPolicyMetrics(context, result.evidenceMass, result.posteriorLower, result.posteriorUpper);
38940
- if (log.enabled) {
38884
+ if (log.isLevelEnabled(Level.Debug)) {
38941
38885
  log.debug(
38942
38886
  `[${detector.id}] reject case=${i} reason=${result.reason} detail=${result.detail ?? "none"} posterior=[${result.posteriorLower.toFixed(3)},${result.posteriorUpper.toFixed(3)}] evidenceMass=${result.evidenceMass.toFixed(3)}`
38943
38887
  );
@@ -39121,13 +39065,13 @@ function emitLayoutDiagnostic(layout, node, emit, ruleId, messageId, template, s
39121
39065
  }
39122
39066
 
39123
39067
  // src/cross-file/rules/undefined-css-class.ts
39124
- var messages132 = {
39068
+ var messages131 = {
39125
39069
  undefinedClass: "CSS class '{{className}}' is not defined in project CSS files"
39126
39070
  };
39127
39071
  var jsxNoUndefinedCssClass = defineCrossRule({
39128
39072
  id: "jsx-no-undefined-css-class",
39129
39073
  severity: "error",
39130
- messages: messages132,
39074
+ messages: messages131,
39131
39075
  meta: {
39132
39076
  description: "Detect undefined CSS class names in JSX",
39133
39077
  fixable: false,
@@ -39146,7 +39090,7 @@ var jsxNoUndefinedCssClass = defineCrossRule({
39146
39090
  ref.solid.sourceFile,
39147
39091
  jsxNoUndefinedCssClass.id,
39148
39092
  "undefinedClass",
39149
- resolveMessage(messages132.undefinedClass, { className: item.className }),
39093
+ resolveMessage(messages131.undefinedClass, { className: item.className }),
39150
39094
  "error"
39151
39095
  ));
39152
39096
  }
@@ -39154,13 +39098,13 @@ var jsxNoUndefinedCssClass = defineCrossRule({
39154
39098
  });
39155
39099
 
39156
39100
  // src/cross-file/rules/unreferenced-css-class.ts
39157
- var messages133 = {
39101
+ var messages132 = {
39158
39102
  unreferencedClass: "CSS class '{{className}}' is defined but not referenced by static JSX class attributes"
39159
39103
  };
39160
39104
  var cssNoUnreferencedComponentClass = defineCrossRule({
39161
39105
  id: "css-no-unreferenced-component-class",
39162
39106
  severity: "warn",
39163
- messages: messages133,
39107
+ messages: messages132,
39164
39108
  meta: {
39165
39109
  description: "Detect CSS classes that are never referenced by static JSX class attributes.",
39166
39110
  fixable: false,
@@ -39184,7 +39128,7 @@ var cssNoUnreferencedComponentClass = defineCrossRule({
39184
39128
  },
39185
39129
  cssNoUnreferencedComponentClass.id,
39186
39130
  "unreferencedClass",
39187
- resolveMessage(messages133.unreferencedClass, { className }),
39131
+ resolveMessage(messages132.unreferencedClass, { className }),
39188
39132
  "warn"
39189
39133
  )
39190
39134
  );
@@ -39193,13 +39137,13 @@ var cssNoUnreferencedComponentClass = defineCrossRule({
39193
39137
  });
39194
39138
 
39195
39139
  // src/cross-file/rules/jsx-no-duplicate-class-token-class-classlist.ts
39196
- var messages134 = {
39140
+ var messages133 = {
39197
39141
  duplicateClassToken: "Class token `{{name}}` appears in both class and classList."
39198
39142
  };
39199
39143
  var jsxNoDuplicateClassTokenClassClasslist = defineCrossRule({
39200
39144
  id: "jsx-no-duplicate-class-token-class-classlist",
39201
39145
  severity: "warn",
39202
- messages: messages134,
39146
+ messages: messages133,
39203
39147
  meta: {
39204
39148
  description: "Disallow duplicate class tokens between class and classList on the same JSX element.",
39205
39149
  fixable: false,
@@ -39241,7 +39185,7 @@ var jsxNoDuplicateClassTokenClassClasslist = defineCrossRule({
39241
39185
  solid.sourceFile,
39242
39186
  jsxNoDuplicateClassTokenClassClasslist.id,
39243
39187
  "duplicateClassToken",
39244
- resolveMessage(messages134.duplicateClassToken, { name: token }),
39188
+ resolveMessage(messages133.duplicateClassToken, { name: token }),
39245
39189
  "warn"
39246
39190
  ));
39247
39191
  }
@@ -39252,13 +39196,13 @@ var jsxNoDuplicateClassTokenClassClasslist = defineCrossRule({
39252
39196
 
39253
39197
  // src/cross-file/rules/jsx-classlist-static-keys.ts
39254
39198
  import ts126 from "typescript";
39255
- var messages135 = {
39199
+ var messages134 = {
39256
39200
  nonStaticKey: "classList key must be statically known for reliable class mapping."
39257
39201
  };
39258
39202
  var jsxClasslistStaticKeys = defineCrossRule({
39259
39203
  id: "jsx-classlist-static-keys",
39260
39204
  severity: "error",
39261
- messages: messages135,
39205
+ messages: messages134,
39262
39206
  meta: {
39263
39207
  description: "Require classList keys to be static and non-computed.",
39264
39208
  fixable: false,
@@ -39269,26 +39213,26 @@ var jsxClasslistStaticKeys = defineCrossRule({
39269
39213
  forEachClassListPropertyAcross(solids, (solid, p) => {
39270
39214
  if (ts126.isSpreadAssignment(p)) return;
39271
39215
  if (!ts126.isPropertyAssignment(p)) {
39272
- emit(createDiagnostic(solid.file, p, solid.sourceFile, jsxClasslistStaticKeys.id, "nonStaticKey", resolveMessage(messages135.nonStaticKey), "error"));
39216
+ emit(createDiagnostic(solid.file, p, solid.sourceFile, jsxClasslistStaticKeys.id, "nonStaticKey", resolveMessage(messages134.nonStaticKey), "error"));
39273
39217
  return;
39274
39218
  }
39275
39219
  if (ts126.isComputedPropertyName(p.name)) return;
39276
39220
  if (ts126.isIdentifier(p.name)) return;
39277
39221
  if (ts126.isStringLiteral(p.name)) return;
39278
- emit(createDiagnostic(solid.file, p.name, solid.sourceFile, jsxClasslistStaticKeys.id, "nonStaticKey", resolveMessage(messages135.nonStaticKey), "error"));
39222
+ emit(createDiagnostic(solid.file, p.name, solid.sourceFile, jsxClasslistStaticKeys.id, "nonStaticKey", resolveMessage(messages134.nonStaticKey), "error"));
39279
39223
  });
39280
39224
  }
39281
39225
  });
39282
39226
 
39283
39227
  // src/cross-file/rules/jsx-classlist-no-constant-literals.ts
39284
39228
  import ts127 from "typescript";
39285
- var messages136 = {
39229
+ var messages135 = {
39286
39230
  constantEntry: "classList entry `{{name}}: {{value}}` is constant; move it to static class."
39287
39231
  };
39288
39232
  var jsxClasslistNoConstantLiterals = defineCrossRule({
39289
39233
  id: "jsx-classlist-no-constant-literals",
39290
39234
  severity: "warn",
39291
- messages: messages136,
39235
+ messages: messages135,
39292
39236
  meta: {
39293
39237
  description: "Disallow classList entries with constant true/false values.",
39294
39238
  fixable: false,
@@ -39308,7 +39252,7 @@ var jsxClasslistNoConstantLiterals = defineCrossRule({
39308
39252
  solid.sourceFile,
39309
39253
  jsxClasslistNoConstantLiterals.id,
39310
39254
  "constantEntry",
39311
- resolveMessage(messages136.constantEntry, { name: n, value: val.kind === ts127.SyntaxKind.TrueKeyword ? "true" : "false" }),
39255
+ resolveMessage(messages135.constantEntry, { name: n, value: val.kind === ts127.SyntaxKind.TrueKeyword ? "true" : "false" }),
39312
39256
  "warn"
39313
39257
  ));
39314
39258
  });
@@ -39343,13 +39287,13 @@ function isDefinitelyNonBooleanType(solid, node) {
39343
39287
  }
39344
39288
 
39345
39289
  // src/cross-file/rules/jsx-classlist-boolean-values.ts
39346
- var messages137 = {
39290
+ var messages136 = {
39347
39291
  nonBooleanValue: "classList value for `{{name}}` must be boolean."
39348
39292
  };
39349
39293
  var jsxClasslistBooleanValues = defineCrossRule({
39350
39294
  id: "jsx-classlist-boolean-values",
39351
39295
  severity: "error",
39352
- messages: messages137,
39296
+ messages: messages136,
39353
39297
  meta: {
39354
39298
  description: "Require classList values to be boolean-like expressions.",
39355
39299
  fixable: false,
@@ -39363,25 +39307,25 @@ var jsxClasslistBooleanValues = defineCrossRule({
39363
39307
  if (!n) return;
39364
39308
  if (isBooleanish(p.initializer)) return;
39365
39309
  if (isDefinitelyNonBoolean(p.initializer)) {
39366
- emit(createDiagnostic(solid.file, p.initializer, solid.sourceFile, jsxClasslistBooleanValues.id, "nonBooleanValue", resolveMessage(messages137.nonBooleanValue, { name: n }), "error"));
39310
+ emit(createDiagnostic(solid.file, p.initializer, solid.sourceFile, jsxClasslistBooleanValues.id, "nonBooleanValue", resolveMessage(messages136.nonBooleanValue, { name: n }), "error"));
39367
39311
  return;
39368
39312
  }
39369
39313
  if (isBooleanType(solid, p.initializer)) return;
39370
39314
  if (!isDefinitelyNonBooleanType(solid, p.initializer)) return;
39371
- emit(createDiagnostic(solid.file, p.initializer, solid.sourceFile, jsxClasslistBooleanValues.id, "nonBooleanValue", resolveMessage(messages137.nonBooleanValue, { name: n }), "error"));
39315
+ emit(createDiagnostic(solid.file, p.initializer, solid.sourceFile, jsxClasslistBooleanValues.id, "nonBooleanValue", resolveMessage(messages136.nonBooleanValue, { name: n }), "error"));
39372
39316
  });
39373
39317
  }
39374
39318
  });
39375
39319
 
39376
39320
  // src/cross-file/rules/jsx-classlist-no-accessor-reference.ts
39377
39321
  import ts129 from "typescript";
39378
- var messages138 = {
39322
+ var messages137 = {
39379
39323
  accessorReference: "Signal accessor `{{name}}` must be called in classList value (use {{name}}())."
39380
39324
  };
39381
39325
  var jsxClasslistNoAccessorReference = defineCrossRule({
39382
39326
  id: "jsx-classlist-no-accessor-reference",
39383
39327
  severity: "error",
39384
- messages: messages138,
39328
+ messages: messages137,
39385
39329
  meta: {
39386
39330
  description: "Disallow passing accessor references directly as classList values.",
39387
39331
  fixable: false,
@@ -39413,7 +39357,7 @@ var jsxClasslistNoAccessorReference = defineCrossRule({
39413
39357
  solid.sourceFile,
39414
39358
  jsxClasslistNoAccessorReference.id,
39415
39359
  "accessorReference",
39416
- resolveMessage(messages138.accessorReference, { name: v.text }),
39360
+ resolveMessage(messages137.accessorReference, { name: v.text }),
39417
39361
  "error"
39418
39362
  ));
39419
39363
  });
@@ -39422,13 +39366,13 @@ var jsxClasslistNoAccessorReference = defineCrossRule({
39422
39366
 
39423
39367
  // src/cross-file/rules/jsx-style-kebab-case-keys.ts
39424
39368
  import ts130 from "typescript";
39425
- var messages139 = {
39369
+ var messages138 = {
39426
39370
  kebabStyleKey: "Style key `{{name}}` should be `{{kebab}}` in Solid style objects."
39427
39371
  };
39428
39372
  var jsxStyleKebabCaseKeys = defineCrossRule({
39429
39373
  id: "jsx-style-kebab-case-keys",
39430
39374
  severity: "error",
39431
- messages: messages139,
39375
+ messages: messages138,
39432
39376
  meta: {
39433
39377
  description: "Require kebab-case keys in JSX style object literals.",
39434
39378
  fixable: false,
@@ -39449,7 +39393,7 @@ var jsxStyleKebabCaseKeys = defineCrossRule({
39449
39393
  solid.sourceFile,
39450
39394
  jsxStyleKebabCaseKeys.id,
39451
39395
  "kebabStyleKey",
39452
- resolveMessage(messages139.kebabStyleKey, { name: n, kebab }),
39396
+ resolveMessage(messages138.kebabStyleKey, { name: n, kebab }),
39453
39397
  "error"
39454
39398
  ));
39455
39399
  });
@@ -39458,13 +39402,13 @@ var jsxStyleKebabCaseKeys = defineCrossRule({
39458
39402
 
39459
39403
  // src/cross-file/rules/jsx-style-no-function-values.ts
39460
39404
  import ts131 from "typescript";
39461
- var messages140 = {
39405
+ var messages139 = {
39462
39406
  functionStyleValue: "Style value for `{{name}}` is a function; pass computed value instead."
39463
39407
  };
39464
39408
  var jsxStyleNoFunctionValues = defineCrossRule({
39465
39409
  id: "jsx-style-no-function-values",
39466
39410
  severity: "error",
39467
- messages: messages140,
39411
+ messages: messages139,
39468
39412
  meta: {
39469
39413
  description: "Disallow function values in JSX style objects.",
39470
39414
  fixable: false,
@@ -39478,11 +39422,11 @@ var jsxStyleNoFunctionValues = defineCrossRule({
39478
39422
  if (!n) return;
39479
39423
  const v = p.initializer;
39480
39424
  if (ts131.isArrowFunction(v) || ts131.isFunctionExpression(v)) {
39481
- emit(createDiagnostic(solid.file, v, solid.sourceFile, jsxStyleNoFunctionValues.id, "functionStyleValue", resolveMessage(messages140.functionStyleValue, { name: n }), "error"));
39425
+ emit(createDiagnostic(solid.file, v, solid.sourceFile, jsxStyleNoFunctionValues.id, "functionStyleValue", resolveMessage(messages139.functionStyleValue, { name: n }), "error"));
39482
39426
  return;
39483
39427
  }
39484
39428
  if (ts131.isIdentifier(v) && solid.typeResolver.isCallableType(v)) {
39485
- emit(createDiagnostic(solid.file, v, solid.sourceFile, jsxStyleNoFunctionValues.id, "functionStyleValue", resolveMessage(messages140.functionStyleValue, { name: n }), "error"));
39429
+ emit(createDiagnostic(solid.file, v, solid.sourceFile, jsxStyleNoFunctionValues.id, "functionStyleValue", resolveMessage(messages139.functionStyleValue, { name: n }), "error"));
39486
39430
  }
39487
39431
  });
39488
39432
  }
@@ -39490,13 +39434,13 @@ var jsxStyleNoFunctionValues = defineCrossRule({
39490
39434
 
39491
39435
  // src/cross-file/rules/jsx-style-no-unused-custom-prop.ts
39492
39436
  import ts132 from "typescript";
39493
- var messages141 = {
39437
+ var messages140 = {
39494
39438
  unusedInlineVar: "Inline custom property `{{name}}` is never read via var({{name}})."
39495
39439
  };
39496
39440
  var jsxStyleNoUnusedCustomProp = defineCrossRule({
39497
39441
  id: "jsx-style-no-unused-custom-prop",
39498
39442
  severity: "warn",
39499
- messages: messages141,
39443
+ messages: messages140,
39500
39444
  meta: {
39501
39445
  description: "Detect inline style custom properties that are never consumed by CSS var() references.",
39502
39446
  fixable: false,
@@ -39537,7 +39481,7 @@ var jsxStyleNoUnusedCustomProp = defineCrossRule({
39537
39481
  solid.sourceFile,
39538
39482
  jsxStyleNoUnusedCustomProp.id,
39539
39483
  "unusedInlineVar",
39540
- resolveMessage(messages141.unusedInlineVar, { name: n }),
39484
+ resolveMessage(messages140.unusedInlineVar, { name: n }),
39541
39485
  "warn"
39542
39486
  ));
39543
39487
  }
@@ -39547,7 +39491,7 @@ var jsxStyleNoUnusedCustomProp = defineCrossRule({
39547
39491
 
39548
39492
  // src/cross-file/rules/jsx-style-policy.ts
39549
39493
  import ts133 from "typescript";
39550
- var messages142 = {
39494
+ var messages141 = {
39551
39495
  fontTooSmall: "Inline style `{{prop}}: {{value}}` ({{resolved}}px) is below the minimum `{{min}}px` for policy `{{policy}}`.",
39552
39496
  lineHeightTooSmall: "Inline style `line-height: {{value}}` is below the minimum `{{min}}` for policy `{{policy}}`.",
39553
39497
  heightTooSmall: "Inline style `{{prop}}: {{value}}` ({{resolved}}px) is below the minimum `{{min}}px` for interactive elements in policy `{{policy}}`.",
@@ -39558,28 +39502,54 @@ var INLINE_TOUCH_TARGET_KEYS = /* @__PURE__ */ new Set([
39558
39502
  "height",
39559
39503
  "min-height",
39560
39504
  "width",
39561
- "min-width",
39562
- "padding-left",
39563
- "padding-right",
39564
- "padding-inline",
39565
- "padding-inline-start",
39566
- "padding-inline-end"
39505
+ "min-width"
39506
+ ]);
39507
+ var INTERACTIVE_HTML_TAGS = /* @__PURE__ */ new Set(["button", "a", "input", "select", "textarea", "label", "summary"]);
39508
+ var INTERACTIVE_ARIA_ROLES = /* @__PURE__ */ new Set([
39509
+ "button",
39510
+ "link",
39511
+ "checkbox",
39512
+ "radio",
39513
+ "combobox",
39514
+ "listbox",
39515
+ "menuitem",
39516
+ "menuitemcheckbox",
39517
+ "menuitemradio",
39518
+ "option",
39519
+ "switch",
39520
+ "tab"
39567
39521
  ]);
39522
+ function isInteractiveElement(solid, element, hostElementRef) {
39523
+ if (element.tagName !== null && INTERACTIVE_HTML_TAGS.has(element.tagName)) return true;
39524
+ const roleAttr = getJSXAttributeEntity(solid, element, "role");
39525
+ if (roleAttr !== null && roleAttr.valueNode !== null) {
39526
+ const role = getStaticStringFromJSXValue(roleAttr.valueNode);
39527
+ if (role !== null && INTERACTIVE_ARIA_ROLES.has(role)) return true;
39528
+ }
39529
+ if (hostElementRef !== null && hostElementRef.element.tagName !== null) {
39530
+ if (INTERACTIVE_HTML_TAGS.has(hostElementRef.element.tagName)) return true;
39531
+ }
39532
+ return false;
39533
+ }
39534
+ function readNodeHostElementRef(layout, solid, element) {
39535
+ const node = layout.elementBySolidFileAndId.get(solid.file)?.get(element.id) ?? null;
39536
+ return node !== null ? readHostElementRef(layout, node) : null;
39537
+ }
39568
39538
  var jsxStylePolicy = defineCrossRule({
39569
39539
  id: "jsx-style-policy",
39570
39540
  severity: "warn",
39571
- messages: messages142,
39541
+ messages: messages141,
39572
39542
  meta: {
39573
39543
  description: "Enforce accessibility policy thresholds on inline JSX style objects.",
39574
39544
  fixable: false,
39575
39545
  category: "css-jsx"
39576
39546
  },
39577
39547
  check(context, emit) {
39578
- const { solids } = context;
39548
+ const { solids, layout } = context;
39579
39549
  const policy = getActivePolicy();
39580
39550
  if (policy === null) return;
39581
39551
  const name = getActivePolicyName() ?? "";
39582
- forEachStylePropertyAcross(solids, (solid, p) => {
39552
+ forEachStylePropertyAcross(solids, (solid, p, element) => {
39583
39553
  if (!ts133.isPropertyAssignment(p)) return;
39584
39554
  const key = objectKeyName(p.name);
39585
39555
  if (!key) return;
@@ -39595,7 +39565,7 @@ var jsxStylePolicy = defineCrossRule({
39595
39565
  solid.sourceFile,
39596
39566
  jsxStylePolicy.id,
39597
39567
  "fontTooSmall",
39598
- resolveMessage(messages142.fontTooSmall, {
39568
+ resolveMessage(messages141.fontTooSmall, {
39599
39569
  prop: key,
39600
39570
  value: strVal,
39601
39571
  resolved: formatRounded(px),
@@ -39617,7 +39587,7 @@ var jsxStylePolicy = defineCrossRule({
39617
39587
  solid.sourceFile,
39618
39588
  jsxStylePolicy.id,
39619
39589
  "lineHeightTooSmall",
39620
- resolveMessage(messages142.lineHeightTooSmall, {
39590
+ resolveMessage(messages141.lineHeightTooSmall, {
39621
39591
  value: String(lh),
39622
39592
  min: String(policy.minLineHeight),
39623
39593
  policy: name
@@ -39627,6 +39597,8 @@ var jsxStylePolicy = defineCrossRule({
39627
39597
  return;
39628
39598
  }
39629
39599
  if (INLINE_TOUCH_TARGET_KEYS.has(normalizedKey)) {
39600
+ const hostRef = readNodeHostElementRef(layout, solid, element);
39601
+ if (!isInteractiveElement(solid, element, hostRef)) return;
39630
39602
  const strVal = getStaticStringValue(p.initializer);
39631
39603
  if (!strVal) return;
39632
39604
  const px = parsePxValue(strVal);
@@ -39639,7 +39611,7 @@ var jsxStylePolicy = defineCrossRule({
39639
39611
  solid.sourceFile,
39640
39612
  jsxStylePolicy.id,
39641
39613
  "heightTooSmall",
39642
- resolveMessage(messages142.heightTooSmall, {
39614
+ resolveMessage(messages141.heightTooSmall, {
39643
39615
  prop: key,
39644
39616
  value: strVal,
39645
39617
  resolved: formatRounded(px),
@@ -39661,7 +39633,7 @@ var jsxStylePolicy = defineCrossRule({
39661
39633
  solid.sourceFile,
39662
39634
  jsxStylePolicy.id,
39663
39635
  "letterSpacingTooSmall",
39664
- resolveMessage(messages142.letterSpacingTooSmall, {
39636
+ resolveMessage(messages141.letterSpacingTooSmall, {
39665
39637
  value: strVal,
39666
39638
  resolved: String(em),
39667
39639
  min: String(policy.minLetterSpacing),
@@ -39682,7 +39654,7 @@ var jsxStylePolicy = defineCrossRule({
39682
39654
  solid.sourceFile,
39683
39655
  jsxStylePolicy.id,
39684
39656
  "wordSpacingTooSmall",
39685
- resolveMessage(messages142.wordSpacingTooSmall, {
39657
+ resolveMessage(messages141.wordSpacingTooSmall, {
39686
39658
  value: strVal,
39687
39659
  resolved: String(em),
39688
39660
  min: String(policy.minWordSpacing),
@@ -39696,7 +39668,7 @@ var jsxStylePolicy = defineCrossRule({
39696
39668
  });
39697
39669
 
39698
39670
  // src/cross-file/rules/css-layout-sibling-alignment-outlier.ts
39699
- var messages143 = {
39671
+ var messages142 = {
39700
39672
  misalignedSibling: "Vertically misaligned '{{subject}}' in '{{parent}}'.{{fix}}{{offsetClause}}"
39701
39673
  };
39702
39674
  var MIN_CONFIDENCE_THRESHOLD = 0.48;
@@ -39705,7 +39677,7 @@ var siblingAlignmentDetector = {
39705
39677
  id: "sibling-alignment-outlier",
39706
39678
  collect: collectAlignmentCases,
39707
39679
  evaluate(input, context) {
39708
- if (context.logger.enabled) {
39680
+ if (context.logger.isLevelEnabled(Level.Trace)) {
39709
39681
  const ctx = input.context;
39710
39682
  context.logger.trace(
39711
39683
  `[sibling-alignment] evaluate subject=${input.subject.elementKey} tag=${input.subject.tag} parent=${ctx.parentElementKey} parentTag=${ctx.parentTag} context.kind=${ctx.kind} certainty=${ctx.certainty} display=${ctx.parentDisplay} alignItems=${ctx.parentAlignItems} crossAxisIsBlockAxis=${ctx.crossAxisIsBlockAxis} crossAxisCertainty=${ctx.crossAxisIsBlockAxisCertainty} baseline=${ctx.baselineRelevance}`
@@ -39744,7 +39716,7 @@ var siblingAlignmentDetector = {
39744
39716
  var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39745
39717
  id: "css-layout-sibling-alignment-outlier",
39746
39718
  severity: "warn",
39747
- messages: messages143,
39719
+ messages: messages142,
39748
39720
  meta: {
39749
39721
  description: "Detect vertical alignment outliers between sibling elements in shared layout containers.",
39750
39722
  fixable: false,
@@ -39754,7 +39726,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39754
39726
  const log = context.logger;
39755
39727
  const detections = runLayoutDetector(context, siblingAlignmentDetector);
39756
39728
  const uniqueDetections = dedupeDetectionsBySubject(detections);
39757
- if (log.enabled) {
39729
+ if (log.isLevelEnabled(Level.Debug)) {
39758
39730
  log.debug(
39759
39731
  `[sibling-alignment] raw=${detections.length} deduped=${uniqueDetections.length}`
39760
39732
  );
@@ -39768,7 +39740,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39768
39740
  const subjectId = detection.caseData.subject.elementId;
39769
39741
  const logPrefix = `[sibling-alignment] <${subjectTag}> in <${parentTag}> (${subjectFile}#${subjectId})`;
39770
39742
  if (detection.evidence.confidence < MIN_CONFIDENCE_THRESHOLD) {
39771
- if (log.enabled) {
39743
+ if (log.isLevelEnabled(Level.Debug)) {
39772
39744
  log.debug(
39773
39745
  `${logPrefix} SKIP: confidence=${detection.evidence.confidence.toFixed(2)} < threshold=${MIN_CONFIDENCE_THRESHOLD}`
39774
39746
  );
@@ -39777,7 +39749,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39777
39749
  }
39778
39750
  const estimatedOffset = detection.evidence.estimatedOffsetPx;
39779
39751
  if (estimatedOffset !== null && Math.abs(estimatedOffset) < MIN_OFFSET_PX_THRESHOLD && !hasNonOffsetPrimaryEvidence(detection.evidence.topFactors)) {
39780
- if (log.enabled) {
39752
+ if (log.isLevelEnabled(Level.Debug)) {
39781
39753
  log.debug(
39782
39754
  `${logPrefix} SKIP: offset=${estimatedOffset.toFixed(2)}px < ${MIN_OFFSET_PX_THRESHOLD}px (no non-offset primary evidence, topFactors=[${detection.evidence.topFactors.join(",")}])`
39783
39755
  );
@@ -39789,7 +39761,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39789
39761
  detection.caseData.cohort.parentElementKey,
39790
39762
  detection.caseData.subject.solidFile
39791
39763
  )) {
39792
- if (log.enabled) {
39764
+ if (log.isLevelEnabled(Level.Debug)) {
39793
39765
  log.debug(`${logPrefix} SKIP: out-of-flow ancestor`);
39794
39766
  }
39795
39767
  continue;
@@ -39800,7 +39772,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39800
39772
  detection.caseData.subject.elementId
39801
39773
  );
39802
39774
  if (!subjectRef) {
39803
- if (log.enabled) {
39775
+ if (log.isLevelEnabled(Level.Debug)) {
39804
39776
  log.debug(`${logPrefix} SKIP: no node ref`);
39805
39777
  }
39806
39778
  continue;
@@ -39816,7 +39788,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39816
39788
  const primaryFix = detection.evidence.primaryFix;
39817
39789
  const firstChar = primaryFix.length > 0 ? primaryFix[0] : void 0;
39818
39790
  const fix = firstChar !== void 0 ? ` ${firstChar.toUpperCase()}${primaryFix.slice(1)}.` : "";
39819
- if (log.enabled) {
39791
+ if (log.isLevelEnabled(Level.Debug)) {
39820
39792
  log.debug(
39821
39793
  `${logPrefix} EMIT: severity=${severity} confidence=${confidence} offset=${offset?.toFixed(2) ?? "null"} posterior=[${detection.evidence.posteriorLower.toFixed(3)},${detection.evidence.posteriorUpper.toFixed(3)}] evidenceMass=${detection.evidence.evidenceMass.toFixed(3)} topFactors=[${detection.evidence.topFactors.join(",")}] causes=[${causes}]`
39822
39794
  );
@@ -39828,7 +39800,7 @@ var cssLayoutSiblingAlignmentOutlier = defineCrossRule({
39828
39800
  subjectRef.solid.sourceFile,
39829
39801
  cssLayoutSiblingAlignmentOutlier.id,
39830
39802
  "misalignedSibling",
39831
- resolveMessage(messages143.misalignedSibling, {
39803
+ resolveMessage(messages142.misalignedSibling, {
39832
39804
  subject,
39833
39805
  parent,
39834
39806
  fix,
@@ -39912,13 +39884,13 @@ function hasNonOffsetPrimaryEvidence(topFactors) {
39912
39884
  }
39913
39885
 
39914
39886
  // src/cross-file/rules/css-layout-transition-layout-property.ts
39915
- var messages144 = {
39887
+ var messages143 = {
39916
39888
  transitionLayoutProperty: "Transition '{{property}}' in '{{declaration}}' animates layout-affecting geometry. Prefer transform/opacity to avoid CLS."
39917
39889
  };
39918
39890
  var cssLayoutTransitionLayoutProperty = defineCrossRule({
39919
39891
  id: "css-layout-transition-layout-property",
39920
39892
  severity: "warn",
39921
- messages: messages144,
39893
+ messages: messages143,
39922
39894
  meta: {
39923
39895
  description: "Disallow transitions that animate layout-affecting geometry properties.",
39924
39896
  fixable: false,
@@ -39942,7 +39914,7 @@ var cssLayoutTransitionLayoutProperty = defineCrossRule({
39942
39914
  },
39943
39915
  cssLayoutTransitionLayoutProperty.id,
39944
39916
  "transitionLayoutProperty",
39945
- resolveMessage(messages144.transitionLayoutProperty, {
39917
+ resolveMessage(messages143.transitionLayoutProperty, {
39946
39918
  property: target,
39947
39919
  declaration: declaration.property
39948
39920
  }),
@@ -39957,13 +39929,13 @@ function findLayoutTransitionTarget(raw) {
39957
39929
  }
39958
39930
 
39959
39931
  // src/cross-file/rules/css-layout-animation-layout-property.ts
39960
- var messages145 = {
39932
+ var messages144 = {
39961
39933
  animationLayoutProperty: "Animation '{{animation}}' mutates layout-affecting '{{property}}', which can trigger CLS. Prefer transform/opacity or reserve geometry."
39962
39934
  };
39963
39935
  var cssLayoutAnimationLayoutProperty = defineCrossRule({
39964
39936
  id: "css-layout-animation-layout-property",
39965
39937
  severity: "warn",
39966
- messages: messages145,
39938
+ messages: messages144,
39967
39939
  meta: {
39968
39940
  description: "Disallow keyframe animations that mutate layout-affecting properties and can trigger CLS.",
39969
39941
  fixable: false,
@@ -39991,7 +39963,7 @@ var cssLayoutAnimationLayoutProperty = defineCrossRule({
39991
39963
  },
39992
39964
  cssLayoutAnimationLayoutProperty.id,
39993
39965
  "animationLayoutProperty",
39994
- resolveMessage(messages145.animationLayoutProperty, {
39966
+ resolveMessage(messages144.animationLayoutProperty, {
39995
39967
  animation: match.name,
39996
39968
  property: match.property
39997
39969
  }),
@@ -40061,13 +40033,13 @@ function firstRiskyAnimationName(names, riskyKeyframes) {
40061
40033
  }
40062
40034
 
40063
40035
  // src/cross-file/rules/css-layout-stateful-box-model-shift.ts
40064
- var messages146 = {
40036
+ var messages145 = {
40065
40037
  statefulBoxModelShift: "State selector '{{selector}}' changes layout-affecting '{{property}}'. Keep geometry stable across states to avoid CLS."
40066
40038
  };
40067
40039
  var cssLayoutStatefulBoxModelShift = defineCrossRule({
40068
40040
  id: "css-layout-stateful-box-model-shift",
40069
40041
  severity: "warn",
40070
- messages: messages146,
40042
+ messages: messages145,
40071
40043
  meta: {
40072
40044
  description: "Disallow stateful selector changes that alter element geometry and trigger layout shifts.",
40073
40045
  fixable: false,
@@ -40108,7 +40080,7 @@ var cssLayoutStatefulBoxModelShift = defineCrossRule({
40108
40080
  },
40109
40081
  cssLayoutStatefulBoxModelShift.id,
40110
40082
  "statefulBoxModelShift",
40111
- resolveMessage(messages146.statefulBoxModelShift, {
40083
+ resolveMessage(messages145.statefulBoxModelShift, {
40112
40084
  selector: match.raw,
40113
40085
  property: declaration.property
40114
40086
  }),
@@ -40202,14 +40174,14 @@ function lookupBaseByProperty(baseValueIndex, selectorKeys) {
40202
40174
 
40203
40175
  // src/cross-file/rules/css-layout-unsized-replaced-element.ts
40204
40176
  import ts134 from "typescript";
40205
- var messages147 = {
40177
+ var messages146 = {
40206
40178
  unsizedReplacedElement: "Replaced element '{{tag}}' has no stable reserved size (width/height or aspect-ratio with a dimension), which can cause CLS."
40207
40179
  };
40208
40180
  var REPLACED_MEDIA_TAGS = /* @__PURE__ */ new Set(["img", "video", "iframe", "canvas", "svg"]);
40209
40181
  var cssLayoutUnsizedReplacedElement = defineCrossRule({
40210
40182
  id: "css-layout-unsized-replaced-element",
40211
40183
  severity: "warn",
40212
- messages: messages147,
40184
+ messages: messages146,
40213
40185
  meta: {
40214
40186
  description: "Require stable reserved geometry for replaced media elements to prevent layout shifts.",
40215
40187
  fixable: false,
@@ -40225,7 +40197,8 @@ var cssLayoutUnsizedReplacedElement = defineCrossRule({
40225
40197
  const ref = readNodeRef(context.layout, node);
40226
40198
  if (!ref) continue;
40227
40199
  const reservedSpace = readReservedSpaceFact(context.layout, node);
40228
- if (hasReservedSize(ref.solid, node.attributes, ref.element, reservedSpace)) continue;
40200
+ const hostRef = readHostElementRef(context.layout, node);
40201
+ if (hasReservedSize(ref.solid, node.attributes, ref.element, reservedSpace, hostRef)) continue;
40229
40202
  emit(
40230
40203
  createDiagnostic(
40231
40204
  ref.solid.file,
@@ -40233,22 +40206,24 @@ var cssLayoutUnsizedReplacedElement = defineCrossRule({
40233
40206
  ref.solid.sourceFile,
40234
40207
  cssLayoutUnsizedReplacedElement.id,
40235
40208
  "unsizedReplacedElement",
40236
- resolveMessage(messages147.unsizedReplacedElement, { tag }),
40209
+ resolveMessage(messages146.unsizedReplacedElement, { tag }),
40237
40210
  "warn"
40238
40211
  )
40239
40212
  );
40240
40213
  }
40241
40214
  }
40242
40215
  });
40243
- function hasReservedSize(solid, attributes, element, reservedSpaceFact) {
40216
+ function hasReservedSize(solid, attributes, element, reservedSpaceFact, hostElementRef) {
40244
40217
  if (reservedSpaceFact.hasReservedSpace) return true;
40245
40218
  const attrWidth = parsePositiveLength(attributes.get("width"));
40246
40219
  const attrHeight = parsePositiveLength(attributes.get("height"));
40247
40220
  const jsxAttrWidth = readPositiveJsxAttribute(solid, element, "width");
40248
40221
  const jsxAttrHeight = readPositiveJsxAttribute(solid, element, "height");
40249
- if (attrWidth && attrHeight || jsxAttrWidth && jsxAttrHeight) return true;
40250
- const hasAnyWidth = attrWidth || jsxAttrWidth || reservedSpaceFact.hasUsableInlineDimension;
40251
- const hasAnyHeight = attrHeight || jsxAttrHeight || reservedSpaceFact.hasUsableBlockDimension || reservedSpaceFact.hasContainIntrinsicSize;
40222
+ const hostJsxWidth = hostElementRef !== null ? readPositiveJsxAttribute(hostElementRef.solid, hostElementRef.element, "width") : false;
40223
+ const hostJsxHeight = hostElementRef !== null ? readPositiveJsxAttribute(hostElementRef.solid, hostElementRef.element, "height") : false;
40224
+ if (attrWidth && attrHeight || jsxAttrWidth && jsxAttrHeight || hostJsxWidth && hostJsxHeight) return true;
40225
+ const hasAnyWidth = attrWidth || jsxAttrWidth || hostJsxWidth || reservedSpaceFact.hasUsableInlineDimension;
40226
+ const hasAnyHeight = attrHeight || jsxAttrHeight || hostJsxHeight || reservedSpaceFact.hasUsableBlockDimension || reservedSpaceFact.hasContainIntrinsicSize;
40252
40227
  if (reservedSpaceFact.hasUsableAspectRatio && (hasAnyWidth || hasAnyHeight)) return true;
40253
40228
  if (reservedSpaceFact.hasContainIntrinsicSize && (hasAnyWidth || hasAnyHeight)) return true;
40254
40229
  return false;
@@ -40284,7 +40259,7 @@ function readPositiveJsxAttribute(solid, element, name) {
40284
40259
  }
40285
40260
 
40286
40261
  // src/cross-file/rules/css-layout-dynamic-slot-no-reserved-space.ts
40287
- var messages148 = {
40262
+ var messages147 = {
40288
40263
  dynamicSlotNoReservedSpace: "Dynamic content container '{{tag}}' does not reserve block space (min-height/height/aspect-ratio/contain-intrinsic-size), which can cause CLS."
40289
40264
  };
40290
40265
  var INLINE_DISPLAYS = /* @__PURE__ */ new Set(["inline", "contents"]);
@@ -40306,7 +40281,7 @@ function hasOutOfFlowAncestor(layout, node) {
40306
40281
  var cssLayoutDynamicSlotNoReservedSpace = defineCrossRule({
40307
40282
  id: "css-layout-dynamic-slot-no-reserved-space",
40308
40283
  severity: "warn",
40309
- messages: messages148,
40284
+ messages: messages147,
40310
40285
  meta: {
40311
40286
  description: "Require reserved block space for dynamic content containers to avoid layout shifts.",
40312
40287
  fixable: false,
@@ -40329,19 +40304,19 @@ var cssLayoutDynamicSlotNoReservedSpace = defineCrossRule({
40329
40304
  const reservedSpace = readReservedSpaceFact(context.layout, node);
40330
40305
  if (reservedSpace.hasReservedSpace) continue;
40331
40306
  if (hasBlockAxisPadding(snapshot)) continue;
40332
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutDynamicSlotNoReservedSpace.id, "dynamicSlotNoReservedSpace", messages148.dynamicSlotNoReservedSpace, cssLayoutDynamicSlotNoReservedSpace.severity)) continue;
40307
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutDynamicSlotNoReservedSpace.id, "dynamicSlotNoReservedSpace", messages147.dynamicSlotNoReservedSpace, cssLayoutDynamicSlotNoReservedSpace.severity)) continue;
40333
40308
  }
40334
40309
  }
40335
40310
  });
40336
40311
 
40337
40312
  // src/cross-file/rules/css-layout-scrollbar-gutter-instability.ts
40338
- var messages149 = {
40313
+ var messages148 = {
40339
40314
  missingScrollbarGutter: "Scrollable container '{{tag}}' uses overflow auto/scroll without `scrollbar-gutter: stable`, which can trigger CLS when scrollbars appear."
40340
40315
  };
40341
40316
  var cssLayoutScrollbarGutterInstability = defineCrossRule({
40342
40317
  id: "css-layout-scrollbar-gutter-instability",
40343
40318
  severity: "warn",
40344
- messages: messages149,
40319
+ messages: messages148,
40345
40320
  meta: {
40346
40321
  description: "Require stable scrollbar gutters for scrollable containers to reduce layout shifts.",
40347
40322
  fixable: false,
@@ -40360,19 +40335,19 @@ var cssLayoutScrollbarGutterInstability = defineCrossRule({
40360
40335
  if (scrollbarWidth === "none") continue;
40361
40336
  const gutter = readKnownNormalized(snapshot, "scrollbar-gutter");
40362
40337
  if (gutter !== null && gutter.startsWith("stable")) continue;
40363
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutScrollbarGutterInstability.id, "missingScrollbarGutter", messages149.missingScrollbarGutter, cssLayoutScrollbarGutterInstability.severity)) continue;
40338
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutScrollbarGutterInstability.id, "missingScrollbarGutter", messages148.missingScrollbarGutter, cssLayoutScrollbarGutterInstability.severity)) continue;
40364
40339
  }
40365
40340
  }
40366
40341
  });
40367
40342
 
40368
40343
  // src/cross-file/rules/css-layout-overflow-anchor-instability.ts
40369
- var messages150 = {
40344
+ var messages149 = {
40370
40345
  unstableOverflowAnchor: "Element '{{tag}}' sets `overflow-anchor: none` on a {{context}} container; disabling scroll anchoring can amplify visible layout shifts."
40371
40346
  };
40372
40347
  var cssLayoutOverflowAnchorInstability = defineCrossRule({
40373
40348
  id: "css-layout-overflow-anchor-instability",
40374
40349
  severity: "warn",
40375
- messages: messages150,
40350
+ messages: messages149,
40376
40351
  meta: {
40377
40352
  description: "Disallow overflow-anchor none on dynamic or scrollable containers prone to visible layout shifts.",
40378
40353
  fixable: false,
@@ -40390,20 +40365,20 @@ var cssLayoutOverflowAnchorInstability = defineCrossRule({
40390
40365
  const isDynamicContainer = isDynamicContainerLike(node);
40391
40366
  if (!isScrollable && !isDynamicContainer) continue;
40392
40367
  const containerContext = isScrollable ? "scrollable" : "dynamic";
40393
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutOverflowAnchorInstability.id, "unstableOverflowAnchor", messages150.unstableOverflowAnchor, cssLayoutOverflowAnchorInstability.severity, { context: containerContext })) continue;
40368
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutOverflowAnchorInstability.id, "unstableOverflowAnchor", messages149.unstableOverflowAnchor, cssLayoutOverflowAnchorInstability.severity, { context: containerContext })) continue;
40394
40369
  }
40395
40370
  }
40396
40371
  });
40397
40372
 
40398
40373
  // src/cross-file/rules/css-layout-font-swap-instability.ts
40399
- var messages151 = {
40374
+ var messages150 = {
40400
40375
  unstableFontSwap: "`@font-face` for '{{family}}' uses `font-display: {{display}}` without metric overrides (for example `size-adjust`), which can cause CLS when the webfont swaps in."
40401
40376
  };
40402
40377
  var SWAP_DISPLAYS = /* @__PURE__ */ new Set(["swap", "fallback"]);
40403
40378
  var cssLayoutFontSwapInstability = defineCrossRule({
40404
40379
  id: "css-layout-font-swap-instability",
40405
40380
  severity: "warn",
40406
- messages: messages151,
40381
+ messages: messages150,
40407
40382
  meta: {
40408
40383
  description: "Require metric overrides for swapping webfonts to reduce layout shifts during font load.",
40409
40384
  fixable: false,
@@ -40450,7 +40425,7 @@ var cssLayoutFontSwapInstability = defineCrossRule({
40450
40425
  },
40451
40426
  cssLayoutFontSwapInstability.id,
40452
40427
  "unstableFontSwap",
40453
- resolveMessage(messages151.unstableFontSwap, {
40428
+ resolveMessage(messages150.unstableFontSwap, {
40454
40429
  family,
40455
40430
  display: report.display
40456
40431
  }),
@@ -40463,14 +40438,14 @@ var cssLayoutFontSwapInstability = defineCrossRule({
40463
40438
  });
40464
40439
 
40465
40440
  // src/cross-file/rules/css-layout-conditional-display-collapse.ts
40466
- var messages152 = {
40441
+ var messages151 = {
40467
40442
  conditionalDisplayCollapse: "Conditional display sets '{{display}}' on '{{tag}}' without stable reserved space, which can collapse/expand layout and cause CLS."
40468
40443
  };
40469
40444
  var COLLAPSING_DISPLAYS = /* @__PURE__ */ new Set(["none", "contents"]);
40470
40445
  var cssLayoutConditionalDisplayCollapse = defineCrossRule({
40471
40446
  id: "css-layout-conditional-display-collapse",
40472
40447
  severity: "warn",
40473
- messages: messages152,
40448
+ messages: messages151,
40474
40449
  meta: {
40475
40450
  description: "Disallow conditional display collapse in flow without reserved geometry.",
40476
40451
  fixable: false,
@@ -40491,13 +40466,13 @@ var cssLayoutConditionalDisplayCollapse = defineCrossRule({
40491
40466
  if (!isFlowRelevantBySiblingsOrText(node, snapshot.node.textualContent)) continue;
40492
40467
  const reservedSpace = readReservedSpaceFact(context.layout, node);
40493
40468
  if (reservedSpace.hasReservedSpace) continue;
40494
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutConditionalDisplayCollapse.id, "conditionalDisplayCollapse", messages152.conditionalDisplayCollapse, cssLayoutConditionalDisplayCollapse.severity, { display })) continue;
40469
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutConditionalDisplayCollapse.id, "conditionalDisplayCollapse", messages151.conditionalDisplayCollapse, cssLayoutConditionalDisplayCollapse.severity, { display })) continue;
40495
40470
  }
40496
40471
  }
40497
40472
  });
40498
40473
 
40499
40474
  // src/cross-file/rules/css-layout-conditional-white-space-wrap-shift.ts
40500
- var messages153 = {
40475
+ var messages152 = {
40501
40476
  conditionalWhiteSpaceShift: "Conditional white-space '{{whiteSpace}}' on '{{tag}}' can reflow text and shift siblings; keep wrapping behavior stable or reserve geometry."
40502
40477
  };
40503
40478
  var WRAP_SHIFT_VALUES = /* @__PURE__ */ new Set(["nowrap", "pre"]);
@@ -40506,7 +40481,7 @@ var BLOCK_SIZE_PROPERTIES = ["height", "min-height"];
40506
40481
  var cssLayoutConditionalWhiteSpaceWrapShift = defineCrossRule({
40507
40482
  id: "css-layout-conditional-white-space-wrap-shift",
40508
40483
  severity: "warn",
40509
- messages: messages153,
40484
+ messages: messages152,
40510
40485
  meta: {
40511
40486
  description: "Disallow conditional white-space wrapping mode toggles that can trigger CLS.",
40512
40487
  fixable: false,
@@ -40529,7 +40504,7 @@ var cssLayoutConditionalWhiteSpaceWrapShift = defineCrossRule({
40529
40504
  if (!flow.inFlow) continue;
40530
40505
  if (!isFlowRelevantBySiblingsOrText(node, snapshot.node.textualContent)) continue;
40531
40506
  if (hasStableTextShell(snapshot)) continue;
40532
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutConditionalWhiteSpaceWrapShift.id, "conditionalWhiteSpaceShift", messages153.conditionalWhiteSpaceShift, cssLayoutConditionalWhiteSpaceWrapShift.severity, { whiteSpace })) continue;
40507
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutConditionalWhiteSpaceWrapShift.id, "conditionalWhiteSpaceShift", messages152.conditionalWhiteSpaceShift, cssLayoutConditionalWhiteSpaceWrapShift.severity, { whiteSpace })) continue;
40533
40508
  }
40534
40509
  }
40535
40510
  });
@@ -40551,13 +40526,13 @@ function hasWrapShiftDelta(delta) {
40551
40526
  }
40552
40527
 
40553
40528
  // src/cross-file/rules/css-layout-overflow-mode-toggle-instability.ts
40554
- var messages154 = {
40529
+ var messages153 = {
40555
40530
  overflowModeToggle: "Conditional overflow mode changes scrolling ('{{overflow}}') on '{{tag}}' without `scrollbar-gutter: stable`, which can trigger CLS."
40556
40531
  };
40557
40532
  var cssLayoutOverflowModeToggleInstability = defineCrossRule({
40558
40533
  id: "css-layout-overflow-mode-toggle-instability",
40559
40534
  severity: "warn",
40560
- messages: messages154,
40535
+ messages: messages153,
40561
40536
  meta: {
40562
40537
  description: "Disallow conditional overflow mode switches that can introduce scrollbar-induced layout shifts.",
40563
40538
  fixable: false,
@@ -40582,7 +40557,7 @@ var cssLayoutOverflowModeToggleInstability = defineCrossRule({
40582
40557
  const gutter = readKnownNormalizedWithGuard(snapshot, "scrollbar-gutter");
40583
40558
  if (gutter !== null && gutter.startsWith("stable")) continue;
40584
40559
  const overflowValue = scrollFact.overflowY ?? scrollFact.overflow ?? "auto";
40585
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutOverflowModeToggleInstability.id, "overflowModeToggle", messages154.overflowModeToggle, cssLayoutOverflowModeToggleInstability.severity, { overflow: overflowValue })) continue;
40560
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutOverflowModeToggleInstability.id, "overflowModeToggle", messages153.overflowModeToggle, cssLayoutOverflowModeToggleInstability.severity, { overflow: overflowValue })) continue;
40586
40561
  }
40587
40562
  }
40588
40563
  });
@@ -40602,7 +40577,7 @@ function hasAnyScrollValue(delta) {
40602
40577
  }
40603
40578
 
40604
40579
  // src/cross-file/rules/css-layout-box-sizing-toggle-with-chrome.ts
40605
- var messages155 = {
40580
+ var messages154 = {
40606
40581
  boxSizingToggleWithChrome: "Conditional `box-sizing` toggle on '{{tag}}' combines with non-zero padding/border, which can shift layout and trigger CLS."
40607
40582
  };
40608
40583
  var BOX_SIZING_VALUES = /* @__PURE__ */ new Set(["content-box", "border-box"]);
@@ -40619,7 +40594,7 @@ var CHROME_PROPERTIES = [
40619
40594
  var cssLayoutBoxSizingToggleWithChrome = defineCrossRule({
40620
40595
  id: "css-layout-box-sizing-toggle-with-chrome",
40621
40596
  severity: "warn",
40622
- messages: messages155,
40597
+ messages: messages154,
40623
40598
  meta: {
40624
40599
  description: "Disallow conditional box-sizing mode toggles when box chrome contributes to geometry shifts.",
40625
40600
  fixable: false,
@@ -40637,7 +40612,7 @@ var cssLayoutBoxSizingToggleWithChrome = defineCrossRule({
40637
40612
  if (!boxSizingDelta.hasConditional) continue;
40638
40613
  if (!boxSizingDelta.hasDelta) continue;
40639
40614
  if (!hasNonZeroChrome(snapshot)) continue;
40640
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutBoxSizingToggleWithChrome.id, "boxSizingToggleWithChrome", messages155.boxSizingToggleWithChrome, cssLayoutBoxSizingToggleWithChrome.severity)) continue;
40615
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutBoxSizingToggleWithChrome.id, "boxSizingToggleWithChrome", messages154.boxSizingToggleWithChrome, cssLayoutBoxSizingToggleWithChrome.severity)) continue;
40641
40616
  }
40642
40617
  }
40643
40618
  });
@@ -40646,13 +40621,13 @@ function hasNonZeroChrome(snapshot) {
40646
40621
  }
40647
40622
 
40648
40623
  // src/cross-file/rules/css-layout-content-visibility-no-intrinsic-size.ts
40649
- var messages156 = {
40624
+ var messages155 = {
40650
40625
  missingIntrinsicSize: "`content-visibility: auto` on '{{tag}}' lacks intrinsic size reservation (`contain-intrinsic-size`/min-height/height/aspect-ratio), which can cause CLS."
40651
40626
  };
40652
40627
  var cssLayoutContentVisibilityNoIntrinsicSize = defineCrossRule({
40653
40628
  id: "css-layout-content-visibility-no-intrinsic-size",
40654
40629
  severity: "warn",
40655
- messages: messages156,
40630
+ messages: messages155,
40656
40631
  meta: {
40657
40632
  description: "Require intrinsic size reservation when using content-visibility auto to avoid late layout shifts.",
40658
40633
  fixable: false,
@@ -40667,19 +40642,19 @@ var cssLayoutContentVisibilityNoIntrinsicSize = defineCrossRule({
40667
40642
  if (!isDeferredContainerLike(node, snapshot.node.textualContent)) continue;
40668
40643
  const reservedSpace = readReservedSpaceFact(context.layout, node);
40669
40644
  if (reservedSpace.hasReservedSpace) continue;
40670
- if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutContentVisibilityNoIntrinsicSize.id, "missingIntrinsicSize", messages156.missingIntrinsicSize, cssLayoutContentVisibilityNoIntrinsicSize.severity)) continue;
40645
+ if (!emitLayoutDiagnostic(context.layout, node, emit, cssLayoutContentVisibilityNoIntrinsicSize.id, "missingIntrinsicSize", messages155.missingIntrinsicSize, cssLayoutContentVisibilityNoIntrinsicSize.severity)) continue;
40671
40646
  }
40672
40647
  }
40673
40648
  });
40674
40649
 
40675
40650
  // src/cross-file/rules/css-layout-conditional-offset-shift.ts
40676
- var messages157 = {
40651
+ var messages156 = {
40677
40652
  conditionalOffsetShift: "Conditional style applies non-zero '{{property}}' offset ({{value}}), which can cause layout shifts when conditions toggle."
40678
40653
  };
40679
40654
  var cssLayoutConditionalOffsetShift = defineCrossRule({
40680
40655
  id: "css-layout-conditional-offset-shift",
40681
40656
  severity: "warn",
40682
- messages: messages157,
40657
+ messages: messages156,
40683
40658
  meta: {
40684
40659
  description: "Disallow conditional non-zero block-axis offsets that can trigger layout shifts.",
40685
40660
  fixable: false,
@@ -40705,7 +40680,7 @@ var cssLayoutConditionalOffsetShift = defineCrossRule({
40705
40680
  ref.solid.sourceFile,
40706
40681
  cssLayoutConditionalOffsetShift.id,
40707
40682
  "conditionalOffsetShift",
40708
- resolveMessage(messages157.conditionalOffsetShift, {
40683
+ resolveMessage(messages156.conditionalOffsetShift, {
40709
40684
  property: match.property,
40710
40685
  value: `${formatFixed(match.value)}px`
40711
40686
  }),
@@ -40766,7 +40741,7 @@ function hasStableBaseline(baselineBySignal, property, expectedPx) {
40766
40741
 
40767
40742
  // src/cross-file/rules/jsx-layout-unstable-style-toggle.ts
40768
40743
  import ts135 from "typescript";
40769
- var messages158 = {
40744
+ var messages157 = {
40770
40745
  unstableLayoutStyleToggle: "Dynamic style value for '{{property}}' can toggle layout geometry at runtime and cause CLS."
40771
40746
  };
40772
40747
  var PX_NUMBER_PROPERTIES = /* @__PURE__ */ new Set([
@@ -40789,7 +40764,7 @@ var POSITIONED_OFFSET_PROPERTIES = /* @__PURE__ */ new Set([
40789
40764
  var jsxLayoutUnstableStyleToggle = defineCrossRule({
40790
40765
  id: "jsx-layout-unstable-style-toggle",
40791
40766
  severity: "warn",
40792
- messages: messages158,
40767
+ messages: messages157,
40793
40768
  meta: {
40794
40769
  description: "Flag dynamic inline style values on layout-sensitive properties that can trigger CLS.",
40795
40770
  fixable: false,
@@ -40811,7 +40786,7 @@ var jsxLayoutUnstableStyleToggle = defineCrossRule({
40811
40786
  solid.sourceFile,
40812
40787
  jsxLayoutUnstableStyleToggle.id,
40813
40788
  "unstableLayoutStyleToggle",
40814
- resolveMessage(messages158.unstableLayoutStyleToggle, { property: normalized }),
40789
+ resolveMessage(messages157.unstableLayoutStyleToggle, { property: normalized }),
40815
40790
  "warn"
40816
40791
  )
40817
40792
  );
@@ -40928,14 +40903,14 @@ function unwrapTypeWrapper(node) {
40928
40903
 
40929
40904
  // src/cross-file/rules/jsx-layout-classlist-geometry-toggle.ts
40930
40905
  import ts136 from "typescript";
40931
- var messages159 = {
40906
+ var messages158 = {
40932
40907
  classListGeometryToggle: "classList toggles '{{className}}', and matching CSS changes layout-affecting '{{property}}', which can cause CLS."
40933
40908
  };
40934
40909
  var OUT_OF_FLOW_POSITIONS2 = /* @__PURE__ */ new Set(["fixed", "absolute"]);
40935
40910
  var jsxLayoutClasslistGeometryToggle = defineCrossRule({
40936
40911
  id: "jsx-layout-classlist-geometry-toggle",
40937
40912
  severity: "warn",
40938
- messages: messages159,
40913
+ messages: messages158,
40939
40914
  meta: {
40940
40915
  description: "Flag classList-driven class toggles that map to layout-affecting CSS geometry changes.",
40941
40916
  fixable: false,
@@ -40961,7 +40936,7 @@ var jsxLayoutClasslistGeometryToggle = defineCrossRule({
40961
40936
  solid.sourceFile,
40962
40937
  jsxLayoutClasslistGeometryToggle.id,
40963
40938
  "classListGeometryToggle",
40964
- resolveMessage(messages159.classListGeometryToggle, {
40939
+ resolveMessage(messages158.classListGeometryToggle, {
40965
40940
  className,
40966
40941
  property
40967
40942
  }),
@@ -41010,14 +40985,14 @@ function isDynamicallyToggleable(node) {
41010
40985
  }
41011
40986
 
41012
40987
  // src/cross-file/rules/jsx-layout-picture-source-ratio-consistency.ts
41013
- var messages160 = {
40988
+ var messages159 = {
41014
40989
  inconsistentPictureRatio: "`<picture>` source ratio {{sourceRatio}} differs from fallback img ratio {{imgRatio}}, which can cause reserved-space mismatch and CLS."
41015
40990
  };
41016
40991
  var RATIO_DELTA_THRESHOLD = 0.02;
41017
40992
  var jsxLayoutPictureSourceRatioConsistency = defineCrossRule({
41018
40993
  id: "jsx-layout-picture-source-ratio-consistency",
41019
40994
  severity: "warn",
41020
- messages: messages160,
40995
+ messages: messages159,
41021
40996
  meta: {
41022
40997
  description: "Require consistent intrinsic aspect ratios across <picture> sources and fallback image.",
41023
40998
  fixable: false,
@@ -41040,7 +41015,7 @@ var jsxLayoutPictureSourceRatioConsistency = defineCrossRule({
41040
41015
  solid.sourceFile,
41041
41016
  jsxLayoutPictureSourceRatioConsistency.id,
41042
41017
  "inconsistentPictureRatio",
41043
- resolveMessage(messages160.inconsistentPictureRatio, {
41018
+ resolveMessage(messages159.inconsistentPictureRatio, {
41044
41019
  sourceRatio: mismatch.sourceRatio,
41045
41020
  imgRatio: mismatch.imgRatio
41046
41021
  }),
@@ -41110,13 +41085,13 @@ function formatRatio(value2) {
41110
41085
  }
41111
41086
 
41112
41087
  // src/cross-file/rules/jsx-layout-fill-image-parent-must-be-sized.ts
41113
- var messages161 = {
41088
+ var messages160 = {
41114
41089
  unsizedFillParent: "Fill-image component '{{component}}' is inside a parent without stable size/position; add parent sizing (height/min-height/aspect-ratio) and non-static position to avoid CLS."
41115
41090
  };
41116
41091
  var jsxLayoutFillImageParentMustBeSized = defineCrossRule({
41117
41092
  id: "jsx-layout-fill-image-parent-must-be-sized",
41118
41093
  severity: "warn",
41119
- messages: messages161,
41094
+ messages: messages160,
41120
41095
  meta: {
41121
41096
  description: "Require stable parent size and positioning for fill-image component usage.",
41122
41097
  fixable: false,
@@ -41146,7 +41121,7 @@ var jsxLayoutFillImageParentMustBeSized = defineCrossRule({
41146
41121
  solid.sourceFile,
41147
41122
  jsxLayoutFillImageParentMustBeSized.id,
41148
41123
  "unsizedFillParent",
41149
- resolveMessage(messages161.unsizedFillParent, {
41124
+ resolveMessage(messages160.unsizedFillParent, {
41150
41125
  component: element.tag ?? "Image"
41151
41126
  }),
41152
41127
  "warn"
@@ -41157,6 +41132,210 @@ var jsxLayoutFillImageParentMustBeSized = defineCrossRule({
41157
41132
  }
41158
41133
  });
41159
41134
 
41135
+ // src/cross-file/rules/jsx-layout-policy-touch-target.ts
41136
+ var messages161 = {
41137
+ heightTooSmall: "`{{signal}}` of `{{value}}px` is below the minimum `{{min}}px` for interactive element `<{{tag}}>` in policy `{{policy}}`.",
41138
+ widthTooSmall: "`{{signal}}` of `{{value}}px` is below the minimum `{{min}}px` for interactive element `<{{tag}}>` in policy `{{policy}}`.",
41139
+ paddingTooSmall: "Horizontal padding `{{signal}}` of `{{value}}px` is below the minimum `{{min}}px` for interactive element `<{{tag}}>` in policy `{{policy}}`.",
41140
+ noReservedBlockSize: "Interactive element `<{{tag}}>` has no declared height (minimum `{{min}}px` required by policy `{{policy}}`). The element is content-sized and may not meet the touch-target threshold.",
41141
+ noReservedInlineSize: "Interactive element `<{{tag}}>` has no declared width (minimum `{{min}}px` required by policy `{{policy}}`). The element is content-sized and may not meet the touch-target threshold."
41142
+ };
41143
+ var INTERACTIVE_HTML_TAGS2 = /* @__PURE__ */ new Set(["button", "a", "input", "select", "textarea", "label", "summary"]);
41144
+ var INTERACTIVE_ARIA_ROLES2 = /* @__PURE__ */ new Set([
41145
+ "button",
41146
+ "link",
41147
+ "checkbox",
41148
+ "radio",
41149
+ "combobox",
41150
+ "listbox",
41151
+ "menuitem",
41152
+ "menuitemcheckbox",
41153
+ "menuitemradio",
41154
+ "option",
41155
+ "switch",
41156
+ "tab"
41157
+ ]);
41158
+ function classifyInteractive(node, solid, element, layout) {
41159
+ const tag = node.tagName;
41160
+ if (tag !== null && INTERACTIVE_HTML_TAGS2.has(tag)) {
41161
+ if (tag === "input" || tag === "select" || tag === "textarea") return "input";
41162
+ return "button";
41163
+ }
41164
+ const roleAttr = getJSXAttributeEntity(solid, element, "role");
41165
+ if (roleAttr !== null && roleAttr.valueNode !== null) {
41166
+ const role = getStaticStringFromJSXValue(roleAttr.valueNode);
41167
+ if (role !== null && INTERACTIVE_ARIA_ROLES2.has(role)) return "button";
41168
+ }
41169
+ const hostRef = layout.hostElementRefsByNode.get(node) ?? null;
41170
+ if (hostRef !== null && hostRef.element.tagName !== null) {
41171
+ const hostTag = hostRef.element.tagName;
41172
+ if (INTERACTIVE_HTML_TAGS2.has(hostTag)) {
41173
+ if (hostTag === "input" || hostTag === "select" || hostTag === "textarea") return "input";
41174
+ return "button";
41175
+ }
41176
+ }
41177
+ return null;
41178
+ }
41179
+ function isVisuallyHidden(snapshot) {
41180
+ const position = readKnownNormalized(snapshot, "position");
41181
+ if (position !== "absolute" && position !== "fixed") return false;
41182
+ const node = snapshot.node;
41183
+ const opacityAttr = node.inlineStyleValues.get("opacity");
41184
+ if (opacityAttr === "0") return true;
41185
+ if (node.classTokenSet.has("opacity-0")) return true;
41186
+ return false;
41187
+ }
41188
+ var jsxLayoutPolicyTouchTarget = defineCrossRule({
41189
+ id: "jsx-layout-policy-touch-target",
41190
+ severity: "warn",
41191
+ messages: messages161,
41192
+ meta: {
41193
+ description: "Enforce minimum interactive element sizes per accessibility policy via resolved layout signals.",
41194
+ fixable: false,
41195
+ category: "css-a11y"
41196
+ },
41197
+ check(context, emit) {
41198
+ const policy = getActivePolicy();
41199
+ if (policy === null) return;
41200
+ const policyName = getActivePolicyName() ?? "";
41201
+ const { layout } = context;
41202
+ const elements = layout.elements;
41203
+ for (let i = 0; i < elements.length; i++) {
41204
+ const node = elements[i];
41205
+ if (!node) continue;
41206
+ const ref = readElementRef(layout, node);
41207
+ if (!ref) continue;
41208
+ const kind = classifyInteractive(node, ref.solid, ref.element, layout);
41209
+ if (kind === null) continue;
41210
+ const snapshot = collectSignalSnapshot(context, node);
41211
+ if (isVisuallyHidden(snapshot)) continue;
41212
+ const tag = node.tagName ?? node.tag ?? "element";
41213
+ checkDimension(
41214
+ snapshot,
41215
+ "height",
41216
+ kind === "button" ? policy.minButtonHeight : policy.minInputHeight,
41217
+ layout,
41218
+ node,
41219
+ emit,
41220
+ "heightTooSmall",
41221
+ messages161.heightTooSmall,
41222
+ tag,
41223
+ policyName
41224
+ );
41225
+ checkDimension(
41226
+ snapshot,
41227
+ "min-height",
41228
+ kind === "button" ? policy.minButtonHeight : policy.minInputHeight,
41229
+ layout,
41230
+ node,
41231
+ emit,
41232
+ "heightTooSmall",
41233
+ messages161.heightTooSmall,
41234
+ tag,
41235
+ policyName
41236
+ );
41237
+ checkDimension(
41238
+ snapshot,
41239
+ "width",
41240
+ kind === "button" ? policy.minButtonWidth : policy.minTouchTarget,
41241
+ layout,
41242
+ node,
41243
+ emit,
41244
+ "widthTooSmall",
41245
+ messages161.widthTooSmall,
41246
+ tag,
41247
+ policyName
41248
+ );
41249
+ checkDimension(
41250
+ snapshot,
41251
+ "min-width",
41252
+ kind === "button" ? policy.minButtonWidth : policy.minTouchTarget,
41253
+ layout,
41254
+ node,
41255
+ emit,
41256
+ "widthTooSmall",
41257
+ messages161.widthTooSmall,
41258
+ tag,
41259
+ policyName
41260
+ );
41261
+ if (kind === "button") {
41262
+ checkDimension(
41263
+ snapshot,
41264
+ "padding-left",
41265
+ policy.minButtonHorizontalPadding,
41266
+ layout,
41267
+ node,
41268
+ emit,
41269
+ "paddingTooSmall",
41270
+ messages161.paddingTooSmall,
41271
+ tag,
41272
+ policyName
41273
+ );
41274
+ checkDimension(
41275
+ snapshot,
41276
+ "padding-right",
41277
+ policy.minButtonHorizontalPadding,
41278
+ layout,
41279
+ node,
41280
+ emit,
41281
+ "paddingTooSmall",
41282
+ messages161.paddingTooSmall,
41283
+ tag,
41284
+ policyName
41285
+ );
41286
+ }
41287
+ const reservedSpace = readReservedSpaceFact(layout, node);
41288
+ const minBlock = kind === "button" ? policy.minButtonHeight : policy.minInputHeight;
41289
+ const minInline = kind === "button" ? policy.minButtonWidth : policy.minTouchTarget;
41290
+ if (!reservedSpace.hasUsableBlockDimension) {
41291
+ emitLayoutDiagnostic(
41292
+ layout,
41293
+ node,
41294
+ emit,
41295
+ jsxLayoutPolicyTouchTarget.id,
41296
+ "noReservedBlockSize",
41297
+ messages161.noReservedBlockSize,
41298
+ "warn",
41299
+ { tag, min: String(minBlock), policy: policyName }
41300
+ );
41301
+ }
41302
+ if (!reservedSpace.hasUsableInlineDimension) {
41303
+ emitLayoutDiagnostic(
41304
+ layout,
41305
+ node,
41306
+ emit,
41307
+ jsxLayoutPolicyTouchTarget.id,
41308
+ "noReservedInlineSize",
41309
+ messages161.noReservedInlineSize,
41310
+ "warn",
41311
+ { tag, min: String(minInline), policy: policyName }
41312
+ );
41313
+ }
41314
+ }
41315
+ }
41316
+ });
41317
+ function checkDimension(snapshot, signal, min, layout, node, emit, messageId, template, tag, policyName) {
41318
+ const px = readKnownPx(snapshot, signal);
41319
+ if (px === null) return;
41320
+ if (px >= min) return;
41321
+ emitLayoutDiagnostic(
41322
+ layout,
41323
+ node,
41324
+ emit,
41325
+ jsxLayoutPolicyTouchTarget.id,
41326
+ messageId,
41327
+ template,
41328
+ "warn",
41329
+ {
41330
+ signal,
41331
+ value: formatRounded(px),
41332
+ min: String(min),
41333
+ tag,
41334
+ policy: policyName
41335
+ }
41336
+ );
41337
+ }
41338
+
41160
41339
  // src/cross-file/rules/index.ts
41161
41340
  var rules3 = [
41162
41341
  jsxNoUndefinedCssClass,
@@ -41188,7 +41367,8 @@ var rules3 = [
41188
41367
  cssLayoutOverflowModeToggleInstability,
41189
41368
  cssLayoutBoxSizingToggleWithChrome,
41190
41369
  cssLayoutContentVisibilityNoIntrinsicSize,
41191
- cssLayoutConditionalOffsetShift
41370
+ cssLayoutConditionalOffsetShift,
41371
+ jsxLayoutPolicyTouchTarget
41192
41372
  ];
41193
41373
 
41194
41374
  // src/cross-file/plugin.ts
@@ -41264,6 +41444,7 @@ export {
41264
41444
  classifyFile,
41265
41445
  extensionsToGlobs,
41266
41446
  canonicalPath,
41447
+ Level,
41267
41448
  noopLogger,
41268
41449
  SolidGraph,
41269
41450
  runPhases,
@@ -41284,4 +41465,4 @@ export {
41284
41465
  rules3,
41285
41466
  runCrossFileRules
41286
41467
  };
41287
- //# sourceMappingURL=chunk-BK7TC7DN.js.map
41468
+ //# sourceMappingURL=chunk-MJKIL7DJ.js.map