react-atom-trigger 2.0.2 → 2.0.6

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/MIGRATION.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  The biggest change is simple: `AtomTrigger` does its own observation now. In `v1.x` you had to pass scroll state and dimensions in from the outside. In `v2.x` you pass callbacks and, when needed, a root element.
6
6
 
7
+ The supported React range for `v2` remains the published peer range: React `16.8` through `19.x`.
8
+
7
9
  ## Before you start
8
10
 
9
11
  This is not just a prop rename release.
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # react-atom-trigger
2
2
 
3
3
  [![codecov](https://codecov.io/gh/innrvoice/react-atom-trigger/branch/master/graph/badge.svg)](https://codecov.io/gh/innrvoice/react-atom-trigger)
4
+ [![bundle size](https://codecov.io/github/innrvoice/react-atom-trigger/branch/master/graph/bundle/react-atom-trigger-esm/badge.svg)](https://app.codecov.io/github/innrvoice/react-atom-trigger/bundles/master/react-atom-trigger-esm)
4
5
 
5
6
  `react-atom-trigger` helps with the usual "run some code when this thing enters or leaves view" problem.
6
7
  It is a lightweight React alternative to `react-waypoint`, written in TypeScript.
@@ -35,12 +36,18 @@ npm install react-atom-trigger
35
36
  yarn add react-atom-trigger
36
37
  ```
37
38
 
39
+ The published package does not enforce a specific Node.js engine.
40
+ Runtime compatibility is determined by your React version, browser target and bundler setup.
41
+
42
+ The public React compatibility contract for `v2` is the published peer range: React `16.8` through
43
+ `19.x`.
44
+
38
45
  ## How it works
39
46
 
40
47
  `react-atom-trigger` uses a mixed approach.
41
48
 
42
49
  - Geometry is the real source of truth for `enter` and `leave`.
43
- - `IntersectionObserver` is only there to wake things up when the browser notices a layout shift.
50
+ - `IntersectionObserver` is only there to wake things up when the browser notices a nearby layout shift.
44
51
  - `rootMargin` logic is handled by the library itself, so it stays consistent and does not depend on native observer quirks.
45
52
 
46
53
  In practice this means `AtomTrigger` reacts to:
@@ -49,7 +56,7 @@ In practice this means `AtomTrigger` reacts to:
49
56
  - window resize
50
57
  - root resize
51
58
  - sentinel resize
52
- - layout shifts that move the observed element even if no scroll event happened
59
+ - nearby layout shifts that move the observed element even if no scroll event happened
53
60
 
54
61
  This is the main reason `v2` can support custom margin-aware behavior and still react to browser-driven layout changes.
55
62
 
@@ -128,6 +135,10 @@ element:
128
135
 
129
136
  If the ref never reaches a DOM node, child mode cannot observe anything.
130
137
 
138
+ If a custom child renders a placeholder first and only exposes its DOM node a moment later,
139
+ `AtomTrigger` waits briefly before showing the missing-ref warning so normal async mount flows do
140
+ not get flagged too early.
141
+
131
142
  ## API
132
143
 
133
144
  ```ts
@@ -159,6 +170,7 @@ interface AtomTriggerProps {
159
170
  - `threshold`: a number from `0` to `1`. It affects `enter`, not `leave`.
160
171
  - `root`: use a specific DOM element as the visible area.
161
172
  - `rootRef`: same idea as `root`, but better when the container is created in JSX. If both are passed, `rootRef` wins.
173
+ - `root` / `rootRef`: if you pass one explicitly but it is still `null`, observation pauses until that real root exists. It does not silently fall back to the viewport.
162
174
  - `rootMargin`: expand or shrink the effective root. String values use `IntersectionObserver`-style syntax. A four-number array is treated as `[top, right, bottom, left]` in pixels.
163
175
  - `className`: applies only to the internal sentinel.
164
176
 
@@ -217,14 +229,20 @@ useViewportSize(options?: {
217
229
  }): { width: number; height: number }
218
230
  ```
219
231
 
220
- Both hooks are SSR-safe. Default throttling is `16ms`.
232
+ Both hooks are SSR-safe and hydration-safe across the supported React range. During hydration, the first client render matches the server snapshot and then refreshes from the live source, including the compat path used when React does not expose `useSyncExternalStore`. Default throttling is `16ms`.
233
+
234
+ If you pass `enabled={false}`, the hook pauses its listeners but keeps the latest value it already knows.
235
+ It does not fake a reset back to zero.
236
+ When you enable it again, it reads from the source immediately and then continues updating as usual.
221
237
 
222
238
  ## Notes
223
239
 
224
240
  - In sentinel mode, `threshold` is usually only interesting if your sentinel has real width or height. The default sentinel is almost point-like.
241
+ - The internal sentinel intentionally uses a non-block display so it behaves like a point-like marker instead of stretching into a full-width placeholder.
225
242
  - Child mode needs exactly one top-level child and any custom component used there needs to pass the received ref through to a DOM element.
226
243
  - In React 19, a plain function component can also work in child mode if it passes the received `ref` prop through to a DOM element.
227
- - `rootMargin` is handled by the library geometry logic. `IntersectionObserver` is only used as a wake-up signal for layout shifts.
244
+ - If you pass `root` or `rootRef` explicitly and it is not ready yet, observation pauses instead of falling back to the viewport.
245
+ - `rootMargin` is handled by the library geometry logic. `IntersectionObserver` is only used as a nearby wake-up signal for layout shifts.
228
246
 
229
247
  ## Migration from v1
230
248
 
@@ -287,11 +305,17 @@ Quick way to tweak it in the browser.
287
305
  pnpm install
288
306
  pnpm lint
289
307
  pnpm test
308
+ pnpm test:coverage
290
309
  pnpm test:storybook
291
310
  pnpm build
292
311
  pnpm format:check
293
312
  ```
294
313
 
314
+ Coverage note:
315
+
316
+ - `pnpm test:coverage` is the official unit coverage signal used in CI and Codecov.
317
+ - `pnpm test:storybook` is a separate browser regression gate and is not merged into the official coverage number.
318
+
295
319
  ## Storybook (Static Build)
296
320
 
297
321
  Build:
package/lib/index.js CHANGED
@@ -1 +1 @@
1
- import e from"react";const t=new Set;function n(){if(typeof process>`u`||!process.env)return null;let e=`production`;return e===`development`||e===`production`?e:null}function r(e){n()===`development`&&(t.has(e)||(t.add(e),typeof console<`u`&&console.warn&&console.warn(e)))}const i=Symbol.for(`react.forward_ref`),a=Symbol.for(`react.memo`);function o(e,t){if(e){if(typeof e==`function`){e(t);return}e.current=t}}function s(e){if(typeof e==`string`||typeof e==`function`)return!0;if(typeof e!=`object`||!e)return!1;let t=e;return t.$$typeof===i?!0:t.$$typeof===a&&t.type?s(t.type):!1}function c(t,n,r,i){return t?n===1?r?i===e.Fragment?`[react-atom-trigger] Child mode does not support React.Fragment. Wrap the content in a single DOM element. Observation is disabled for this render.`:(!i||s(i),null):`[react-atom-trigger] Child mode expects a React element child. Observation is disabled for this render.`:`[react-atom-trigger] Child mode expects exactly one top-level React element. Observation is disabled for this render.`:null}function l(e){return Array.isArray(e)&&e.length===4&&e.every(e=>typeof e==`number`&&Number.isFinite(e))}function u(e){return typeof e==`string`?e:l(e)?e.map(e=>`${Object.is(e,-0)?0:e}px`).join(` `):(e==null||r(`[react-atom-trigger] Invalid rootMargin array ${JSON.stringify(e)}. Use exactly four finite numbers: [top, right, bottom, left]. Falling back to 0px.`),`0px`)}function d(e,t){let n=e.trim();if(!n||/^[+-]?0(?:\.0+)?$/.test(n))return 0;let i=n.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(px|%)$/);if(!i)return r(`[react-atom-trigger] Invalid rootMargin token "${n}". Use px, % or 0. Falling back to 0px.`),0;let[,a,o]=i,s=Number.parseFloat(a);return o===`%`?s/100*t:s}function f(e,t,n){let i=e.trim().split(/\s+/).filter(Boolean);if(i.length>4)return r(`[react-atom-trigger] Invalid rootMargin "${e}". Use 1 to 4 values in IntersectionObserver order. Falling back to 0px.`),{top:0,right:0,bottom:0,left:0};let[a=`0px`,o=a,s=a,c=o]=i;return{top:d(a,n),right:d(o,t),bottom:d(s,n),left:d(c,t)}}function p(e,t){let n=f(t,e.width,e.height);return new DOMRect(e.left-n.left,e.top-n.top,e.width+n.left+n.right,e.height+n.top+n.bottom)}function m(e){let t=e.width>0?e.width:1,n=e.height>0?e.height:1;return t===e.width&&n===e.height?e:new DOMRect(e.left,e.top,t,n)}function h(e,t){let n=Math.max(e.left,t.left),r=Math.max(e.top,t.top),i=Math.min(e.right,t.right),a=Math.min(e.bottom,t.bottom);return i<=n||a<=r?new DOMRect(0,0,0,0):new DOMRect(n,r,i-n,a-r)}function g(e,t){let n=e.width*e.height;return n<=0?0:t.width*t.height/n}function _(e){return Math.min(1,Math.max(0,e))}function v(e){return Array.isArray(e)?(r("[react-atom-trigger] `threshold` expects a single number in v2. Using the first finite numeric entry."),_(e.find(e=>typeof e==`number`&&Number.isFinite(e))??0)):e==null?0:typeof e!=`number`||!Number.isFinite(e)?(r("[react-atom-trigger] `threshold` must be a finite number between 0 and 1. Falling back to 0."),0):((e<0||e>1)&&r("[react-atom-trigger] `threshold` should be between 0 and 1. Values are clamped."),_(e))}function y(e,t){if(!e)return`unknown`;let n=t.left-e.left,r=t.top-e.top;return n===0&&r===0?`stationary`:Math.abs(r)>=Math.abs(n)?r<0?`up`:`down`:n<0?`left`:`right`}function b(e){if(e.isIntersecting)return`inside`;let t=e.boundingClientRect,n=e.rootBounds?.top??0,r=e.rootBounds?.bottom??window.innerHeight,i=e.rootBounds?.left??0,a=e.rootBounds?.right??window.innerWidth;return t.bottom<=n?`above`:t.top>=r?`below`:t.right<=i?`left`:t.left>=a?`right`:`outside`}const x=new WeakMap;function S(){return new DOMRect(0,0,window.innerWidth,window.innerHeight)}function C(e){return e===window||typeof Window<`u`&&e instanceof Window}function w(e,t,n,r){return!(n&&t.entered+t.left>0||r&&(e===`enter`&&t.entered>0||e===`leave`&&t.left>0))}function T(e){return e.once?e.counts.entered+e.counts.left>0:e.oncePerDirection?e.counts.entered>0&&e.counts.left>0:!1}function E(e){e.previousTriggerActive=void 0,e.previousRect=null}function D(e,t,n,r){let i=m(e.node.getBoundingClientRect()),a=p(t,e.rootMargin),o=h(i,a),s=g(i,o),c=s>0,l=e.previousTriggerActive,u=l===!0||e.threshold===0?c:s>=e.threshold,d=e.previousRect&&(n===`root-change`||r)?`stationary`:y(e.previousRect,i);e.previousRect=i,e.previousTriggerActive=u;let f=Date.now(),_={target:e.node,rootBounds:a,boundingClientRect:i,intersectionRect:o,isIntersecting:c,intersectionRatio:s,source:`geometry`},v=l===void 0;if(v&&(!e.fireOnInitialVisible||!u)||l===u)return;let x=u?`enter`:`leave`;if(!w(x,e.counts,e.once,e.oncePerDirection))return;let S=x===`enter`?{...e.counts,entered:e.counts.entered+1}:{...e.counts,left:e.counts.left+1};e.counts=S;let C={type:x,isInitial:v,entry:_,counts:S,movementDirection:d,position:b(_),timestamp:f};e.onEvent?.(C),x===`enter`?e.onEnter?.(C):e.onLeave?.(C),T(e)&&e.dispose?.()}function O(e){let t={registrations:new Set,rafId:0,pendingSampleCause:null,previousBaseRootBounds:null,resizeObserver:null,intersectionObserver:null,queueSample:()=>{},cleanup:()=>{}},n=()=>{if(t.rafId=0,t.registrations.size===0){t.pendingSampleCause=null;return}let n=t.pendingSampleCause??`geometry-change`;t.pendingSampleCause=null;let r=C(e)?S():e.getBoundingClientRect(),i=t.previousBaseRootBounds!==null&&(t.previousBaseRootBounds.top!==r.top||t.previousBaseRootBounds.left!==r.left||t.previousBaseRootBounds.width!==r.width||t.previousBaseRootBounds.height!==r.height);for(let e of t.registrations)D(e,r,n,i);t.previousBaseRootBounds=new DOMRect(r.left,r.top,r.width,r.height)},r=(e=`geometry-change`)=>{if((t.pendingSampleCause===null||t.pendingSampleCause===`geometry-change`&&e!==`geometry-change`||t.pendingSampleCause===`root-change`&&e===`scroll`)&&(t.pendingSampleCause=e),t.rafId!==0)return;t.rafId=-1;let r=window.requestAnimationFrame(()=>{t.rafId=0,n()});t.rafId===-1&&(t.rafId=r)},i=()=>{r(`scroll`)},a=()=>{r(`root-change`)};return e.addEventListener(`scroll`,i,{passive:!0}),window.addEventListener(`resize`,a),typeof ResizeObserver<`u`&&(t.resizeObserver=new ResizeObserver(a),C(e)||t.resizeObserver.observe(e)),typeof IntersectionObserver<`u`&&(t.intersectionObserver=new IntersectionObserver(()=>{r(`geometry-change`)},{root:C(e)?null:e,rootMargin:`200% 200% 200% 200%`,threshold:0})),t.queueSample=r,t.cleanup=()=>{t.rafId!==0&&(cancelAnimationFrame(t.rafId),t.rafId=0),e.removeEventListener(`scroll`,i),window.removeEventListener(`resize`,a),t.resizeObserver?.disconnect(),t.intersectionObserver?.disconnect(),t.pendingSampleCause=null,t.previousBaseRootBounds=null},t}function k(e){let t=x.get(e);if(t)return t;let n=O(e);return x.set(e,n),n}function A(e,t){let n=k(e),r=!1;n.registrations.add(t),n.resizeObserver?.observe(t.node),n.intersectionObserver?.observe(t.node),n.queueSample();let i=()=>{r||(r=!0,n.registrations.delete(t),n.resizeObserver?.unobserve(t.node),n.intersectionObserver?.unobserve(t.node),t.dispose=void 0,n.registrations.size===0&&(n.cleanup(),x.delete(e)))};return t.dispose=i,i}function j(e,t){return t?t.current:e||(typeof window>`u`?null:window)}const M={display:`table`},N=({onEnter:t,onLeave:n,onEvent:i,children:a,once:s=!1,oncePerDirection:l=!1,fireOnInitialVisible:d=!1,disabled:f=!1,threshold:p=0,root:m=null,rootRef:h,rootMargin:g=`0px`,className:_})=>{let y=e.useRef(null),[b,x]=e.useState(null),S=e.useRef(null),C=e.useRef(null),w=e.useRef(null),T=e.useRef(null),D=u(g),O=v(p),k=a!=null,N=e.Children.count(a),P=N===1&&e.isValidElement(a)?a:null,F=c(k,N,P,P?P.type:null),I=F||!P?null:P,L=I?.props.ref,R=e.useCallback(e=>{if(o(L,e),e===null){S.current=null,x(e=>e===null?e:null);return}if(e instanceof Element){S.current=e,x(t=>t===e?t:e);return}S.current=null,x(e=>e===null?e:null),r(`[react-atom-trigger] Child mode requires the child ref to resolve to a DOM element. Observation is disabled for this render.`)},[L]);return e.useEffect(()=>{r(`[react-atom-trigger] v2 uses a new internal observation engine. If you upgraded from v1.x, verify trigger behavior for timing, threshold and rootMargin.`)},[]),e.useEffect(()=>{k&&_&&r("[react-atom-trigger] `className` only applies to the internal sentinel. In child mode, style the child element directly.")},[_,k]),e.useEffect(()=>{F&&r(F)},[F]),e.useEffect(()=>{if(typeof window>`u`||!k||!I||F||b)return;let e=window.setTimeout(()=>{S.current||r(`[react-atom-trigger] Child mode expects a DOM element or a component that forwards its ref to a DOM element. Observation is disabled for this render.`)},0);return()=>{window.clearTimeout(e)}},[b,I,k,F]),e.useEffect(()=>{let e=C.current;e&&(e.onEnter=t,e.onLeave=n,e.onEvent=i)},[t,n,i]),e.useEffect(()=>{if(typeof window>`u`)return;let e=k?b:y.current,r=j(m,h);if(!e){C.current&&E(C.current),w.current?.(),w.current=null,T.current=null;return}C.current?(C.current.node=e,C.current.rootMargin=D,C.current.threshold=O,C.current.once=s,C.current.oncePerDirection=l,C.current.fireOnInitialVisible=d):C.current={node:e,rootMargin:D,threshold:O,once:s,oncePerDirection:l,fireOnInitialVisible:d,onEnter:t,onLeave:n,onEvent:i,previousTriggerActive:void 0,previousRect:null,counts:{entered:0,left:0}};let a=C.current;if(f||!r){E(a),w.current?.(),w.current=null,T.current=null;return}let o=T.current,c={node:e,target:r,rootMargin:D,threshold:O,once:s,oncePerDirection:l,fireOnInitialVisible:d};(!o||o.node!==c.node||o.target!==c.target||o.rootMargin!==c.rootMargin||o.threshold!==c.threshold||o.once!==c.once||o.oncePerDirection!==c.oncePerDirection||o.fireOnInitialVisible!==c.fireOnInitialVisible)&&(E(a),w.current?.(),w.current=A(r,a),T.current=c)},[f,D,O,s,l,d,b,m,h?.current,k]),e.useEffect(()=>()=>{w.current?.(),w.current=null,T.current=null},[]),k?I?e.cloneElement(I,{ref:R}):e.createElement(e.Fragment,null,a):e.createElement(`div`,{ref:y,style:M,className:_})},P={x:0,y:0},F=typeof window>`u`?e.useEffect:e.useLayoutEffect;function I(e,t){let n=null,r=null,i=()=>{n&&(clearTimeout(n),n=null),r=Date.now(),e()};return{schedule:()=>{if(t<=0){i();return}let e=Date.now();if(r===null||e-r>=t){i();return}n||(n=setTimeout(()=>{i()},t-(e-r)))},cancel:()=>{n&&(clearTimeout(n),n=null)}}}function L(){return typeof window>`u`?{width:0,height:0}:{width:window.innerWidth,height:window.innerHeight}}function R(e){return!!(e&&typeof e==`object`&&!(typeof Window<`u`&&e instanceof Window)&&`current`in e)}function z(e){return R(e)?e.current:e||(typeof window>`u`?null:window)}function B(e){return e===window||typeof Window<`u`&&e instanceof Window}function V(e){if(B(e))return{x:e.scrollX,y:e.scrollY};let t=e;return{x:t.scrollLeft,y:t.scrollTop}}function H(t){let[n,r]=e.useState(L);return e.useEffect(()=>{if(typeof window>`u`||t?.enabled===!1)return;let e=t?.throttleMs??16;r(L());let n=I(()=>{r(L())},e);return window.addEventListener(`resize`,n.schedule,{passive:t?.passive}),()=>{n.cancel(),window.removeEventListener(`resize`,n.schedule)}},[t?.enabled,t?.passive,t?.throttleMs]),n}function U(t){let n=t?.target,r=R(n),[i,a]=e.useState(()=>{let e=z(n);return e?V(e):P}),[o,s]=e.useState(()=>r?z(n):null);F(()=>{if(!r)return;let e=z(n);s(t=>t===e?t:e)});let c=r?o:z(n);return e.useEffect(()=>{if(t?.enabled===!1){a(P);return}if(!c){a(P);return}let e=t?.throttleMs??16;a(V(c));let n=I(()=>{a(V(c))},e);return c.addEventListener(`scroll`,n.schedule,{passive:t?.passive}),()=>{n.cancel(),c.removeEventListener(`scroll`,n.schedule)}},[t?.enabled,t?.passive,t?.throttleMs,c]),i}export{N as AtomTrigger,U as useScrollPosition,H as useViewportSize};
1
+ import e from"react";const t=new Set;function n(){if(typeof process>`u`||!process.env)return null;let e=`production`;return e===`development`||e===`production`?e:null}function r(e){return(Object.prototype.hasOwnProperty.call(e??{},`nodeEnv`)?e?.nodeEnv??null:n())===`development`}function i(e){r()&&(t.has(e)||(t.add(e),typeof console<`u`&&console.warn&&console.warn(e)))}function a(e){return!!(e&&typeof e==`object`&&`nodeType`in e&&e.nodeType===1&&`getBoundingClientRect`in e&&typeof e.getBoundingClientRect==`function`&&`addEventListener`in e&&typeof e.addEventListener==`function`&&`removeEventListener`in e&&typeof e.removeEventListener==`function`)}function o(e){return!!(e&&typeof e==`object`&&`window`in e&&e.window===e)}function s(e,t){if(e){if(typeof e==`function`){e(t);return}e.current=t}}function c(e){if(!e||typeof e!=`object`&&typeof e!=`function`)return;let t=Object.getOwnPropertyDescriptor(e,`ref`);if(!(!t||!(`value`in t)))return t.value}function l(e){if(!e)return;let t=c(e.props);return t===void 0?c(e):t}function u(t,n,r){return t?n===1?r?r.type===e.Fragment?`[react-atom-trigger] Child mode does not support React.Fragment. Wrap the content in a single DOM element. Observation is disabled for this render.`:null:`[react-atom-trigger] Child mode expects a React element child. Observation is disabled for this render.`:`[react-atom-trigger] Child mode expects exactly one top-level React element. Observation is disabled for this render.`:null}function d({originalChildRef:t,hasObservedChild:n,invalidChildWarning:r,shouldWarnAboutMissingDomRef:o}){let[c,l]=e.useState(null),u=e.useRef(null),d=e.useCallback(()=>{u.current=null,l(e=>e===null?e:null)},[]),f=e.useCallback(e=>{if(s(t,e),e===null){d();return}if(a(e)){u.current=e,l(t=>t===e?t:e);return}d(),i(`[react-atom-trigger] Child mode requires the child ref to resolve to a DOM element. Observation is disabled for this render.`)},[d,t]);return e.useEffect(()=>{if(typeof window>`u`||!(n&&!r&&!c&&o))return;let e=window.setTimeout(()=>{u.current||i(`[react-atom-trigger] Child mode expects a DOM element or a component that forwards its ref to a DOM element. Observation is disabled for this render.`)},16);return()=>{window.clearTimeout(e)}},[n,r,c,o]),{childNode:c,attachObservedChildRef:f}}function f(e){return Array.isArray(e)&&e.length===4&&e.every(e=>typeof e==`number`&&Number.isFinite(e))}function p(e){return typeof e==`string`?e:f(e)?e.map(e=>`${Object.is(e,-0)?0:e}px`).join(` `):(e==null||i(`[react-atom-trigger] Invalid rootMargin array ${JSON.stringify(e)}. Use exactly four finite numbers: [top, right, bottom, left]. Falling back to 0px.`),`0px`)}function m(e,t){let n=e.trim();if(!n||/^[+-]?0(?:\.0+)?$/.test(n))return 0;let r=n.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(px|%)$/);if(!r)return i(`[react-atom-trigger] Invalid rootMargin token "${n}". Use px, % or 0. Falling back to 0px.`),0;let[,a,o]=r,s=Number.parseFloat(a);return o===`%`?s/100*t:s}function h(e,t,n){let r=e.trim().split(/\s+/).filter(Boolean);if(r.length>4)return i(`[react-atom-trigger] Invalid rootMargin "${e}". Use 1 to 4 values in IntersectionObserver order. Falling back to 0px.`),{top:0,right:0,bottom:0,left:0};let[a=`0px`,o=a,s=a,c=o]=r;return{top:m(a,n),right:m(o,t),bottom:m(s,n),left:m(c,t)}}function g(e,t){let n=h(t,e.width,e.height);return new DOMRect(e.left-n.left,e.top-n.top,e.width+n.left+n.right,e.height+n.top+n.bottom)}function _(e){let t=e.width>0?e.width:1,n=e.height>0?e.height:1;return t===e.width&&n===e.height?e:new DOMRect(e.left,e.top,t,n)}function v(e,t){let n=Math.max(e.left,t.left),r=Math.max(e.top,t.top),i=Math.min(e.right,t.right),a=Math.min(e.bottom,t.bottom);return i<=n||a<=r?new DOMRect(0,0,0,0):new DOMRect(n,r,i-n,a-r)}function y(e,t){let n=e.width*e.height;return n<=0?0:t.width*t.height/n}function b(e){return Math.min(1,Math.max(0,e))}function x(e){return Array.isArray(e)?(i("[react-atom-trigger] `threshold` expects a single number in v2. Using the first finite numeric entry."),b(e.find(e=>typeof e==`number`&&Number.isFinite(e))??0)):e==null?0:typeof e!=`number`||!Number.isFinite(e)?(i("[react-atom-trigger] `threshold` must be a finite number between 0 and 1. Falling back to 0."),0):((e<0||e>1)&&i("[react-atom-trigger] `threshold` should be between 0 and 1. Values are clamped."),b(e))}function S(e,t){if(!e)return`unknown`;let n=t.left-e.left,r=t.top-e.top;return n===0&&r===0?`stationary`:Math.abs(r)>=Math.abs(n)?r<0?`up`:`down`:n<0?`left`:`right`}function C(e){if(e.isIntersecting)return`inside`;let t=e.boundingClientRect,n=e.rootBounds?.top??0,r=e.rootBounds?.bottom??window.innerHeight,i=e.rootBounds?.left??0,a=e.rootBounds?.right??window.innerWidth;return t.bottom<=n?`above`:t.top>=r?`below`:t.right<=i?`left`:t.left>=a?`right`:`outside`}function w(e,t,n,r){return!(n&&t.entered+t.left>0||r&&(e===`enter`&&t.entered>0||e===`leave`&&t.left>0))}function T(e){return e.once?e.counts.entered+e.counts.left>0:e.oncePerDirection?e.counts.entered>0&&e.counts.left>0:!1}function E(e){e.previousTriggerActive=void 0,e.previousRect=null}function D(e,t,n,r){let i=_(e.node.getBoundingClientRect()),a=g(t,e.rootMargin),o=v(i,a),s=y(i,o),c=s>0,l=e.previousTriggerActive,u=l===!0||e.threshold===0?c:s>=e.threshold,d=e.previousRect&&(n===`root-change`||r)?`stationary`:S(e.previousRect,i);e.previousRect=i,e.previousTriggerActive=u;let f=Date.now(),p={target:e.node,rootBounds:a,boundingClientRect:i,intersectionRect:o,isIntersecting:c,intersectionRatio:s,source:`geometry`},m=l===void 0;if(m&&(!e.fireOnInitialVisible||!u)||l===u)return;let h=u?`enter`:`leave`;if(!w(h,e.counts,e.once,e.oncePerDirection))return;let b=h===`enter`?{...e.counts,entered:e.counts.entered+1}:{...e.counts,left:e.counts.left+1};e.counts=b;let x={type:h,isInitial:m,entry:p,counts:b,movementDirection:d,position:C(p),timestamp:f};e.onEvent?.(x),h===`enter`?e.onEnter?.(x):e.onLeave?.(x),T(e)&&e.dispose?.()}const O=new WeakMap;function k(){return new DOMRect(0,0,window.innerWidth,window.innerHeight)}function A(e){return e===window||o(e)}function j(e){let t={registrations:new Set,rafId:0,pendingSampleCause:null,previousBaseRootBounds:null,resizeObserver:null,intersectionObserver:null,queueSample:()=>{},cleanup:()=>{}},n=()=>{if(t.rafId=0,t.registrations.size===0){t.pendingSampleCause=null;return}let n=t.pendingSampleCause??`geometry-change`;t.pendingSampleCause=null;let r=A(e)?k():e.getBoundingClientRect(),i=t.previousBaseRootBounds!==null&&(t.previousBaseRootBounds.top!==r.top||t.previousBaseRootBounds.left!==r.left||t.previousBaseRootBounds.width!==r.width||t.previousBaseRootBounds.height!==r.height);for(let e of t.registrations)D(e,r,n,i);t.previousBaseRootBounds=new DOMRect(r.left,r.top,r.width,r.height)},r=(e=`geometry-change`)=>{if((t.pendingSampleCause===null||t.pendingSampleCause===`geometry-change`&&e!==`geometry-change`||t.pendingSampleCause===`root-change`&&e===`scroll`)&&(t.pendingSampleCause=e),t.rafId!==0)return;t.rafId=-1;let r=window.requestAnimationFrame(()=>{t.rafId=0,n()});t.rafId===-1&&(t.rafId=r)},i=()=>{r(`scroll`)},a=()=>{r(`root-change`)};return e.addEventListener(`scroll`,i,{passive:!0}),window.addEventListener(`resize`,a),typeof ResizeObserver<`u`&&(t.resizeObserver=new ResizeObserver(a),A(e)||t.resizeObserver.observe(e)),typeof IntersectionObserver<`u`&&(t.intersectionObserver=new IntersectionObserver(()=>{r(`geometry-change`)},{root:A(e)?null:e,rootMargin:`200% 200% 200% 200%`,threshold:0})),t.queueSample=r,t.cleanup=()=>{t.rafId!==0&&(cancelAnimationFrame(t.rafId),t.rafId=0),e.removeEventListener(`scroll`,i),window.removeEventListener(`resize`,a),t.resizeObserver?.disconnect(),t.intersectionObserver?.disconnect(),t.pendingSampleCause=null,t.previousBaseRootBounds=null},t}function ee(e){let t=O.get(e);if(t)return t;let n=j(e);return O.set(e,n),n}function te(e,t){let n=ee(e),r=!1,i=t.node;n.registrations.add(t),n.resizeObserver?.observe(i),n.intersectionObserver?.observe(i),n.queueSample();let a=()=>{r||(r=!0,n.registrations.delete(t),n.resizeObserver?.unobserve(i),n.intersectionObserver?.unobserve(i),t.dispose=void 0,n.registrations.size===0&&(n.cleanup(),O.delete(e)))};return t.dispose=a,a}function ne(e,t){return{...e,...t,previousTriggerActive:void 0,previousRect:null,counts:{entered:0,left:0}}}function M(e,t){e.node=t.node,e.rootMargin=t.rootMargin,e.threshold=t.threshold,e.once=t.once,e.oncePerDirection=t.oncePerDirection,e.fireOnInitialVisible=t.fireOnInitialVisible}function re(e,t){e.onEnter=t.onEnter,e.onLeave=t.onLeave,e.onEvent=t.onEvent}function N(e){e.dispose?.(),e.dispose=null,e.binding=null}function ie(e){return{node:e.node,rootMargin:e.rootMargin,threshold:e.threshold,once:e.once,oncePerDirection:e.oncePerDirection,fireOnInitialVisible:e.fireOnInitialVisible}}function ae(e,t){return!!(e&&e.node===t.node&&e.target===t.target&&e.rootMargin===t.rootMargin&&e.threshold===t.threshold&&e.once===t.once&&e.oncePerDirection===t.oncePerDirection&&e.fireOnInitialVisible===t.fireOnInitialVisible)}function P(e,t){return{registration:ne(e,t),binding:null,dispose:null}}function F(e,t){re(e.registration,t)}function I(e,t){let n=e.registration;if(!t.node){E(n),N(e);return}let r=ie({node:t.node,rootMargin:t.rootMargin,threshold:t.threshold,once:t.once,oncePerDirection:t.oncePerDirection,fireOnInitialVisible:t.fireOnInitialVisible});if(t.disabled||!t.target){N(e),M(n,r),E(n);return}let i={...r,target:t.target};if(ae(e.binding,i)){M(n,r);return}E(n),N(e),M(n,r),e.dispose=te(t.target,n),e.binding=i}function L(e){N(e)}function R(e){let t=e.kind===`rootRef`?"[react-atom-trigger] `rootRef.current` must resolve to a real DOM element. Observation is paused until it does.":"[react-atom-trigger] `root` must be a real DOM element when provided. Observation is paused until it is.",{target:n}=e;return n==null?null:a(n)?n:(i(t),null)}function z(t){let n=t!==void 0,[r,i]=e.useState(()=>n?t.current:null);return e.useEffect(()=>{if(!n)return;let e=t.current;i(t=>t===e?t:e)}),n?r:void 0}function B(e){switch(e.kind){case`rootRef`:case`root`:return R(e);case`viewport`:return typeof window>`u`?null:window}}const V={display:`table`},oe=({onEnter:t,onLeave:n,onEvent:r,children:a,once:o=!1,oncePerDirection:s=!1,fireOnInitialVisible:c=!1,disabled:f=!1,threshold:m=0,root:h,rootRef:g,rootMargin:_=`0px`,className:v})=>{let y=e.useRef(null),b=e.useRef(null),S=z(g),C=p(_),w=x(m),T=a!=null,E=e.Children.count(a),D=E===1&&e.isValidElement(a)?a:null,O=u(T,E,D),k=O||!D?null:D,{childNode:A,attachObservedChildRef:j}=d({originalChildRef:l(k),hasObservedChild:T,invalidChildWarning:O,shouldWarnAboutMissingDomRef:k!==null});return e.useEffect(()=>{T&&v&&i("[react-atom-trigger] `className` only applies to the internal sentinel. In child mode, style the child element directly.")},[v,T]),e.useEffect(()=>{O&&i(O)},[O]),e.useEffect(()=>{o&&s&&i("[react-atom-trigger] `once` and `oncePerDirection` were both provided. `once` takes precedence.")},[o,s]),e.useEffect(()=>{let e=b.current;e&&F(e,{onEnter:t,onLeave:n,onEvent:r})},[t,n,r]),e.useEffect(()=>{if(typeof window>`u`)return;let e=T?A:y.current,i=B(g===void 0?h===void 0?{kind:`viewport`}:{kind:`root`,target:h}:{kind:`rootRef`,target:S});if(!e){b.current&&I(b.current,{disabled:!1,node:null,target:i,rootMargin:C,threshold:w,once:o,oncePerDirection:s,fireOnInitialVisible:c});return}b.current||(b.current=P({node:e,rootMargin:C,threshold:w,once:o,oncePerDirection:s,fireOnInitialVisible:c},{onEnter:t,onLeave:n,onEvent:r})),I(b.current,{disabled:f,node:e,target:i,rootMargin:C,threshold:w,once:o,oncePerDirection:s,fireOnInitialVisible:c})},[f,C,w,o,s,c,A,h,g,S,T]),e.useEffect(()=>()=>{b.current&&(L(b.current),b.current=null)},[]),T?k?e.cloneElement(k,{ref:j}):e.createElement(e.Fragment,null,a):e.createElement(`div`,{ref:y,style:V,className:v})},H=e.useSyncExternalStore,se=typeof window>`u`?e.useEffect:e.useLayoutEffect;function U(t,n,r){if(H)return H(t,n,r);let[i,a]=e.useState(()=>r()),o=e.useRef(i);return se(()=>{let e=()=>{let e=n();Object.is(o.current,e)||(o.current=e,a(e))};return e(),t(e)},[t,n]),i}function W(e,t,n){return n(e.current,t)?e.current:(e.current=t,t)}const G={x:0,y:0},K={width:0,height:0},ce=typeof window>`u`?e.useEffect:e.useLayoutEffect;function q(e,t){let n=null,r=null,i=()=>{n&&(clearTimeout(n),n=null),r=Date.now(),e()};return{schedule:()=>{if(t<=0){i();return}let e=Date.now();if(r===null||e-r>=t){i();return}n||(n=setTimeout(()=>{i()},t-(e-r)))},cancel:()=>{n&&(clearTimeout(n),n=null)}}}function J(){return typeof window>`u`?K:{width:window.innerWidth,height:window.innerHeight}}function Y(e){return!!(e&&typeof e==`object`&&!o(e)&&`current`in e)}function X(e){return Y(e)?e.current:e||(typeof window>`u`?null:window)}function le(e){return e===window||o(e)}function Z(e){if(le(e))return{x:e.scrollX,y:e.scrollY};let t=e;return{x:t.scrollLeft,y:t.scrollTop}}function ue(e){let t=X(e);return t?Z(t):G}function Q(e,t){return e.x===t.x&&e.y===t.y}function $(e,t){return e.width===t.width&&e.height===t.height}function de(t){let n=t?.enabled!==!1,r=t?.passive,i=t?.throttleMs??16,a=e.useRef(J()),o=e.useCallback(()=>typeof window>`u`?K:n?W(a,J(),$):a.current,[n]);return U(e.useCallback(e=>{if(typeof window>`u`||!n)return()=>{};let t=q(()=>{let t=J();$(a.current,t)||(a.current=t,e())},i);return window.addEventListener(`resize`,t.schedule,{passive:r}),()=>{t.cancel(),window.removeEventListener(`resize`,t.schedule)}},[n,r,i]),o,()=>K)}function fe(t){let n=t?.target,r=Y(n),i=t?.enabled!==!1,a=t?.passive,o=t?.throttleMs??16,s=e.useRef(ue(n)),[c,l]=e.useState(()=>r?X(n):null);ce(()=>{if(!r)return;let e=X(n);l(t=>t===e?t:e)});let u=r?c:X(n),d=e.useCallback(()=>i?u?W(s,Z(u),Q):W(s,G,Q):s.current,[i,u]);return U(e.useCallback(e=>{if(!i||!u)return()=>{};let t=q(()=>{let t=Z(u);Q(s.current,t)||(s.current=t,e())},o);return u.addEventListener(`scroll`,t.schedule,{passive:a}),()=>{t.cancel(),u.removeEventListener(`scroll`,t.schedule)}},[i,a,u,o]),d,()=>G)}export{oe as AtomTrigger,fe as useScrollPosition,de as useViewportSize};
package/lib/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`)):typeof define==`function`&&define.amd?define([`exports`,`react`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.reactAtomTrigger={},e.React))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=Object.create,r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,o=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty,c=(e,t,n,o)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=a(t),l=0,u=c.length,d;l<u;l++)d=c[l],!s.call(e,d)&&d!==n&&r(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(o=i(t,d))||o.enumerable});return e};t=((e,t,i)=>(i=e==null?{}:n(o(e)),c(t||!e||!e.__esModule?r(i,`default`,{value:e,enumerable:!0}):i,e)))(t);let l=new Set;function u(){if(typeof process>`u`||!process.env)return null;let e=`production`;return e===`development`||e===`production`?e:null}function d(e){u()===`development`&&(l.has(e)||(l.add(e),typeof console<`u`&&console.warn&&console.warn(e)))}let f=Symbol.for(`react.forward_ref`),p=Symbol.for(`react.memo`);function m(e,t){if(e){if(typeof e==`function`){e(t);return}e.current=t}}function h(e){if(typeof e==`string`||typeof e==`function`)return!0;if(typeof e!=`object`||!e)return!1;let t=e;return t.$$typeof===f?!0:t.$$typeof===p&&t.type?h(t.type):!1}function g(e,n,r,i){return e?n===1?r?i===t.default.Fragment?`[react-atom-trigger] Child mode does not support React.Fragment. Wrap the content in a single DOM element. Observation is disabled for this render.`:(!i||h(i),null):`[react-atom-trigger] Child mode expects a React element child. Observation is disabled for this render.`:`[react-atom-trigger] Child mode expects exactly one top-level React element. Observation is disabled for this render.`:null}function _(e){return Array.isArray(e)&&e.length===4&&e.every(e=>typeof e==`number`&&Number.isFinite(e))}function v(e){return typeof e==`string`?e:_(e)?e.map(e=>`${Object.is(e,-0)?0:e}px`).join(` `):(e==null||d(`[react-atom-trigger] Invalid rootMargin array ${JSON.stringify(e)}. Use exactly four finite numbers: [top, right, bottom, left]. Falling back to 0px.`),`0px`)}function y(e,t){let n=e.trim();if(!n||/^[+-]?0(?:\.0+)?$/.test(n))return 0;let r=n.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(px|%)$/);if(!r)return d(`[react-atom-trigger] Invalid rootMargin token "${n}". Use px, % or 0. Falling back to 0px.`),0;let[,i,a]=r,o=Number.parseFloat(i);return a===`%`?o/100*t:o}function b(e,t,n){let r=e.trim().split(/\s+/).filter(Boolean);if(r.length>4)return d(`[react-atom-trigger] Invalid rootMargin "${e}". Use 1 to 4 values in IntersectionObserver order. Falling back to 0px.`),{top:0,right:0,bottom:0,left:0};let[i=`0px`,a=i,o=i,s=a]=r;return{top:y(i,n),right:y(a,t),bottom:y(o,n),left:y(s,t)}}function x(e,t){let n=b(t,e.width,e.height);return new DOMRect(e.left-n.left,e.top-n.top,e.width+n.left+n.right,e.height+n.top+n.bottom)}function S(e){let t=e.width>0?e.width:1,n=e.height>0?e.height:1;return t===e.width&&n===e.height?e:new DOMRect(e.left,e.top,t,n)}function C(e,t){let n=Math.max(e.left,t.left),r=Math.max(e.top,t.top),i=Math.min(e.right,t.right),a=Math.min(e.bottom,t.bottom);return i<=n||a<=r?new DOMRect(0,0,0,0):new DOMRect(n,r,i-n,a-r)}function w(e,t){let n=e.width*e.height;return n<=0?0:t.width*t.height/n}function T(e){return Math.min(1,Math.max(0,e))}function E(e){return Array.isArray(e)?(d("[react-atom-trigger] `threshold` expects a single number in v2. Using the first finite numeric entry."),T(e.find(e=>typeof e==`number`&&Number.isFinite(e))??0)):e==null?0:typeof e!=`number`||!Number.isFinite(e)?(d("[react-atom-trigger] `threshold` must be a finite number between 0 and 1. Falling back to 0."),0):((e<0||e>1)&&d("[react-atom-trigger] `threshold` should be between 0 and 1. Values are clamped."),T(e))}function D(e,t){if(!e)return`unknown`;let n=t.left-e.left,r=t.top-e.top;return n===0&&r===0?`stationary`:Math.abs(r)>=Math.abs(n)?r<0?`up`:`down`:n<0?`left`:`right`}function O(e){if(e.isIntersecting)return`inside`;let t=e.boundingClientRect,n=e.rootBounds?.top??0,r=e.rootBounds?.bottom??window.innerHeight,i=e.rootBounds?.left??0,a=e.rootBounds?.right??window.innerWidth;return t.bottom<=n?`above`:t.top>=r?`below`:t.right<=i?`left`:t.left>=a?`right`:`outside`}let k=new WeakMap;function A(){return new DOMRect(0,0,window.innerWidth,window.innerHeight)}function j(e){return e===window||typeof Window<`u`&&e instanceof Window}function M(e,t,n,r){return!(n&&t.entered+t.left>0||r&&(e===`enter`&&t.entered>0||e===`leave`&&t.left>0))}function N(e){return e.once?e.counts.entered+e.counts.left>0:e.oncePerDirection?e.counts.entered>0&&e.counts.left>0:!1}function P(e){e.previousTriggerActive=void 0,e.previousRect=null}function F(e,t,n,r){let i=S(e.node.getBoundingClientRect()),a=x(t,e.rootMargin),o=C(i,a),s=w(i,o),c=s>0,l=e.previousTriggerActive,u=l===!0||e.threshold===0?c:s>=e.threshold,d=e.previousRect&&(n===`root-change`||r)?`stationary`:D(e.previousRect,i);e.previousRect=i,e.previousTriggerActive=u;let f=Date.now(),p={target:e.node,rootBounds:a,boundingClientRect:i,intersectionRect:o,isIntersecting:c,intersectionRatio:s,source:`geometry`},m=l===void 0;if(m&&(!e.fireOnInitialVisible||!u)||l===u)return;let h=u?`enter`:`leave`;if(!M(h,e.counts,e.once,e.oncePerDirection))return;let g=h===`enter`?{...e.counts,entered:e.counts.entered+1}:{...e.counts,left:e.counts.left+1};e.counts=g;let _={type:h,isInitial:m,entry:p,counts:g,movementDirection:d,position:O(p),timestamp:f};e.onEvent?.(_),h===`enter`?e.onEnter?.(_):e.onLeave?.(_),N(e)&&e.dispose?.()}function I(e){let t={registrations:new Set,rafId:0,pendingSampleCause:null,previousBaseRootBounds:null,resizeObserver:null,intersectionObserver:null,queueSample:()=>{},cleanup:()=>{}},n=()=>{if(t.rafId=0,t.registrations.size===0){t.pendingSampleCause=null;return}let n=t.pendingSampleCause??`geometry-change`;t.pendingSampleCause=null;let r=j(e)?A():e.getBoundingClientRect(),i=t.previousBaseRootBounds!==null&&(t.previousBaseRootBounds.top!==r.top||t.previousBaseRootBounds.left!==r.left||t.previousBaseRootBounds.width!==r.width||t.previousBaseRootBounds.height!==r.height);for(let e of t.registrations)F(e,r,n,i);t.previousBaseRootBounds=new DOMRect(r.left,r.top,r.width,r.height)},r=(e=`geometry-change`)=>{if((t.pendingSampleCause===null||t.pendingSampleCause===`geometry-change`&&e!==`geometry-change`||t.pendingSampleCause===`root-change`&&e===`scroll`)&&(t.pendingSampleCause=e),t.rafId!==0)return;t.rafId=-1;let r=window.requestAnimationFrame(()=>{t.rafId=0,n()});t.rafId===-1&&(t.rafId=r)},i=()=>{r(`scroll`)},a=()=>{r(`root-change`)};return e.addEventListener(`scroll`,i,{passive:!0}),window.addEventListener(`resize`,a),typeof ResizeObserver<`u`&&(t.resizeObserver=new ResizeObserver(a),j(e)||t.resizeObserver.observe(e)),typeof IntersectionObserver<`u`&&(t.intersectionObserver=new IntersectionObserver(()=>{r(`geometry-change`)},{root:j(e)?null:e,rootMargin:`200% 200% 200% 200%`,threshold:0})),t.queueSample=r,t.cleanup=()=>{t.rafId!==0&&(cancelAnimationFrame(t.rafId),t.rafId=0),e.removeEventListener(`scroll`,i),window.removeEventListener(`resize`,a),t.resizeObserver?.disconnect(),t.intersectionObserver?.disconnect(),t.pendingSampleCause=null,t.previousBaseRootBounds=null},t}function L(e){let t=k.get(e);if(t)return t;let n=I(e);return k.set(e,n),n}function R(e,t){let n=L(e),r=!1;n.registrations.add(t),n.resizeObserver?.observe(t.node),n.intersectionObserver?.observe(t.node),n.queueSample();let i=()=>{r||(r=!0,n.registrations.delete(t),n.resizeObserver?.unobserve(t.node),n.intersectionObserver?.unobserve(t.node),t.dispose=void 0,n.registrations.size===0&&(n.cleanup(),k.delete(e)))};return t.dispose=i,i}function z(e,t){return t?t.current:e||(typeof window>`u`?null:window)}let B={display:`table`},V=({onEnter:e,onLeave:n,onEvent:r,children:i,once:a=!1,oncePerDirection:o=!1,fireOnInitialVisible:s=!1,disabled:c=!1,threshold:l=0,root:u=null,rootRef:f,rootMargin:p=`0px`,className:h})=>{let _=t.default.useRef(null),[y,b]=t.default.useState(null),x=t.default.useRef(null),S=t.default.useRef(null),C=t.default.useRef(null),w=t.default.useRef(null),T=v(p),D=E(l),O=i!=null,k=t.default.Children.count(i),A=k===1&&t.default.isValidElement(i)?i:null,j=g(O,k,A,A?A.type:null),M=j||!A?null:A,N=M?.props.ref,F=t.default.useCallback(e=>{if(m(N,e),e===null){x.current=null,b(e=>e===null?e:null);return}if(e instanceof Element){x.current=e,b(t=>t===e?t:e);return}x.current=null,b(e=>e===null?e:null),d(`[react-atom-trigger] Child mode requires the child ref to resolve to a DOM element. Observation is disabled for this render.`)},[N]);return t.default.useEffect(()=>{d(`[react-atom-trigger] v2 uses a new internal observation engine. If you upgraded from v1.x, verify trigger behavior for timing, threshold and rootMargin.`)},[]),t.default.useEffect(()=>{O&&h&&d("[react-atom-trigger] `className` only applies to the internal sentinel. In child mode, style the child element directly.")},[h,O]),t.default.useEffect(()=>{j&&d(j)},[j]),t.default.useEffect(()=>{if(typeof window>`u`||!O||!M||j||y)return;let e=window.setTimeout(()=>{x.current||d(`[react-atom-trigger] Child mode expects a DOM element or a component that forwards its ref to a DOM element. Observation is disabled for this render.`)},0);return()=>{window.clearTimeout(e)}},[y,M,O,j]),t.default.useEffect(()=>{let t=S.current;t&&(t.onEnter=e,t.onLeave=n,t.onEvent=r)},[e,n,r]),t.default.useEffect(()=>{if(typeof window>`u`)return;let t=O?y:_.current,i=z(u,f);if(!t){S.current&&P(S.current),C.current?.(),C.current=null,w.current=null;return}S.current?(S.current.node=t,S.current.rootMargin=T,S.current.threshold=D,S.current.once=a,S.current.oncePerDirection=o,S.current.fireOnInitialVisible=s):S.current={node:t,rootMargin:T,threshold:D,once:a,oncePerDirection:o,fireOnInitialVisible:s,onEnter:e,onLeave:n,onEvent:r,previousTriggerActive:void 0,previousRect:null,counts:{entered:0,left:0}};let l=S.current;if(c||!i){P(l),C.current?.(),C.current=null,w.current=null;return}let d=w.current,p={node:t,target:i,rootMargin:T,threshold:D,once:a,oncePerDirection:o,fireOnInitialVisible:s};(!d||d.node!==p.node||d.target!==p.target||d.rootMargin!==p.rootMargin||d.threshold!==p.threshold||d.once!==p.once||d.oncePerDirection!==p.oncePerDirection||d.fireOnInitialVisible!==p.fireOnInitialVisible)&&(P(l),C.current?.(),C.current=R(i,l),w.current=p)},[c,T,D,a,o,s,y,u,f?.current,O]),t.default.useEffect(()=>()=>{C.current?.(),C.current=null,w.current=null},[]),O?M?t.default.cloneElement(M,{ref:F}):t.default.createElement(t.default.Fragment,null,i):t.default.createElement(`div`,{ref:_,style:B,className:h})},H={x:0,y:0},U=typeof window>`u`?t.default.useEffect:t.default.useLayoutEffect;function W(e,t){let n=null,r=null,i=()=>{n&&(clearTimeout(n),n=null),r=Date.now(),e()};return{schedule:()=>{if(t<=0){i();return}let e=Date.now();if(r===null||e-r>=t){i();return}n||(n=setTimeout(()=>{i()},t-(e-r)))},cancel:()=>{n&&(clearTimeout(n),n=null)}}}function G(){return typeof window>`u`?{width:0,height:0}:{width:window.innerWidth,height:window.innerHeight}}function K(e){return!!(e&&typeof e==`object`&&!(typeof Window<`u`&&e instanceof Window)&&`current`in e)}function q(e){return K(e)?e.current:e||(typeof window>`u`?null:window)}function J(e){return e===window||typeof Window<`u`&&e instanceof Window}function Y(e){if(J(e))return{x:e.scrollX,y:e.scrollY};let t=e;return{x:t.scrollLeft,y:t.scrollTop}}function X(e){let[n,r]=t.default.useState(G);return t.default.useEffect(()=>{if(typeof window>`u`||e?.enabled===!1)return;let t=e?.throttleMs??16;r(G());let n=W(()=>{r(G())},t);return window.addEventListener(`resize`,n.schedule,{passive:e?.passive}),()=>{n.cancel(),window.removeEventListener(`resize`,n.schedule)}},[e?.enabled,e?.passive,e?.throttleMs]),n}function Z(e){let n=e?.target,r=K(n),[i,a]=t.default.useState(()=>{let e=q(n);return e?Y(e):H}),[o,s]=t.default.useState(()=>r?q(n):null);U(()=>{if(!r)return;let e=q(n);s(t=>t===e?t:e)});let c=r?o:q(n);return t.default.useEffect(()=>{if(e?.enabled===!1){a(H);return}if(!c){a(H);return}let t=e?.throttleMs??16;a(Y(c));let n=W(()=>{a(Y(c))},t);return c.addEventListener(`scroll`,n.schedule,{passive:e?.passive}),()=>{n.cancel(),c.removeEventListener(`scroll`,n.schedule)}},[e?.enabled,e?.passive,e?.throttleMs,c]),i}e.AtomTrigger=V,e.useScrollPosition=Z,e.useViewportSize=X});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`)):typeof define==`function`&&define.amd?define([`exports`,`react`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.reactAtomTrigger={},e.React))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=Object.create,r=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,o=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty,c=(e,t,n,o)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=a(t),l=0,u=c.length,d;l<u;l++)d=c[l],!s.call(e,d)&&d!==n&&r(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(o=i(t,d))||o.enumerable});return e};t=((e,t,i)=>(i=e==null?{}:n(o(e)),c(t||!e||!e.__esModule?r(i,`default`,{value:e,enumerable:!0}):i,e)))(t);let l=new Set;function u(){if(typeof process>`u`||!process.env)return null;let e=`production`;return e===`development`||e===`production`?e:null}function d(e){return(Object.prototype.hasOwnProperty.call(e??{},`nodeEnv`)?e?.nodeEnv??null:u())===`development`}function f(e){d()&&(l.has(e)||(l.add(e),typeof console<`u`&&console.warn&&console.warn(e)))}function p(e){return!!(e&&typeof e==`object`&&`nodeType`in e&&e.nodeType===1&&`getBoundingClientRect`in e&&typeof e.getBoundingClientRect==`function`&&`addEventListener`in e&&typeof e.addEventListener==`function`&&`removeEventListener`in e&&typeof e.removeEventListener==`function`)}function m(e){return!!(e&&typeof e==`object`&&`window`in e&&e.window===e)}function h(e,t){if(e){if(typeof e==`function`){e(t);return}e.current=t}}function g(e){if(!e||typeof e!=`object`&&typeof e!=`function`)return;let t=Object.getOwnPropertyDescriptor(e,`ref`);if(!(!t||!(`value`in t)))return t.value}function _(e){if(!e)return;let t=g(e.props);return t===void 0?g(e):t}function v(e,n,r){return e?n===1?r?r.type===t.default.Fragment?`[react-atom-trigger] Child mode does not support React.Fragment. Wrap the content in a single DOM element. Observation is disabled for this render.`:null:`[react-atom-trigger] Child mode expects a React element child. Observation is disabled for this render.`:`[react-atom-trigger] Child mode expects exactly one top-level React element. Observation is disabled for this render.`:null}function y({originalChildRef:e,hasObservedChild:n,invalidChildWarning:r,shouldWarnAboutMissingDomRef:i}){let[a,o]=t.default.useState(null),s=t.default.useRef(null),c=t.default.useCallback(()=>{s.current=null,o(e=>e===null?e:null)},[]),l=t.default.useCallback(t=>{if(h(e,t),t===null){c();return}if(p(t)){s.current=t,o(e=>e===t?e:t);return}c(),f(`[react-atom-trigger] Child mode requires the child ref to resolve to a DOM element. Observation is disabled for this render.`)},[c,e]);return t.default.useEffect(()=>{if(typeof window>`u`||!(n&&!r&&!a&&i))return;let e=window.setTimeout(()=>{s.current||f(`[react-atom-trigger] Child mode expects a DOM element or a component that forwards its ref to a DOM element. Observation is disabled for this render.`)},16);return()=>{window.clearTimeout(e)}},[n,r,a,i]),{childNode:a,attachObservedChildRef:l}}function b(e){return Array.isArray(e)&&e.length===4&&e.every(e=>typeof e==`number`&&Number.isFinite(e))}function ee(e){return typeof e==`string`?e:b(e)?e.map(e=>`${Object.is(e,-0)?0:e}px`).join(` `):(e==null||f(`[react-atom-trigger] Invalid rootMargin array ${JSON.stringify(e)}. Use exactly four finite numbers: [top, right, bottom, left]. Falling back to 0px.`),`0px`)}function x(e,t){let n=e.trim();if(!n||/^[+-]?0(?:\.0+)?$/.test(n))return 0;let r=n.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(px|%)$/);if(!r)return f(`[react-atom-trigger] Invalid rootMargin token "${n}". Use px, % or 0. Falling back to 0px.`),0;let[,i,a]=r,o=Number.parseFloat(i);return a===`%`?o/100*t:o}function S(e,t,n){let r=e.trim().split(/\s+/).filter(Boolean);if(r.length>4)return f(`[react-atom-trigger] Invalid rootMargin "${e}". Use 1 to 4 values in IntersectionObserver order. Falling back to 0px.`),{top:0,right:0,bottom:0,left:0};let[i=`0px`,a=i,o=i,s=a]=r;return{top:x(i,n),right:x(a,t),bottom:x(o,n),left:x(s,t)}}function C(e,t){let n=S(t,e.width,e.height);return new DOMRect(e.left-n.left,e.top-n.top,e.width+n.left+n.right,e.height+n.top+n.bottom)}function w(e){let t=e.width>0?e.width:1,n=e.height>0?e.height:1;return t===e.width&&n===e.height?e:new DOMRect(e.left,e.top,t,n)}function T(e,t){let n=Math.max(e.left,t.left),r=Math.max(e.top,t.top),i=Math.min(e.right,t.right),a=Math.min(e.bottom,t.bottom);return i<=n||a<=r?new DOMRect(0,0,0,0):new DOMRect(n,r,i-n,a-r)}function E(e,t){let n=e.width*e.height;return n<=0?0:t.width*t.height/n}function D(e){return Math.min(1,Math.max(0,e))}function te(e){return Array.isArray(e)?(f("[react-atom-trigger] `threshold` expects a single number in v2. Using the first finite numeric entry."),D(e.find(e=>typeof e==`number`&&Number.isFinite(e))??0)):e==null?0:typeof e!=`number`||!Number.isFinite(e)?(f("[react-atom-trigger] `threshold` must be a finite number between 0 and 1. Falling back to 0."),0):((e<0||e>1)&&f("[react-atom-trigger] `threshold` should be between 0 and 1. Values are clamped."),D(e))}function O(e,t){if(!e)return`unknown`;let n=t.left-e.left,r=t.top-e.top;return n===0&&r===0?`stationary`:Math.abs(r)>=Math.abs(n)?r<0?`up`:`down`:n<0?`left`:`right`}function k(e){if(e.isIntersecting)return`inside`;let t=e.boundingClientRect,n=e.rootBounds?.top??0,r=e.rootBounds?.bottom??window.innerHeight,i=e.rootBounds?.left??0,a=e.rootBounds?.right??window.innerWidth;return t.bottom<=n?`above`:t.top>=r?`below`:t.right<=i?`left`:t.left>=a?`right`:`outside`}function A(e,t,n,r){return!(n&&t.entered+t.left>0||r&&(e===`enter`&&t.entered>0||e===`leave`&&t.left>0))}function ne(e){return e.once?e.counts.entered+e.counts.left>0:e.oncePerDirection?e.counts.entered>0&&e.counts.left>0:!1}function j(e){e.previousTriggerActive=void 0,e.previousRect=null}function re(e,t,n,r){let i=w(e.node.getBoundingClientRect()),a=C(t,e.rootMargin),o=T(i,a),s=E(i,o),c=s>0,l=e.previousTriggerActive,u=l===!0||e.threshold===0?c:s>=e.threshold,d=e.previousRect&&(n===`root-change`||r)?`stationary`:O(e.previousRect,i);e.previousRect=i,e.previousTriggerActive=u;let f=Date.now(),p={target:e.node,rootBounds:a,boundingClientRect:i,intersectionRect:o,isIntersecting:c,intersectionRatio:s,source:`geometry`},m=l===void 0;if(m&&(!e.fireOnInitialVisible||!u)||l===u)return;let h=u?`enter`:`leave`;if(!A(h,e.counts,e.once,e.oncePerDirection))return;let g=h===`enter`?{...e.counts,entered:e.counts.entered+1}:{...e.counts,left:e.counts.left+1};e.counts=g;let _={type:h,isInitial:m,entry:p,counts:g,movementDirection:d,position:k(p),timestamp:f};e.onEvent?.(_),h===`enter`?e.onEnter?.(_):e.onLeave?.(_),ne(e)&&e.dispose?.()}let M=new WeakMap;function ie(){return new DOMRect(0,0,window.innerWidth,window.innerHeight)}function N(e){return e===window||m(e)}function ae(e){let t={registrations:new Set,rafId:0,pendingSampleCause:null,previousBaseRootBounds:null,resizeObserver:null,intersectionObserver:null,queueSample:()=>{},cleanup:()=>{}},n=()=>{if(t.rafId=0,t.registrations.size===0){t.pendingSampleCause=null;return}let n=t.pendingSampleCause??`geometry-change`;t.pendingSampleCause=null;let r=N(e)?ie():e.getBoundingClientRect(),i=t.previousBaseRootBounds!==null&&(t.previousBaseRootBounds.top!==r.top||t.previousBaseRootBounds.left!==r.left||t.previousBaseRootBounds.width!==r.width||t.previousBaseRootBounds.height!==r.height);for(let e of t.registrations)re(e,r,n,i);t.previousBaseRootBounds=new DOMRect(r.left,r.top,r.width,r.height)},r=(e=`geometry-change`)=>{if((t.pendingSampleCause===null||t.pendingSampleCause===`geometry-change`&&e!==`geometry-change`||t.pendingSampleCause===`root-change`&&e===`scroll`)&&(t.pendingSampleCause=e),t.rafId!==0)return;t.rafId=-1;let r=window.requestAnimationFrame(()=>{t.rafId=0,n()});t.rafId===-1&&(t.rafId=r)},i=()=>{r(`scroll`)},a=()=>{r(`root-change`)};return e.addEventListener(`scroll`,i,{passive:!0}),window.addEventListener(`resize`,a),typeof ResizeObserver<`u`&&(t.resizeObserver=new ResizeObserver(a),N(e)||t.resizeObserver.observe(e)),typeof IntersectionObserver<`u`&&(t.intersectionObserver=new IntersectionObserver(()=>{r(`geometry-change`)},{root:N(e)?null:e,rootMargin:`200% 200% 200% 200%`,threshold:0})),t.queueSample=r,t.cleanup=()=>{t.rafId!==0&&(cancelAnimationFrame(t.rafId),t.rafId=0),e.removeEventListener(`scroll`,i),window.removeEventListener(`resize`,a),t.resizeObserver?.disconnect(),t.intersectionObserver?.disconnect(),t.pendingSampleCause=null,t.previousBaseRootBounds=null},t}function oe(e){let t=M.get(e);if(t)return t;let n=ae(e);return M.set(e,n),n}function se(e,t){let n=oe(e),r=!1,i=t.node;n.registrations.add(t),n.resizeObserver?.observe(i),n.intersectionObserver?.observe(i),n.queueSample();let a=()=>{r||(r=!0,n.registrations.delete(t),n.resizeObserver?.unobserve(i),n.intersectionObserver?.unobserve(i),t.dispose=void 0,n.registrations.size===0&&(n.cleanup(),M.delete(e)))};return t.dispose=a,a}function ce(e,t){return{...e,...t,previousTriggerActive:void 0,previousRect:null,counts:{entered:0,left:0}}}function P(e,t){e.node=t.node,e.rootMargin=t.rootMargin,e.threshold=t.threshold,e.once=t.once,e.oncePerDirection=t.oncePerDirection,e.fireOnInitialVisible=t.fireOnInitialVisible}function le(e,t){e.onEnter=t.onEnter,e.onLeave=t.onLeave,e.onEvent=t.onEvent}function F(e){e.dispose?.(),e.dispose=null,e.binding=null}function ue(e){return{node:e.node,rootMargin:e.rootMargin,threshold:e.threshold,once:e.once,oncePerDirection:e.oncePerDirection,fireOnInitialVisible:e.fireOnInitialVisible}}function de(e,t){return!!(e&&e.node===t.node&&e.target===t.target&&e.rootMargin===t.rootMargin&&e.threshold===t.threshold&&e.once===t.once&&e.oncePerDirection===t.oncePerDirection&&e.fireOnInitialVisible===t.fireOnInitialVisible)}function I(e,t){return{registration:ce(e,t),binding:null,dispose:null}}function L(e,t){le(e.registration,t)}function R(e,t){let n=e.registration;if(!t.node){j(n),F(e);return}let r=ue({node:t.node,rootMargin:t.rootMargin,threshold:t.threshold,once:t.once,oncePerDirection:t.oncePerDirection,fireOnInitialVisible:t.fireOnInitialVisible});if(t.disabled||!t.target){F(e),P(n,r),j(n);return}let i={...r,target:t.target};if(de(e.binding,i)){P(n,r);return}j(n),F(e),P(n,r),e.dispose=se(t.target,n),e.binding=i}function z(e){F(e)}function B(e){let t=e.kind===`rootRef`?"[react-atom-trigger] `rootRef.current` must resolve to a real DOM element. Observation is paused until it does.":"[react-atom-trigger] `root` must be a real DOM element when provided. Observation is paused until it is.",{target:n}=e;return n==null?null:p(n)?n:(f(t),null)}function V(e){let n=e!==void 0,[r,i]=t.default.useState(()=>n?e.current:null);return t.default.useEffect(()=>{if(!n)return;let t=e.current;i(e=>e===t?e:t)}),n?r:void 0}function fe(e){switch(e.kind){case`rootRef`:case`root`:return B(e);case`viewport`:return typeof window>`u`?null:window}}let pe={display:`table`},me=({onEnter:e,onLeave:n,onEvent:r,children:i,once:a=!1,oncePerDirection:o=!1,fireOnInitialVisible:s=!1,disabled:c=!1,threshold:l=0,root:u,rootRef:d,rootMargin:p=`0px`,className:m})=>{let h=t.default.useRef(null),g=t.default.useRef(null),b=V(d),x=ee(p),S=te(l),C=i!=null,w=t.default.Children.count(i),T=w===1&&t.default.isValidElement(i)?i:null,E=v(C,w,T),D=E||!T?null:T,{childNode:O,attachObservedChildRef:k}=y({originalChildRef:_(D),hasObservedChild:C,invalidChildWarning:E,shouldWarnAboutMissingDomRef:D!==null});return t.default.useEffect(()=>{C&&m&&f("[react-atom-trigger] `className` only applies to the internal sentinel. In child mode, style the child element directly.")},[m,C]),t.default.useEffect(()=>{E&&f(E)},[E]),t.default.useEffect(()=>{a&&o&&f("[react-atom-trigger] `once` and `oncePerDirection` were both provided. `once` takes precedence.")},[a,o]),t.default.useEffect(()=>{let t=g.current;t&&L(t,{onEnter:e,onLeave:n,onEvent:r})},[e,n,r]),t.default.useEffect(()=>{if(typeof window>`u`)return;let t=C?O:h.current,i=fe(d===void 0?u===void 0?{kind:`viewport`}:{kind:`root`,target:u}:{kind:`rootRef`,target:b});if(!t){g.current&&R(g.current,{disabled:!1,node:null,target:i,rootMargin:x,threshold:S,once:a,oncePerDirection:o,fireOnInitialVisible:s});return}g.current||(g.current=I({node:t,rootMargin:x,threshold:S,once:a,oncePerDirection:o,fireOnInitialVisible:s},{onEnter:e,onLeave:n,onEvent:r})),R(g.current,{disabled:c,node:t,target:i,rootMargin:x,threshold:S,once:a,oncePerDirection:o,fireOnInitialVisible:s})},[c,x,S,a,o,s,O,u,d,b,C]),t.default.useEffect(()=>()=>{g.current&&(z(g.current),g.current=null)},[]),C?D?t.default.cloneElement(D,{ref:k}):t.default.createElement(t.default.Fragment,null,i):t.default.createElement(`div`,{ref:h,style:pe,className:m})},H=t.default.useSyncExternalStore,he=typeof window>`u`?t.default.useEffect:t.default.useLayoutEffect;function U(e,n,r){if(H)return H(e,n,r);let[i,a]=t.default.useState(()=>r()),o=t.default.useRef(i);return he(()=>{let t=()=>{let e=n();Object.is(o.current,e)||(o.current=e,a(e))};return t(),e(t)},[e,n]),i}function W(e,t,n){return n(e.current,t)?e.current:(e.current=t,t)}let G={x:0,y:0},K={width:0,height:0},ge=typeof window>`u`?t.default.useEffect:t.default.useLayoutEffect;function q(e,t){let n=null,r=null,i=()=>{n&&(clearTimeout(n),n=null),r=Date.now(),e()};return{schedule:()=>{if(t<=0){i();return}let e=Date.now();if(r===null||e-r>=t){i();return}n||(n=setTimeout(()=>{i()},t-(e-r)))},cancel:()=>{n&&(clearTimeout(n),n=null)}}}function J(){return typeof window>`u`?K:{width:window.innerWidth,height:window.innerHeight}}function Y(e){return!!(e&&typeof e==`object`&&!m(e)&&`current`in e)}function X(e){return Y(e)?e.current:e||(typeof window>`u`?null:window)}function _e(e){return e===window||m(e)}function Z(e){if(_e(e))return{x:e.scrollX,y:e.scrollY};let t=e;return{x:t.scrollLeft,y:t.scrollTop}}function ve(e){let t=X(e);return t?Z(t):G}function Q(e,t){return e.x===t.x&&e.y===t.y}function $(e,t){return e.width===t.width&&e.height===t.height}function ye(e){let n=e?.enabled!==!1,r=e?.passive,i=e?.throttleMs??16,a=t.default.useRef(J()),o=t.default.useCallback(()=>typeof window>`u`?K:n?W(a,J(),$):a.current,[n]);return U(t.default.useCallback(e=>{if(typeof window>`u`||!n)return()=>{};let t=q(()=>{let t=J();$(a.current,t)||(a.current=t,e())},i);return window.addEventListener(`resize`,t.schedule,{passive:r}),()=>{t.cancel(),window.removeEventListener(`resize`,t.schedule)}},[n,r,i]),o,()=>K)}function be(e){let n=e?.target,r=Y(n),i=e?.enabled!==!1,a=e?.passive,o=e?.throttleMs??16,s=t.default.useRef(ve(n)),[c,l]=t.default.useState(()=>r?X(n):null);ge(()=>{if(!r)return;let e=X(n);l(t=>t===e?t:e)});let u=r?c:X(n),d=t.default.useCallback(()=>i?u?W(s,Z(u),Q):W(s,G,Q):s.current,[i,u]);return U(t.default.useCallback(e=>{if(!i||!u)return()=>{};let t=q(()=>{let t=Z(u);Q(s.current,t)||(s.current=t,e())},o);return u.addEventListener(`scroll`,t.schedule,{passive:a}),()=>{t.cancel(),u.removeEventListener(`scroll`,t.schedule)}},[i,a,u,o]),d,()=>G)}e.AtomTrigger=me,e.useScrollPosition=be,e.useViewportSize=ye});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-atom-trigger",
3
- "version": "2.0.2",
3
+ "version": "2.0.6",
4
4
  "description": "Geometry-based scroll trigger for React with precise enter/leave control. A modern alternative to react-waypoint.",
