@hyperframes/lint 0.8.36 → 0.8.38
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/browser.js +1 -90
- package/dist/browser.js.map +1 -1
- package/dist/index.js +1 -90
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2843,10 +2843,6 @@ function targetHasNoStableIdentity(selector, identity) {
|
|
|
2843
2843
|
if (identity) return false;
|
|
2844
2844
|
return selector === UNRESOLVED_TARGET || selector === "dwell/hold" || selector.startsWith("proxy \u2192 ");
|
|
2845
2845
|
}
|
|
2846
|
-
function readRegisteredTimelineCompositionId(script) {
|
|
2847
|
-
const match = script.match(WINDOW_TIMELINE_ASSIGN_PATTERN);
|
|
2848
|
-
return match?.[1] || match?.[2] || null;
|
|
2849
|
-
}
|
|
2850
2846
|
function unwrapRaw(value) {
|
|
2851
2847
|
if (typeof value === "number") return value;
|
|
2852
2848
|
if (typeof value !== "string") return void 0;
|
|
@@ -3014,21 +3010,6 @@ function makesOverlayVisible(win) {
|
|
|
3014
3010
|
if (win.method === "from" && isHiddenGsapState(win.propertyValues)) return true;
|
|
3015
3011
|
return isVisibleGsapState(win.propertyValues);
|
|
3016
3012
|
}
|
|
3017
|
-
function isSceneBoundaryExit(win) {
|
|
3018
|
-
if (win.end <= win.position) return false;
|
|
3019
|
-
if (win.method !== "to" && win.method !== "fromTo") return false;
|
|
3020
|
-
return isHiddenGsapState(win.propertyValues);
|
|
3021
|
-
}
|
|
3022
|
-
function isHardKillSet(win, selector, boundary) {
|
|
3023
|
-
return win.method === "set" && win.targetSelector === selector && Math.abs(win.position - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues);
|
|
3024
|
-
}
|
|
3025
|
-
function hiddenStateLiteral(values) {
|
|
3026
|
-
if (zeroValue(values.autoAlpha)) return "{ autoAlpha: 0 }";
|
|
3027
|
-
if (zeroValue(values.opacity)) return "{ opacity: 0 }";
|
|
3028
|
-
if (stringValue(values.visibility)?.toLowerCase() === "hidden") return '{ visibility: "hidden" }';
|
|
3029
|
-
if (stringValue(values.display)?.toLowerCase() === "none") return '{ display: "none" }';
|
|
3030
|
-
return "{ opacity: 0 }";
|
|
3031
|
-
}
|
|
3032
3013
|
function findTagEnd(source, tag) {
|
|
3033
3014
|
const escapedTagName = tag.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3034
3015
|
const pattern = new RegExp(`<\\/?${escapedTagName}\\b[^>]*>`, "gi");
|
|
@@ -3045,56 +3026,11 @@ function findTagEnd(source, tag) {
|
|
|
3045
3026
|
}
|
|
3046
3027
|
return source.length;
|
|
3047
3028
|
}
|
|
3048
|
-
function collectCompositionRanges(source, tags) {
|
|
3049
|
-
return tags.map((tag) => {
|
|
3050
|
-
const id = readDecodedAttr(tag.raw, "data-composition-id");
|
|
3051
|
-
if (!id) return null;
|
|
3052
|
-
return {
|
|
3053
|
-
id,
|
|
3054
|
-
start: tag.index,
|
|
3055
|
-
end: findTagEnd(source, tag)
|
|
3056
|
-
};
|
|
3057
|
-
}).filter((range) => range !== null);
|
|
3058
|
-
}
|
|
3059
|
-
function findContainingCompositionId(tag, ranges) {
|
|
3060
|
-
let match = null;
|
|
3061
|
-
for (const range of ranges) {
|
|
3062
|
-
if (tag.index < range.start || tag.index >= range.end) continue;
|
|
3063
|
-
if (!match || range.start >= match.start) match = range;
|
|
3064
|
-
}
|
|
3065
|
-
return match?.id || null;
|
|
3066
|
-
}
|
|
3067
3029
|
function getClipTagClasses(tag) {
|
|
3068
3030
|
const classAttr = readAttr(tag.raw, "class") || "";
|
|
3069
3031
|
const classes = classAttr.split(/\s+/).filter(Boolean);
|
|
3070
3032
|
return classes.includes("clip") ? { classAttr, classes } : null;
|
|
3071
3033
|
}
|
|
3072
|
-
function collectClipStartBoundariesByComposition(source, tags) {
|
|
3073
|
-
const ranges = collectCompositionRanges(source, tags);
|
|
3074
|
-
const boundaries = /* @__PURE__ */ new Map();
|
|
3075
|
-
for (const tag of tags) {
|
|
3076
|
-
if (!getClipTagClasses(tag)) continue;
|
|
3077
|
-
const compositionId = findContainingCompositionId(tag, ranges);
|
|
3078
|
-
if (!compositionId) continue;
|
|
3079
|
-
const start = numberValue(readAttr(tag.raw, "data-start") ?? void 0);
|
|
3080
|
-
if (start == null || start <= 0) continue;
|
|
3081
|
-
const compositionBoundaries = boundaries.get(compositionId) ?? /* @__PURE__ */ new Set();
|
|
3082
|
-
compositionBoundaries.add(start);
|
|
3083
|
-
boundaries.set(compositionId, compositionBoundaries);
|
|
3084
|
-
}
|
|
3085
|
-
return new Map(
|
|
3086
|
-
[...boundaries.entries()].map(([compositionId, values]) => [
|
|
3087
|
-
compositionId,
|
|
3088
|
-
[...values].sort((a, b) => a - b)
|
|
3089
|
-
])
|
|
3090
|
-
);
|
|
3091
|
-
}
|
|
3092
|
-
function findMatchingSceneBoundary(time, boundaries) {
|
|
3093
|
-
for (const boundary of boundaries) {
|
|
3094
|
-
if (Math.abs(time - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS) return boundary;
|
|
3095
|
-
}
|
|
3096
|
-
return null;
|
|
3097
|
-
}
|
|
3098
3034
|
function readStyleProperty(style, property) {
|
|
3099
3035
|
const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3100
3036
|
const match = style.match(new RegExp(`(?:^|;)\\s*${escapedProperty}\\s*:\\s*([^;]+)`, "i"));
|
|
@@ -3593,7 +3529,7 @@ var gsapRules = [
|
|
|
3593
3529
|
},
|
|
3594
3530
|
// overlapping_gsap_tweens + gsap_animates_clip_element
|
|
3595
3531
|
// fallow-ignore-next-line complexity
|
|
3596
|
-
async ({
|
|
3532
|
+
async ({ tags, scripts, styles }) => {
|
|
3597
3533
|
const findings = [];
|
|
3598
3534
|
const authoredHiddenSelectors = new Set(
|
|
3599
3535
|
scripts.flatMap((script) => [...extractStandaloneHiddenSelectors(script.content)])
|
|
@@ -3614,13 +3550,10 @@ var gsapRules = [
|
|
|
3614
3550
|
if (cls !== "clip") clipClasses.set(`.${cls}`, info);
|
|
3615
3551
|
}
|
|
3616
3552
|
}
|
|
3617
|
-
const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);
|
|
3618
3553
|
const styleRules = collectSimpleStyleRules(styles);
|
|
3619
3554
|
const reportedVisibleOverlayKeys = /* @__PURE__ */ new Set();
|
|
3620
3555
|
for (const script of scripts) {
|
|
3621
|
-
const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
|
|
3622
3556
|
const gsapWindows = await cachedExtractGsapWindows(script.content);
|
|
3623
|
-
const clipStartBoundaries = clipStartBoundariesByComposition.get(localTimelineCompId || rootCompositionId || "") ?? [];
|
|
3624
3557
|
for (let i = 0; i < gsapWindows.length; i++) {
|
|
3625
3558
|
const left = gsapWindows[i];
|
|
3626
3559
|
if (!left) continue;
|
|
@@ -3682,28 +3615,6 @@ ${right.raw}`)
|
|
|
3682
3615
|
snippet: truncateSnippet(fromToWindows.map((win) => win.raw).join("\n"))
|
|
3683
3616
|
});
|
|
3684
3617
|
}
|
|
3685
|
-
if (clipStartBoundaries.length > 0) {
|
|
3686
|
-
for (const win of gsapWindows) {
|
|
3687
|
-
if (win.targetSelector === UNRESOLVED_TARGET) continue;
|
|
3688
|
-
if (!isSceneBoundaryExit(win)) continue;
|
|
3689
|
-
const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);
|
|
3690
|
-
if (boundary == null) continue;
|
|
3691
|
-
const hasHardKill = gsapWindows.some(
|
|
3692
|
-
(candidate) => isHardKillSet(candidate, win.targetSelector, boundary)
|
|
3693
|
-
);
|
|
3694
|
-
if (hasHardKill) continue;
|
|
3695
|
-
const exitClipInfo = clipIds.get(win.targetSelector) || clipClasses.get(win.targetSelector);
|
|
3696
|
-
const fixHint = exitClipInfo ? `"${win.targetSelector}" is a clip element \u2014 the framework already manages its visibility. Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill (\`tl.set("<inner-selector>", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\`) onto that wrapper instead.` : `Add \`tl.set("${win.targetSelector}", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\` after the exit tween.`;
|
|
3697
|
-
findings.push({
|
|
3698
|
-
code: "gsap_exit_missing_hard_kill",
|
|
3699
|
-
severity: "error",
|
|
3700
|
-
message: `GSAP exit on "${win.targetSelector}" ends at the ${boundary.toFixed(2)}s clip start boundary without a matching tl.set hard kill. Non-linear seeking can land after the fade and leave stale visibility state.`,
|
|
3701
|
-
selector: win.targetSelector,
|
|
3702
|
-
fixHint,
|
|
3703
|
-
snippet: truncateSnippet(win.raw)
|
|
3704
|
-
});
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
3618
|
for (const tag of tags) {
|
|
3708
3619
|
const selectors = tagSimpleSelectors(tag);
|
|
3709
3620
|
if (selectors.length === 0) continue;
|