@hortonstudio/main 1.7.16 → 1.8.0

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.
@@ -661,6 +661,78 @@ export function init() {
661
661
  tocList.appendChild(tocItem);
662
662
  });
663
663
 
664
+ // Set up IntersectionObserver for active state
665
+ const sections = Array.from(h2Headings).map(heading => heading.parentElement);
666
+ const tocLinks = tocList.querySelectorAll('a');
667
+ let currentActiveId = null;
668
+
669
+ const observerOptions = {
670
+ rootMargin: '-10% 0px -50% 0px',
671
+ threshold: [0, 0.25, 0.5, 0.75, 1]
672
+ };
673
+
674
+ const observer = new IntersectionObserver((entries) => {
675
+ // Collect all currently intersecting sections
676
+ const intersectingSections = [];
677
+
678
+ entries.forEach(entry => {
679
+ const sectionId = entry.target.id;
680
+ const existingIndex = intersectingSections.findIndex(s => s.id === sectionId);
681
+
682
+ if (entry.isIntersecting) {
683
+ if (existingIndex === -1) {
684
+ intersectingSections.push({
685
+ id: sectionId,
686
+ ratio: entry.intersectionRatio,
687
+ element: entry.target
688
+ });
689
+ } else {
690
+ intersectingSections[existingIndex].ratio = entry.intersectionRatio;
691
+ }
692
+ }
693
+ });
694
+
695
+ // Find all currently intersecting sections (not just from this batch)
696
+ const allIntersecting = sections
697
+ .filter(section => {
698
+ const rect = section.getBoundingClientRect();
699
+ const windowHeight = window.innerHeight;
700
+ // Check if section is in the active zone
701
+ return rect.top < windowHeight * 0.6 && rect.bottom > windowHeight * 0.1;
702
+ })
703
+ .map(section => ({
704
+ id: section.id,
705
+ top: section.getBoundingClientRect().top,
706
+ element: section
707
+ }));
708
+
709
+ if (allIntersecting.length === 0) return;
710
+
711
+ // Pick the topmost section in the active zone
712
+ const topmost = allIntersecting.reduce((prev, curr) =>
713
+ curr.top < prev.top ? curr : prev
714
+ );
715
+
716
+ // Only update if the active section changed
717
+ if (currentActiveId !== topmost.id) {
718
+ currentActiveId = topmost.id;
719
+
720
+ // Remove is-active from all links
721
+ tocLinks.forEach(link => link.classList.remove('is-active'));
722
+
723
+ // Add is-active to the corresponding link
724
+ const activeLink = Array.from(tocLinks).find(link =>
725
+ link.getAttribute('href') === `#${topmost.id}`
726
+ );
727
+ if (activeLink) {
728
+ activeLink.classList.add('is-active');
729
+ }
730
+ }
731
+ }, observerOptions);
732
+
733
+ // Observe all sections
734
+ sections.forEach(section => observer.observe(section));
735
+
664
736
  });
665
737
  }
666
738
 
package/index.js CHANGED
@@ -9,6 +9,9 @@ const initializeHsMain = async () => {
9
9
  return;
10
10
  }
11
11
 
12
+ // Add hs-main class to HTML element immediately
13
+ document.documentElement.classList.add('hs-main');
14
+
12
15
  const queuedModules = Array.isArray(window[API_NAME]) ? window[API_NAME] : [];
13
16
 
14
17
  const animationModules = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hortonstudio/main",
3
- "version": "1.7.16",
3
+ "version": "1.8.0",
4
4
  "description": "Animation and utility library for client websites",
5
5
  "main": "index.js",
6
6
  "type": "module",