@jump-section/core 1.0.20 → 1.0.22

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <img src="https://raw.githubusercontent.com/bae080311/jump-section/main/docs/public/logo.png" alt="Jump Section Logo" width="200" />
5
5
  </div>
6
6
 
7
- Core scroll management library for jump-section. Framework-agnostic scroll navigation with intersection observer.
7
+ Framework-agnostic scroll section management library. Tracks active sections via IntersectionObserver and provides programmatic scroll navigation.
8
8
 
9
9
  ## Installation
10
10
 
@@ -21,31 +21,29 @@ yarn add @jump-section/core
21
21
  ```typescript
22
22
  import { ScrollManager } from '@jump-section/core';
23
23
 
24
- // Create a scroll manager instance
25
24
  const manager = new ScrollManager({
26
- offset: -80, // Offset for fixed headers (optional)
27
- behavior: 'smooth', // Scroll behavior (optional)
25
+ offset: -80,
26
+ behavior: 'smooth',
27
+ hash: true,
28
+ keyboard: true,
28
29
  });
29
30
 
30
31
  // Register sections
31
- const section1 = document.getElementById('section-1');
32
- const section2 = document.getElementById('section-2');
33
-
34
- manager.registerSection('section-1', section1);
35
- manager.registerSection('section-2', section2);
32
+ manager.registerSection('section-1', document.getElementById('section-1')!);
33
+ manager.registerSection('section-2', document.getElementById('section-2')!);
36
34
 
37
35
  // Scroll to a section
38
- manager.scrollTo('section-1');
36
+ await manager.scrollTo('section-1');
39
37
 
40
38
  // Listen to active section changes
41
- const unsubscribe = manager.onActiveChange((activeId) => {
39
+ const unsubscribe = manager.onActiveChange((activeId, meta) => {
42
40
  console.log('Active section:', activeId);
41
+ console.log('Previous:', meta.previous, 'Direction:', meta.direction);
43
42
  });
44
43
 
45
44
  // Cleanup
46
- manager.unregisterSection('section-1');
47
- manager.destroy();
48
45
  unsubscribe();
46
+ manager.destroy();
49
47
  ```
50
48
 
51
49
  ## API
@@ -60,30 +58,76 @@ new ScrollManager(options?: ScrollOptions)
60
58
 
61
59
  **Options:**
62
60
 
63
- - `offset?: number` - Vertical offset in pixels (useful for fixed headers)
64
- - `behavior?: ScrollBehavior` - Scroll behavior: `'smooth'` | `'instant'` | `'auto'`
61
+ | Option | Type | Default | Description |
62
+ | ---------- | --------------------- | ---------- | ---------------------------------------------------------- |
63
+ | `offset` | `number` | `0` | Vertical offset in pixels (useful for fixed headers) |
64
+ | `behavior` | `ScrollBehavior` | `'smooth'` | Scroll behavior: `'smooth'` \| `'instant'` \| `'auto'` |
65
+ | `hash` | `boolean` | `false` | Sync active section with URL hash |
66
+ | `root` | `HTMLElement \| null` | `null` | Custom scroll container (defaults to `window`) |
67
+ | `keyboard` | `boolean` | `false` | Enable `Alt+ArrowDown` / `Alt+ArrowUp` keyboard navigation |
65
68
 
66
69
  #### Methods
67
70
 
68
71
  ##### `registerSection(id: string, element: HTMLElement): void`
69
72
 
70
- Registers a section element to be tracked by the scroll manager.
73
+ Registers a section element to be tracked.
71
74
 
72
75
  ##### `unregisterSection(id: string): void`
73
76
 
74
77
  Unregisters a section from tracking.
75
78
 
76
- ##### `scrollTo(id: string): void`
79
+ ##### `scrollTo(id: string): Promise<void>`
80
+
81
+ Scrolls to the specified section. Returns a Promise that resolves when scrolling is complete.
82
+
83
+ ##### `scrollToNext(): Promise<void>`
84
+
85
+ Scrolls to the next section in DOM order.
77
86
 
78
- Scrolls to the specified section.
87
+ ##### `scrollToPrev(): Promise<void>`
79
88
 
80
- ##### `onActiveChange(callback: (id: string | null) => void): () => void`
89
+ Scrolls to the previous section in DOM order.
90
+
91
+ ##### `scrollToFirst(): Promise<void>`
92
+
93
+ Scrolls to the first registered section.
94
+
95
+ ##### `scrollToLast(): Promise<void>`
96
+
97
+ Scrolls to the last registered section.
98
+
99
+ ##### `onActiveChange(callback: (id: string | null, meta: ActiveChangeMeta) => void): () => void`
81
100
 
82
101
  Subscribes to active section changes. Returns an unsubscribe function.
83
102
 