5
5
  "keywords": [
6
6
  "intersection",
@@ -52,9 +52,12 @@
52
52
  "precommit:checks": "pnpm format:check && pnpm lint && pnpm test",
53
53
  "test": "pnpm test:all",
54
54
  "test:all": "pnpm test:unit && pnpm test:storybook",
55
- "test:coverage": "pnpm test:coverage:unit && pnpm test:coverage:storybook",
55
+ "test:coverage": "pnpm test:coverage:unit",
56
56
  "test:coverage:unit": "vitest run --project=unit --reporter=verbose --coverage.enabled=true --coverage.reportsDirectory=coverage/unit",
57
57
  "test:coverage:storybook": "vitest run --project=storybook --coverage.enabled=true --coverage.reportsDirectory=coverage/storybook",
58
+ "test:package-smoke": "node scripts/package-smoke.mjs",
59
+ "test:react-compat": "node scripts/react-compat-smoke.mjs",
60
+ "test:react-compat:matrix": "node scripts/react-compat-matrix.mjs",
58
61
  "test:unit": "vitest run --project=unit --reporter=verbose",
59
62
  "test:watch": "vitest --project=unit",
60
63
  "test:storybook": "vitest run --project=storybook",
@@ -62,6 +65,7 @@
62
65
  "build-storybook": "storybook build -o storybook-static"
63
66
  },
64
67
  "devDependencies": {
68
+ "@codecov/rollup-plugin": "^1.9.1",
65
69
  "@storybook/addon-docs": "10.3.4",
66
70
  "@storybook/addon-vitest": "10.3.4",
67
71
  "@storybook/react-vite": "10.3.4",
@@ -88,12 +92,11 @@
88
92
  "peerDependencies": {
89
93
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
90
94
  },
91
- "engines": {
92
- "node": ">=20.19.0"
93
- },
94
95
  "packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
95
96
  "pnpm": {
96
97
  "overrides": {
98
+ "@actions/github>undici": "7.24.7",
99
+ "@actions/http-client>undici": "7.24.7",
97
100
  "picomatch": "^4.0.4"
98
101
  }
99
102
  }