@jay-framework/design-system-validator 0.24.6 → 0.24.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tools.d.ts CHANGED
@@ -17,6 +17,8 @@ declare const validateFontFallbacks: JayHtmlValidatorFn;
17
17
 
18
18
  declare const validateUndefinedVars: JayHtmlValidatorFn;
19
19
 
20
+ declare const validateViewportHeight: JayHtmlValidatorFn;
21
+
20
22
  declare const ADD_MENU_GENERATED_REL = "agent-kit/aiditor/add-menu/design-system.generated.yaml";
21
23
 
22
24
  /**
@@ -98,4 +100,4 @@ declare const regenerateDesignSystemAddMenu: _jay_framework_fullstack_component.
98
100
  message: any;
99
101
  }, []>;
100
102
 
101
- export { ADD_MENU_GENERATED_REL, generateDesignSystemAgentKit, getDesignSystemSettingsStatus, loadDesignSystemAddMenuCatalog, regenerateDesignSystemAddMenu, runDesignSystemAnalysisAction as runDesignSystemAnalysis, saveDesignSystemAddMenuCatalog, validateComponents, validateContrast, validateFontFallbacks, validateStructure, validateTokens, validateUndefinedVars };
103
+ export { ADD_MENU_GENERATED_REL, generateDesignSystemAgentKit, getDesignSystemSettingsStatus, loadDesignSystemAddMenuCatalog, regenerateDesignSystemAddMenu, runDesignSystemAnalysisAction as runDesignSystemAnalysis, saveDesignSystemAddMenuCatalog, validateComponents, validateContrast, validateFontFallbacks, validateStructure, validateTokens, validateUndefinedVars, validateViewportHeight };
package/dist/tools.js CHANGED
@@ -189,16 +189,26 @@ function parseInlineStyles(style) {
189
189
  }
190
190
  return declarations;
191
191
  }
192
+ function selectorTargetsRoot(root, selector) {
193
+ const trimmed = selector.trim();
194
+ if (trimmed === "html" || trimmed === ":root") return true;
195
+ try {
196
+ return root.closest(trimmed) === root;
197
+ } catch {
198
+ return false;
199
+ }
200
+ }
192
201
  function buildSelectorCache(rules, root) {
193
202
  const cache = /* @__PURE__ */ new Map();
194
203
  for (const rule of rules) {
195
204
  if (cache.has(rule.selector)) continue;
205
+ const matched = /* @__PURE__ */ new Set();
196
206
  try {
197
- const matches = root.querySelectorAll(rule.selector);
198
- cache.set(rule.selector, new Set(matches));
207
+ for (const el of root.querySelectorAll(rule.selector)) matched.add(el);
199
208
  } catch {
200
- cache.set(rule.selector, /* @__PURE__ */ new Set());
201
209
  }
210
+ if (selectorTargetsRoot(root, rule.selector)) matched.add(root);
211
+ cache.set(rule.selector, matched);
202
212
  }
203
213
  return cache;
204
214
  }
@@ -279,9 +289,7 @@ function resolveCascade(cssSources, root) {
279
289
  if (child.nodeType === 1) walk(child);
280
290
  }
281
291
  }
282
- for (const child of root.childNodes) {
283
- if (child.nodeType === 1) walk(child);
284
- }
292
+ walk(root);
285
293
  return result;
286
294
  }
287
295
  function resolveCascadeByBreakpoint(cssSources, root) {
@@ -320,9 +328,7 @@ function resolveCascadeByBreakpoint(cssSources, root) {
320
328
  );
321
329
  const selectorCache = buildSelectorCache(rulesForBreakpoint, root);
322
330
  const breakpointResult = /* @__PURE__ */ new Map();
323
- for (const child of root.childNodes) {
324
- if (child.nodeType === 1) walk(child);
325
- }
331
+ walk(root);
326
332
  result.set(breakpoint, breakpointResult);
327
333
  }
328
334
  return result;