103
+ `ActiveChangeMeta`:
104
+
105
+ - `previous: string | null` — previously active section ID
106
+ - `direction: 'up' | 'down' | null` — scroll direction at the time of change
107
+
108
+ ##### `onProgressChange(id: string, callback: (progress: number) => void): () => void`
109
+
110
+ Subscribes to scroll progress (0–1) for a specific section. Returns an unsubscribe function.
111
+
112
+ ##### `disableSection(id: string): void`
113
+
114
+ Temporarily excludes a section from active tracking.
115
+
116
+ ##### `enableSection(id: string): void`
117
+
118
+ Re-includes a previously disabled section in active tracking.
119
+
120
+ ##### `getSections(): string[]`
121
+
122
+ Returns registered section IDs sorted by DOM position (top to bottom), excluding disabled sections.
123
+
124
+ ##### `getActiveId(): string | null`
125
+
126
+ Returns the currently active section ID.
127
+
84
128
  ##### `destroy(): void`
85
129
 
86
- Cleans up the scroll manager and removes all observers.
130
+ Cleans up all observers, event listeners, and internal state.
87
131
 
88
132
  ## License
89
133
 
package/dist/index.d.mts CHANGED
@@ -64,12 +64,12 @@ declare class ScrollManager {
64
64
  scrollToFirst(): Promise<void>;
65
65
  /** 마지막 섹션으로 스크롤합니다 */
66
66
  scrollToLast(): Promise<void>;
67
- /** 활성 섹션 변경 호출될 콜백을 등록합니다. 구독 해제 함수를 반환합니다 */
67
+ /** 활성 섹션 변경 이벤트를 구독합니다 */
68
68
  onActiveChange(callback: ActiveChangeCallback): () => void;
69
- /** 특정 섹션의 스크롤 진행률(0~1) 변경 시 호출될 콜백을 등록합니다 */
70
- onProgressChange(id: string, callback: ProgressCallback): () => void;
71
69
  private notifyListeners;
72
- /** 모든 리소스를 정리합니다 */
70
+ /** 특정 섹션의 스크롤 진행률 이벤트를 구독합니다 */
71
+ onProgressChange(sectionId: string, callback: ProgressCallback): () => void;
72
+ /** 등록된 모든 이벤트 리스너와 Observer를 해제하고 정리합니다 */
73
73
  destroy(): void;
74
74
  }
75
75
 
package/dist/index.d.ts CHANGED
@@ -64,12 +64,12 @@ declare class ScrollManager {
64
64
  scrollToFirst(): Promise<void>;
65
65
  /** 마지막 섹션으로 스크롤합니다 */
66
66
  scrollToLast(): Promise<void>;
67
- /** 활성 섹션 변경 호출될 콜백을 등록합니다. 구독 해제 함수를 반환합니다 */
67
+ /** 활성 섹션 변경 이벤트를 구독합니다 */
68
68
  onActiveChange(callback: ActiveChangeCallback): () => void;
69
- /** 특정 섹션의 스크롤 진행률(0~1) 변경 시 호출될 콜백을 등록합니다 */
70
- onProgressChange(id: string, callback: ProgressCallback): () => void;
71
69
  private notifyListeners;
72
- /** 모든 리소스를 정리합니다 */
70
+ /** 특정 섹션의 스크롤 진행률 이벤트를 구독합니다 */
71
+ onProgressChange(sectionId: string, callback: ProgressCallback): () => void;
72
+ /** 등록된 모든 이벤트 리스너와 Observer를 해제하고 정리합니다 */
73
73
  destroy(): void;
74
74
  }
75
75
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var b=Object.defineProperty;var p=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var d=(l,e,t)=>e in l?b(l,e,{enumerable:true,configurable:true,writable:true,value:t}):l[e]=t,u=(l,e)=>{for(var t in e||(e={}))w.call(e,t)&&d(l,t,e[t]);if(p)for(var t of p(e))S.call(e,t)&&d(l,t,e[t]);return l};var o=(l,e,t)=>d(l,typeof e!="symbol"?e+"":e,t);var v=class{constructor(e={}){o(this,"sections",new Map);o(this,"disabledSections",new Set);o(this,"observer",null);o(this,"resizeObserver",null);o(this,"activeId",null);o(this,"previousId",null);o(this,"lastScrollY",0);o(this,"scrollDirection",null);o(this,"listeners",new Set);o(this,"progressListeners",new Map);o(this,"options");o(this,"keyboardHandler",null);o(this,"scrollHandler",null);o(this,"popstateHandler",null);o(this,"notifyScheduled",false);o(this,"handleIntersection",e=>{var c;let t=e.filter(n=>n.isIntersecting);if(t.length===0)return;let i=t.reduce((n,a)=>n.intersectionRatio>a.intersectionRatio?n:a),s=[...this.sections.entries()].find(([,n])=>n===i.target),r=(c=s==null?void 0:s[0])!=null?c:i.target.id;!r||r===this.activeId||this.disabledSections.has(r)||(this.previousId=this.activeId,this.activeId=r,this.scheduleNotify(),this.options.hash&&history.replaceState(null,"",`#${r}`));});this.options=u({offset:0,behavior:"smooth",hash:false,root:null,keyboard:false},e),this.initObserver(),this.initScrollListener(),this.options.hash&&this.initHashSync(),this.options.keyboard&&this.initKeyboard();}get scrollRoot(){var e;return (e=this.options.root)!=null?e:window}get currentScrollTop(){return this.options.root?this.options.root.scrollTop:window.scrollY}initObserver(){var e;typeof window!="undefined"&&(this.observer=new IntersectionObserver(this.handleIntersection,{root:(e=this.options.root)!=null?e:null,rootMargin:"-20% 0px -60% 0px",threshold:[0,.1,.5,1]}),typeof ResizeObserver!="undefined"&&(this.resizeObserver=new ResizeObserver(()=>{this.sections.forEach(t=>{var i,s;(i=this.observer)==null||i.unobserve(t),(s=this.observer)==null||s.observe(t);});})));}initScrollListener(){typeof window!="undefined"&&(this.scrollHandler=()=>{let e=this.currentScrollTop;e!==this.lastScrollY&&(this.scrollDirection=e>this.lastScrollY?"down":"up",this.lastScrollY=e),this.updateProgress();},this.scrollRoot.addEventListener("scroll",this.scrollHandler,{passive:true}));}initHashSync(){typeof window!="undefined"&&(this.popstateHandler=()=>{let e=window.location.hash.slice(1);e&&this.sections.has(e)&&this.scrollTo(e);},window.addEventListener("popstate",this.popstateHandler));}initKeyboard(){typeof window!="undefined"&&(this.keyboardHandler=e=>{e.altKey&&(e.key==="ArrowDown"?(e.preventDefault(),this.scrollToNext()):e.key==="ArrowUp"&&(e.preventDefault(),this.scrollToPrev()));},document.addEventListener("keydown",this.keyboardHandler));}scheduleNotify(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.notifyListeners();}));}updateProgress(){if(this.progressListeners.size===0)return;let e=this.currentScrollTop,t=this.options.root?this.options.root.clientHeight:window.innerHeight;this.progressListeners.forEach((i,s)=>{if(i.size===0)return;let r=this.sections.get(s);if(!r)return;let c=r.getBoundingClientRect(),n=this.options.root?c.top-this.options.root.getBoundingClientRect().top+this.options.root.scrollTop:c.top+e,a=r.offsetHeight||c.height;if(a===0)return;let h=(e-n+t*.2)/a,f=Math.max(0,Math.min(1,h));i.forEach(g=>g(f));});}registerSection(e,t){var i,s;typeof window!="undefined"&&t&&(this.sections.set(e,t),t.id||(t.id=e),(i=this.observer)==null||i.observe(t),(s=this.resizeObserver)==null||s.observe(t),this.options.hash&&window.location.hash===`#${e}`&&setTimeout(()=>this.scrollTo(e),0));}unregisterSection(e){var i,s;let t=this.sections.get(e);t&&((i=this.observer)==null||i.unobserve(t),(s=this.resizeObserver)==null||s.unobserve(t)),this.sections.delete(e),this.disabledSections.delete(e),this.progressListeners.delete(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}disableSection(e){this.disabledSections.add(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}enableSection(e){this.disabledSections.delete(e);}getSections(){return [...this.sections.entries()].filter(([e])=>!this.disabledSections.has(e)).sort(([,e],[,t])=>{let i=e.getBoundingClientRect().top,s=t.getBoundingClientRect().top;return i-s}).map(([e])=>e)}getActiveId(){return this.activeId}scrollTo(e){if(typeof window=="undefined")return Promise.resolve();let t=this.sections.get(e);if(!t)return console.warn(`[ScrollManager] Section with id "${e}" not found. Available sections: ${Array.from(this.sections.keys()).join(", ")}`),Promise.resolve();let{offset:i,behavior:s}=this.options;if(this.options.root){let r=t.offsetTop;this.options.root.scrollTo({top:r+i,behavior:s});}else {let r=t.getBoundingClientRect().top+window.scrollY;window.scrollTo({top:r+i,behavior:s});}return new Promise(r=>{if(s==="auto"||s==="instant"){r();return}let c=this.currentScrollTop,n,a=()=>{let h=this.currentScrollTop;if(h===c){cancelAnimationFrame(n),r();return}c=h,n=requestAnimationFrame(a);};n=requestAnimationFrame(a),setTimeout(()=>{cancelAnimationFrame(n),r();},1e3);})}scrollToNext(){let e=this.getSections(),t=this.activeId?e.indexOf(this.activeId):-1,i=e[t+1];return i?this.scrollTo(i):Promise.resolve()}scrollToPrev(){let e=this.getSections(),t=this.activeId?e.indexOf(this.activeId):e.length,i=e[t-1];return i?this.scrollTo(i):Promise.resolve()}scrollToFirst(){let e=this.getSections();return e.length>0?this.scrollTo(e[0]):Promise.resolve()}scrollToLast(){let e=this.getSections();return e.length>0?this.scrollTo(e[e.length-1]):Promise.resolve()}onActiveChange(e){return this.listeners.add(e),e(this.activeId,{previous:this.previousId,direction:this.scrollDirection}),()=>this.listeners.delete(e)}onProgressChange(e,t){return this.progressListeners.has(e)||this.progressListeners.set(e,new Set),this.progressListeners.get(e).add(t),()=>{let i=this.progressListeners.get(e);i&&(i.delete(t),i.size===0&&this.progressListeners.delete(e));}}notifyListeners(){let e={previous:this.previousId,direction:this.scrollDirection};this.listeners.forEach(t=>t(this.activeId,e));}destroy(){var e,t;(e=this.observer)==null||e.disconnect(),(t=this.resizeObserver)==null||t.disconnect(),this.scrollHandler&&(this.scrollRoot.removeEventListener("scroll",this.scrollHandler),this.scrollHandler=null),this.keyboardHandler&&(document.removeEventListener("keydown",this.keyboardHandler),this.keyboardHandler=null),this.popstateHandler&&(window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null),this.sections.clear(),this.listeners.clear(),this.progressListeners.clear(),this.disabledSections.clear();}};exports.ScrollManager=v;
1
+ 'use strict';var b=Object.defineProperty;var u=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var p=(l,e,t)=>e in l?b(l,e,{enumerable:true,configurable:true,writable:true,value:t}):l[e]=t,v=(l,e)=>{for(var t in e||(e={}))w.call(e,t)&&p(l,t,e[t]);if(u)for(var t of u(e))S.call(e,t)&&p(l,t,e[t]);return l};var r=(l,e,t)=>p(l,typeof e!="symbol"?e+"":e,t);var f=class{constructor(e={}){r(this,"sections",new Map);r(this,"disabledSections",new Set);r(this,"observer",null);r(this,"resizeObserver",null);r(this,"activeId",null);r(this,"previousId",null);r(this,"lastScrollY",0);r(this,"scrollDirection",null);r(this,"listeners",new Set);r(this,"progressListeners",new Map);r(this,"options");r(this,"keyboardHandler",null);r(this,"scrollHandler",null);r(this,"popstateHandler",null);r(this,"notifyScheduled",false);r(this,"handleIntersection",e=>{let t=e.filter(o=>o.isIntersecting);if(t.length===0){this.activeId!==null&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());return}let s=t.reduce((o,n)=>o.intersectionRatio>n.intersectionRatio?o:n),i;for(let[o,n]of this.sections)if(n===s.target){i=o;break}i=i!=null?i:s.target.id,!(!i||i===this.activeId||this.disabledSections.has(i))&&(this.previousId=this.activeId,this.activeId=i,this.scheduleNotify(),this.options.hash&&history.replaceState(null,"",`#${i}`));});this.options=v({offset:0,behavior:"smooth",hash:false,root:null,keyboard:false},e),this.initObserver(),this.initScrollListener(),this.options.hash&&this.initHashSync(),this.options.keyboard&&this.initKeyboard();}get scrollRoot(){var e;return (e=this.options.root)!=null?e:window}get currentScrollTop(){return this.options.root?this.options.root.scrollTop:window.scrollY}initObserver(){var e;typeof window!="undefined"&&(this.observer=new IntersectionObserver(this.handleIntersection,{root:(e=this.options.root)!=null?e:null,rootMargin:"-20% 0px -60% 0px",threshold:[0,.1,.5,1]}),typeof ResizeObserver!="undefined"&&(this.resizeObserver=new ResizeObserver(()=>{this.sections.forEach(t=>{var s,i;(s=this.observer)==null||s.unobserve(t),(i=this.observer)==null||i.observe(t);});})));}initScrollListener(){typeof window!="undefined"&&(this.scrollHandler=()=>{let e=this.currentScrollTop;e!==this.lastScrollY&&(this.scrollDirection=e>this.lastScrollY?"down":"up",this.lastScrollY=e),this.updateProgress();},this.scrollRoot.addEventListener("scroll",this.scrollHandler,{passive:true}));}initHashSync(){typeof window!="undefined"&&(this.popstateHandler=()=>{let e=window.location.hash.slice(1);e&&this.sections.has(e)&&this.scrollTo(e);},window.addEventListener("popstate",this.popstateHandler));}initKeyboard(){typeof window!="undefined"&&(this.keyboardHandler=e=>{e.altKey&&(e.key==="ArrowDown"?(e.preventDefault(),this.scrollToNext()):e.key==="ArrowUp"&&(e.preventDefault(),this.scrollToPrev()));},document.addEventListener("keydown",this.keyboardHandler));}scheduleNotify(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.notifyListeners();}));}updateProgress(){if(this.progressListeners.size===0)return;let e=this.currentScrollTop,t=this.options.root?this.options.root.clientHeight:window.innerHeight;this.progressListeners.forEach((s,i)=>{if(s.size===0)return;let o=this.sections.get(i);if(!o)return;let n=o.getBoundingClientRect(),a=this.options.root?n.top-this.options.root.getBoundingClientRect().top+this.options.root.scrollTop:n.top+e,c=o.offsetHeight||n.height;if(c===0)return;let h=(e-a+t*.2)/c,d=Math.max(0,Math.min(1,h));s.forEach(g=>g(d));});}registerSection(e,t){var s,i;typeof window!="undefined"&&t&&(this.sections.set(e,t),t.id||(t.id=e),(s=this.observer)==null||s.observe(t),(i=this.resizeObserver)==null||i.observe(t),this.options.hash&&window.location.hash===`#${e}`&&setTimeout(()=>this.scrollTo(e),0));}unregisterSection(e){var s,i;let t=this.sections.get(e);t&&((s=this.observer)==null||s.unobserve(t),(i=this.resizeObserver)==null||i.unobserve(t)),this.sections.delete(e),this.disabledSections.delete(e),this.progressListeners.delete(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}disableSection(e){this.disabledSections.add(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}enableSection(e){this.disabledSections.delete(e);}getSections(){return [...this.sections.entries()].filter(([e])=>!this.disabledSections.has(e)).sort(([,e],[,t])=>{let s=e.getBoundingClientRect().top,i=t.getBoundingClientRect().top;return s-i}).map(([e])=>e)}getActiveId(){return this.activeId}scrollTo(e){var a;if(typeof window=="undefined")return Promise.resolve();let t=this.sections.get(e);if(!t)return console.warn(`[ScrollManager] Section with id "${e}" not found. Available sections: ${Array.from(this.sections.keys()).join(", ")}`),Promise.resolve();let s=t.getBoundingClientRect(),i=((a=this.options.root)==null?void 0:a.getBoundingClientRect())||{top:0},o=s.top+this.currentScrollTop-i.top+this.options.offset,n=this.options.root||window;return new Promise(c=>{let h=()=>{(Math.abs(this.currentScrollTop-o)<1||n===window&&window.innerHeight+window.scrollY>=document.body.offsetHeight||this.options.root&&this.options.root.clientHeight+this.options.root.scrollTop>=this.options.root.scrollHeight)&&(n.removeEventListener("scroll",h),clearTimeout(d),c());},d=setTimeout(()=>{n.removeEventListener("scroll",h),c();},1e3);this.options.behavior==="smooth"?n.addEventListener("scroll",h,{passive:true}):(clearTimeout(d),c()),this.options.root?this.options.root.scrollTo({top:o,behavior:this.options.behavior}):window.scrollTo({top:o,behavior:this.options.behavior});})}scrollToNext(){let e=this.getSections(),s=(this.activeId?e.indexOf(this.activeId):-1)+1;return s<e.length?this.scrollTo(e[s]):Promise.resolve()}scrollToPrev(){let e=this.getSections(),s=(this.activeId?e.indexOf(this.activeId):-1)-1;return s>=0?this.scrollTo(e[s]):Promise.resolve()}scrollToFirst(){let e=this.getSections();return e.length>0?this.scrollTo(e[0]):Promise.resolve()}scrollToLast(){let e=this.getSections();return e.length>0?this.scrollTo(e[e.length-1]):Promise.resolve()}onActiveChange(e){return this.listeners.add(e),e(this.activeId,{previous:this.previousId,direction:this.scrollDirection}),()=>{this.listeners.delete(e);}}notifyListeners(){let e={previous:this.previousId,direction:this.scrollDirection};this.listeners.forEach(t=>t(this.activeId,e));}onProgressChange(e,t){var s;return this.progressListeners.has(e)||this.progressListeners.set(e,new Set),(s=this.progressListeners.get(e))==null||s.add(t),this.updateProgress(),()=>{var i;(i=this.progressListeners.get(e))==null||i.delete(t);}}destroy(){var e,t;(e=this.observer)==null||e.disconnect(),(t=this.resizeObserver)==null||t.disconnect(),this.sections.forEach(s=>{var i,o;(i=this.observer)==null||i.unobserve(s),(o=this.resizeObserver)==null||o.unobserve(s);}),this.sections.clear(),this.disabledSections.clear(),this.listeners.clear(),this.progressListeners.clear(),this.scrollHandler&&this.scrollRoot.removeEventListener("scroll",this.scrollHandler),this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),this.keyboardHandler&&document.removeEventListener("keydown",this.keyboardHandler);}};exports.ScrollManager=f;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var b=Object.defineProperty;var p=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var d=(l,e,t)=>e in l?b(l,e,{enumerable:true,configurable:true,writable:true,value:t}):l[e]=t,u=(l,e)=>{for(var t in e||(e={}))w.call(e,t)&&d(l,t,e[t]);if(p)for(var t of p(e))S.call(e,t)&&d(l,t,e[t]);return l};var o=(l,e,t)=>d(l,typeof e!="symbol"?e+"":e,t);var v=class{constructor(e={}){o(this,"sections",new Map);o(this,"disabledSections",new Set);o(this,"observer",null);o(this,"resizeObserver",null);o(this,"activeId",null);o(this,"previousId",null);o(this,"lastScrollY",0);o(this,"scrollDirection",null);o(this,"listeners",new Set);o(this,"progressListeners",new Map);o(this,"options");o(this,"keyboardHandler",null);o(this,"scrollHandler",null);o(this,"popstateHandler",null);o(this,"notifyScheduled",false);o(this,"handleIntersection",e=>{var c;let t=e.filter(n=>n.isIntersecting);if(t.length===0)return;let i=t.reduce((n,a)=>n.intersectionRatio>a.intersectionRatio?n:a),s=[...this.sections.entries()].find(([,n])=>n===i.target),r=(c=s==null?void 0:s[0])!=null?c:i.target.id;!r||r===this.activeId||this.disabledSections.has(r)||(this.previousId=this.activeId,this.activeId=r,this.scheduleNotify(),this.options.hash&&history.replaceState(null,"",`#${r}`));});this.options=u({offset:0,behavior:"smooth",hash:false,root:null,keyboard:false},e),this.initObserver(),this.initScrollListener(),this.options.hash&&this.initHashSync(),this.options.keyboard&&this.initKeyboard();}get scrollRoot(){var e;return (e=this.options.root)!=null?e:window}get currentScrollTop(){return this.options.root?this.options.root.scrollTop:window.scrollY}initObserver(){var e;typeof window!="undefined"&&(this.observer=new IntersectionObserver(this.handleIntersection,{root:(e=this.options.root)!=null?e:null,rootMargin:"-20% 0px -60% 0px",threshold:[0,.1,.5,1]}),typeof ResizeObserver!="undefined"&&(this.resizeObserver=new ResizeObserver(()=>{this.sections.forEach(t=>{var i,s;(i=this.observer)==null||i.unobserve(t),(s=this.observer)==null||s.observe(t);});})));}initScrollListener(){typeof window!="undefined"&&(this.scrollHandler=()=>{let e=this.currentScrollTop;e!==this.lastScrollY&&(this.scrollDirection=e>this.lastScrollY?"down":"up",this.lastScrollY=e),this.updateProgress();},this.scrollRoot.addEventListener("scroll",this.scrollHandler,{passive:true}));}initHashSync(){typeof window!="undefined"&&(this.popstateHandler=()=>{let e=window.location.hash.slice(1);e&&this.sections.has(e)&&this.scrollTo(e);},window.addEventListener("popstate",this.popstateHandler));}initKeyboard(){typeof window!="undefined"&&(this.keyboardHandler=e=>{e.altKey&&(e.key==="ArrowDown"?(e.preventDefault(),this.scrollToNext()):e.key==="ArrowUp"&&(e.preventDefault(),this.scrollToPrev()));},document.addEventListener("keydown",this.keyboardHandler));}scheduleNotify(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.notifyListeners();}));}updateProgress(){if(this.progressListeners.size===0)return;let e=this.currentScrollTop,t=this.options.root?this.options.root.clientHeight:window.innerHeight;this.progressListeners.forEach((i,s)=>{if(i.size===0)return;let r=this.sections.get(s);if(!r)return;let c=r.getBoundingClientRect(),n=this.options.root?c.top-this.options.root.getBoundingClientRect().top+this.options.root.scrollTop:c.top+e,a=r.offsetHeight||c.height;if(a===0)return;let h=(e-n+t*.2)/a,f=Math.max(0,Math.min(1,h));i.forEach(g=>g(f));});}registerSection(e,t){var i,s;typeof window!="undefined"&&t&&(this.sections.set(e,t),t.id||(t.id=e),(i=this.observer)==null||i.observe(t),(s=this.resizeObserver)==null||s.observe(t),this.options.hash&&window.location.hash===`#${e}`&&setTimeout(()=>this.scrollTo(e),0));}unregisterSection(e){var i,s;let t=this.sections.get(e);t&&((i=this.observer)==null||i.unobserve(t),(s=this.resizeObserver)==null||s.unobserve(t)),this.sections.delete(e),this.disabledSections.delete(e),this.progressListeners.delete(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}disableSection(e){this.disabledSections.add(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}enableSection(e){this.disabledSections.delete(e);}getSections(){return [...this.sections.entries()].filter(([e])=>!this.disabledSections.has(e)).sort(([,e],[,t])=>{let i=e.getBoundingClientRect().top,s=t.getBoundingClientRect().top;return i-s}).map(([e])=>e)}getActiveId(){return this.activeId}scrollTo(e){if(typeof window=="undefined")return Promise.resolve();let t=this.sections.get(e);if(!t)return console.warn(`[ScrollManager] Section with id "${e}" not found. Available sections: ${Array.from(this.sections.keys()).join(", ")}`),Promise.resolve();let{offset:i,behavior:s}=this.options;if(this.options.root){let r=t.offsetTop;this.options.root.scrollTo({top:r+i,behavior:s});}else {let r=t.getBoundingClientRect().top+window.scrollY;window.scrollTo({top:r+i,behavior:s});}return new Promise(r=>{if(s==="auto"||s==="instant"){r();return}let c=this.currentScrollTop,n,a=()=>{let h=this.currentScrollTop;if(h===c){cancelAnimationFrame(n),r();return}c=h,n=requestAnimationFrame(a);};n=requestAnimationFrame(a),setTimeout(()=>{cancelAnimationFrame(n),r();},1e3);})}scrollToNext(){let e=this.getSections(),t=this.activeId?e.indexOf(this.activeId):-1,i=e[t+1];return i?this.scrollTo(i):Promise.resolve()}scrollToPrev(){let e=this.getSections(),t=this.activeId?e.indexOf(this.activeId):e.length,i=e[t-1];return i?this.scrollTo(i):Promise.resolve()}scrollToFirst(){let e=this.getSections();return e.length>0?this.scrollTo(e[0]):Promise.resolve()}scrollToLast(){let e=this.getSections();return e.length>0?this.scrollTo(e[e.length-1]):Promise.resolve()}onActiveChange(e){return this.listeners.add(e),e(this.activeId,{previous:this.previousId,direction:this.scrollDirection}),()=>this.listeners.delete(e)}onProgressChange(e,t){return this.progressListeners.has(e)||this.progressListeners.set(e,new Set),this.progressListeners.get(e).add(t),()=>{let i=this.progressListeners.get(e);i&&(i.delete(t),i.size===0&&this.progressListeners.delete(e));}}notifyListeners(){let e={previous:this.previousId,direction:this.scrollDirection};this.listeners.forEach(t=>t(this.activeId,e));}destroy(){var e,t;(e=this.observer)==null||e.disconnect(),(t=this.resizeObserver)==null||t.disconnect(),this.scrollHandler&&(this.scrollRoot.removeEventListener("scroll",this.scrollHandler),this.scrollHandler=null),this.keyboardHandler&&(document.removeEventListener("keydown",this.keyboardHandler),this.keyboardHandler=null),this.popstateHandler&&(window.removeEventListener("popstate",this.popstateHandler),this.popstateHandler=null),this.sections.clear(),this.listeners.clear(),this.progressListeners.clear(),this.disabledSections.clear();}};export{v as ScrollManager};
1
+ var b=Object.defineProperty;var u=Object.getOwnPropertySymbols;var w=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable;var p=(l,e,t)=>e in l?b(l,e,{enumerable:true,configurable:true,writable:true,value:t}):l[e]=t,v=(l,e)=>{for(var t in e||(e={}))w.call(e,t)&&p(l,t,e[t]);if(u)for(var t of u(e))S.call(e,t)&&p(l,t,e[t]);return l};var r=(l,e,t)=>p(l,typeof e!="symbol"?e+"":e,t);var f=class{constructor(e={}){r(this,"sections",new Map);r(this,"disabledSections",new Set);r(this,"observer",null);r(this,"resizeObserver",null);r(this,"activeId",null);r(this,"previousId",null);r(this,"lastScrollY",0);r(this,"scrollDirection",null);r(this,"listeners",new Set);r(this,"progressListeners",new Map);r(this,"options");r(this,"keyboardHandler",null);r(this,"scrollHandler",null);r(this,"popstateHandler",null);r(this,"notifyScheduled",false);r(this,"handleIntersection",e=>{let t=e.filter(o=>o.isIntersecting);if(t.length===0){this.activeId!==null&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());return}let s=t.reduce((o,n)=>o.intersectionRatio>n.intersectionRatio?o:n),i;for(let[o,n]of this.sections)if(n===s.target){i=o;break}i=i!=null?i:s.target.id,!(!i||i===this.activeId||this.disabledSections.has(i))&&(this.previousId=this.activeId,this.activeId=i,this.scheduleNotify(),this.options.hash&&history.replaceState(null,"",`#${i}`));});this.options=v({offset:0,behavior:"smooth",hash:false,root:null,keyboard:false},e),this.initObserver(),this.initScrollListener(),this.options.hash&&this.initHashSync(),this.options.keyboard&&this.initKeyboard();}get scrollRoot(){var e;return (e=this.options.root)!=null?e:window}get currentScrollTop(){return this.options.root?this.options.root.scrollTop:window.scrollY}initObserver(){var e;typeof window!="undefined"&&(this.observer=new IntersectionObserver(this.handleIntersection,{root:(e=this.options.root)!=null?e:null,rootMargin:"-20% 0px -60% 0px",threshold:[0,.1,.5,1]}),typeof ResizeObserver!="undefined"&&(this.resizeObserver=new ResizeObserver(()=>{this.sections.forEach(t=>{var s,i;(s=this.observer)==null||s.unobserve(t),(i=this.observer)==null||i.observe(t);});})));}initScrollListener(){typeof window!="undefined"&&(this.scrollHandler=()=>{let e=this.currentScrollTop;e!==this.lastScrollY&&(this.scrollDirection=e>this.lastScrollY?"down":"up",this.lastScrollY=e),this.updateProgress();},this.scrollRoot.addEventListener("scroll",this.scrollHandler,{passive:true}));}initHashSync(){typeof window!="undefined"&&(this.popstateHandler=()=>{let e=window.location.hash.slice(1);e&&this.sections.has(e)&&this.scrollTo(e);},window.addEventListener("popstate",this.popstateHandler));}initKeyboard(){typeof window!="undefined"&&(this.keyboardHandler=e=>{e.altKey&&(e.key==="ArrowDown"?(e.preventDefault(),this.scrollToNext()):e.key==="ArrowUp"&&(e.preventDefault(),this.scrollToPrev()));},document.addEventListener("keydown",this.keyboardHandler));}scheduleNotify(){this.notifyScheduled||(this.notifyScheduled=true,queueMicrotask(()=>{this.notifyScheduled=false,this.notifyListeners();}));}updateProgress(){if(this.progressListeners.size===0)return;let e=this.currentScrollTop,t=this.options.root?this.options.root.clientHeight:window.innerHeight;this.progressListeners.forEach((s,i)=>{if(s.size===0)return;let o=this.sections.get(i);if(!o)return;let n=o.getBoundingClientRect(),a=this.options.root?n.top-this.options.root.getBoundingClientRect().top+this.options.root.scrollTop:n.top+e,c=o.offsetHeight||n.height;if(c===0)return;let h=(e-a+t*.2)/c,d=Math.max(0,Math.min(1,h));s.forEach(g=>g(d));});}registerSection(e,t){var s,i;typeof window!="undefined"&&t&&(this.sections.set(e,t),t.id||(t.id=e),(s=this.observer)==null||s.observe(t),(i=this.resizeObserver)==null||i.observe(t),this.options.hash&&window.location.hash===`#${e}`&&setTimeout(()=>this.scrollTo(e),0));}unregisterSection(e){var s,i;let t=this.sections.get(e);t&&((s=this.observer)==null||s.unobserve(t),(i=this.resizeObserver)==null||i.unobserve(t)),this.sections.delete(e),this.disabledSections.delete(e),this.progressListeners.delete(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}disableSection(e){this.disabledSections.add(e),this.activeId===e&&(this.previousId=this.activeId,this.activeId=null,this.scheduleNotify());}enableSection(e){this.disabledSections.delete(e);}getSections(){return [...this.sections.entries()].filter(([e])=>!this.disabledSections.has(e)).sort(([,e],[,t])=>{let s=e.getBoundingClientRect().top,i=t.getBoundingClientRect().top;return s-i}).map(([e])=>e)}getActiveId(){return this.activeId}scrollTo(e){var a;if(typeof window=="undefined")return Promise.resolve();let t=this.sections.get(e);if(!t)return console.warn(`[ScrollManager] Section with id "${e}" not found. Available sections: ${Array.from(this.sections.keys()).join(", ")}`),Promise.resolve();let s=t.getBoundingClientRect(),i=((a=this.options.root)==null?void 0:a.getBoundingClientRect())||{top:0},o=s.top+this.currentScrollTop-i.top+this.options.offset,n=this.options.root||window;return new Promise(c=>{let h=()=>{(Math.abs(this.currentScrollTop-o)<1||n===window&&window.innerHeight+window.scrollY>=document.body.offsetHeight||this.options.root&&this.options.root.clientHeight+this.options.root.scrollTop>=this.options.root.scrollHeight)&&(n.removeEventListener("scroll",h),clearTimeout(d),c());},d=setTimeout(()=>{n.removeEventListener("scroll",h),c();},1e3);this.options.behavior==="smooth"?n.addEventListener("scroll",h,{passive:true}):(clearTimeout(d),c()),this.options.root?this.options.root.scrollTo({top:o,behavior:this.options.behavior}):window.scrollTo({top:o,behavior:this.options.behavior});})}scrollToNext(){let e=this.getSections(),s=(this.activeId?e.indexOf(this.activeId):-1)+1;return s<e.length?this.scrollTo(e[s]):Promise.resolve()}scrollToPrev(){let e=this.getSections(),s=(this.activeId?e.indexOf(this.activeId):-1)-1;return s>=0?this.scrollTo(e[s]):Promise.resolve()}scrollToFirst(){let e=this.getSections();return e.length>0?this.scrollTo(e[0]):Promise.resolve()}scrollToLast(){let e=this.getSections();return e.length>0?this.scrollTo(e[e.length-1]):Promise.resolve()}onActiveChange(e){return this.listeners.add(e),e(this.activeId,{previous:this.previousId,direction:this.scrollDirection}),()=>{this.listeners.delete(e);}}notifyListeners(){let e={previous:this.previousId,direction:this.scrollDirection};this.listeners.forEach(t=>t(this.activeId,e));}onProgressChange(e,t){var s;return this.progressListeners.has(e)||this.progressListeners.set(e,new Set),(s=this.progressListeners.get(e))==null||s.add(t),this.updateProgress(),()=>{var i;(i=this.progressListeners.get(e))==null||i.delete(t);}}destroy(){var e,t;(e=this.observer)==null||e.disconnect(),(t=this.resizeObserver)==null||t.disconnect(),this.sections.forEach(s=>{var i,o;(i=this.observer)==null||i.unobserve(s),(o=this.resizeObserver)==null||o.unobserve(s);}),this.sections.clear(),this.disabledSections.clear(),this.listeners.clear(),this.progressListeners.clear(),this.scrollHandler&&this.scrollRoot.removeEventListener("scroll",this.scrollHandler),this.popstateHandler&&window.removeEventListener("popstate",this.popstateHandler),this.keyboardHandler&&document.removeEventListener("keydown",this.keyboardHandler);}};export{f as ScrollManager};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jump-section/core",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "Core scroll management library for jump-section",
5
5
  "keywords": [
6
6
  "scroll",