@@ -1251,6 +1257,51 @@ See agent-kit/designer/design-system.md for usage guide.`
1251
1257
  }
1252
1258
  return findings;
1253
1259
  };
1260
+ const VIEWPORT_HEIGHT_UNIT = /\d*\.?\d+(vh|svh|lvh|dvh|vmax)\b/i;
1261
+ const TOP_LEVEL_TAGS = /* @__PURE__ */ new Set(["html", "body", "main"]);
1262
+ const PARENT_TAGS = /* @__PURE__ */ new Set(["body", "main"]);
1263
+ const OUT_OF_FLOW = /* @__PURE__ */ new Set(["fixed", "absolute", "sticky"]);
1264
+ const HEIGHT_PROPS = ["height", "min-height"];
1265
+ function tagOf(el) {
1266
+ return (el?.rawTagName ?? "").toLowerCase();
1267
+ }
1268
+ function usesViewportHeight(value) {
1269
+ return value != null && VIEWPORT_HEIGHT_UNIT.test(value);
1270
+ }
1271
+ function isTopLevel(el) {
1272
+ if (TOP_LEVEL_TAGS.has(tagOf(el))) return true;
1273
+ return PARENT_TAGS.has(tagOf(el.parentNode));
1274
+ }
1275
+ const validateViewportHeight = (ctx) => {
1276
+ if (!ctx.css) return [];
1277
+ if (!ctx.filePath.includes("/pages/") && !ctx.filePath.startsWith("src/pages/")) {
1278
+ return [];
1279
+ }
1280
+ if (ctx.validationOverrides?.["design-system"]?.["allow-viewport-height"] === true) {
1281
+ return [];
1282
+ }
1283
+ const base = resolveCascadeByBreakpoint([ctx.css], ctx.body).get(void 0);
1284
+ if (!base) return [];
1285
+ const findings = [];
1286
+ for (const [el, styles] of base) {
1287
+ if (!isTopLevel(el)) continue;
1288
+ if (OUT_OF_FLOW.has(styles["position"]?.value?.trim().toLowerCase() ?? "")) continue;
1289
+ const maxHeight = styles["max-height"]?.value?.trim();
1290
+ const bounded = maxHeight != null && maxHeight.toLowerCase() !== "none" && !usesViewportHeight(maxHeight);
1291
+ if (bounded) continue;
1292
+ for (const property of HEIGHT_PROPS) {
1293
+ const decl = styles[property];
1294
+ if (!usesViewportHeight(decl?.value)) continue;
1295
+ findings.push({
1296
+ severity: "warning",
1297
+ message: `Top-level container "${decl.selector}" sets ${property}: ${decl.value}. Googlebot renders into a very tall viewport (~12,000px), so viewport-height units expand this section and distort Search Console screenshots / mobile-usability reports.`,
1298
+ suggestion: `Choose a fix by content type — text: chain height from a bounded ancestor; hero/visual: cap with max-height inside a mobile @media; overlay: this is safe, suppress with design-system: { allow-viewport-height: true }. Note: swapping vh → dvh/svh/lvh is NOT a fix (all resolve tall under Googlebot). See agent-kit/designer/jay-html-styling.md (and validation-guide.md for suppression).`,
1299
+ element: `<${tagOf(el)}>`
1300
+ });
1301
+ }
1302
+ }
1303
+ return findings;
1304
+ };
1254
1305
  const PLUGIN_ATTRS = {
1255
1306
  pluginName: "design-system-validator",
1256
1307
  packageName: "@jay-framework/design-system-validator"
@@ -1871,5 +1922,6 @@ export {
1871
1922
  validateFontFallbacks,
1872
1923
  validateStructure,
1873
1924
  validateTokens,
1874
- validateUndefinedVars
1925
+ validateUndefinedVars,
1926
+ validateViewportHeight
1875
1927
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/design-system-validator",
3
- "version": "0.24.6",
3
+ "version": "0.24.7",
4
4
  "type": "module",
5
5
  "description": "Design system validation plugin for Jay Framework — validates jay-html CSS against DESIGN.md tokens",
6
6
  "license": "Apache-2.0",
@@ -37,25 +37,25 @@
37
37
  "@capsizecss/metrics": "^4.2.0",
38
38
  "@capsizecss/unpack": "^4.0.1",
39
39
  "@csstools/selector-specificity": "^5.0.0",
40
- "@jay-framework/component": "^0.24.6",
41
- "@jay-framework/fullstack-component": "^0.24.6",
42
- "@jay-framework/plugin-validator": "^0.24.6",
43
- "@jay-framework/stack-server-runtime": "^0.24.6",
40
+ "@jay-framework/component": "^0.24.7",
41
+ "@jay-framework/fullstack-component": "^0.24.7",
42
+ "@jay-framework/plugin-validator": "^0.24.7",
43
+ "@jay-framework/stack-server-runtime": "^0.24.7",
44
44
  "js-yaml": "^4.1.0",
45
45
  "postcss": "^8.5.6",
46
46
  "postcss-selector-parser": "^7.1.0"
47
47
  },
48
48
  "peerDependencies": {
49
- "@jay-framework/compiler-jay-html": "^0.24.6",
50
- "@jay-framework/compiler-shared": "^0.24.6"
49
+ "@jay-framework/compiler-jay-html": "^0.24.7",
50
+ "@jay-framework/compiler-shared": "^0.24.7"
51
51
  },
52
52
  "devDependencies": {
53
- "@jay-framework/compiler-jay-html": "^0.24.6",
54
- "@jay-framework/compiler-jay-stack": "^0.24.6",
55
- "@jay-framework/compiler-shared": "^0.24.6",
56
- "@jay-framework/dev-environment": "^0.24.6",
57
- "@jay-framework/jay-cli": "^0.24.6",
58
- "@jay-framework/jay-stack-cli": "^0.24.6",
53
+ "@jay-framework/compiler-jay-html": "^0.24.7",
54
+ "@jay-framework/compiler-jay-stack": "^0.24.7",
55
+ "@jay-framework/compiler-shared": "^0.24.7",
56
+ "@jay-framework/dev-environment": "^0.24.7",
57
+ "@jay-framework/jay-cli": "^0.24.7",
58
+ "@jay-framework/jay-stack-cli": "^0.24.7",
59
59
  "@types/js-yaml": "^4.0.9",
60
60
  "@types/node": "^22.15.21",
61
61
  "node-html-parser": "^6.1.0",
package/plugin.yaml CHANGED
@@ -51,3 +51,7 @@ validators:
51
51
  - name: undefined-vars
52
52
  handler: validateUndefinedVars
53
53
  description: Flags CSS var(--name) references that are never defined as custom properties
54
+
55
+ - name: design-viewport-height
56
+ handler: validateViewportHeight
57
+ description: Flags unbounded viewport-height units (vh/svh/lvh/dvh/vmax) on top-level containers that distort Googlebot's tall-viewport render (Search Console screenshots / mobile-usability)