react-sticky-kit 0.2.0 โ†’ 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,7 +31,7 @@ A lightweight, flexible React sticky container and item component library. Easil
31
31
  - ๐Ÿ“ฆ Simple API: `<StickyContainer>` and `<StickyItem>`
32
32
  - ๐Ÿงฉ Supports `replace`, `stack`, and `none` sticky modes
33
33
  - ๐Ÿท๏ธ Customizable offset, z-index (baseZIndex), and sticky logic
34
- - ๐Ÿ–ฅ๏ธ Flexible reference containers (window, DOM elements, refs)
34
+ - ๐Ÿ–ฅ๏ธ Viewport-relative sticky offsets, including updates on nested scroll events
35
35
  - ๐Ÿ”„ Supports SSR/SSG (Next.js, Gatsby, Astro, etc.)
36
36
  - ๐Ÿงช Handles edge cases: empty sections, dynamic heights, zero-height headers, long headers, etc.
37
37
  - โšก๏ธ Written in TypeScript, fully typed
@@ -84,7 +84,7 @@ export default function Example() {
84
84
  | `baseZIndex` | `number` | `200` | Base z-index for sticky items. Should be greater than the number of sticky items. |
85
85
  | | | | In `replace` mode, z-index = baseZIndex - index; in `stack` mode, z-index = baseZIndex + index. |
86
86
  | `onStickyItemsHeightChange` | `(height: number) => void` | | Callback when total sticky height changes |
87
- | `constraint` | `'none'` | | Define the constraint for sticky behavior. 'none' = no constraints (CSS-like behavior) |
87
+ | `constraint` | `'none'` | | Define the constraint for sticky behavior. 'none' = no container boundary |
88
88
 
89
89
  ### `<StickyItem />`
90
90
  | Prop | Type | Default | Description |
@@ -113,14 +113,9 @@ function Example() {
113
113
  <div>Content...</div>
114
114
  </StickyContainer>
115
115
 
116
- {/* 2. No constraints (like CSS position:sticky) */}
116
+ {/* 2. No container boundary */}
117
117
  <StickyContainer constraint="none">
118
- <StickyItem><div>Always sticky like CSS position:sticky</div></StickyItem>
119
- <div>Content...</div>
120
- </StickyContainer>
121
- </div>
122
- );
123
- }
118
+ <StickyItem><div>Sticky even after the container leaves</div></StickyItem>
124
119
  <div>Content...</div>
125
120
  </StickyContainer>
126
121
  </div>
@@ -130,7 +125,7 @@ function Example() {
130
125
 
131
126
  ### Special behavior of `constraint="none"`
132
127
 
133
- When you set `constraint="none"`, the sticky items will always stick when they reach the top of the viewport, regardless of their parent container's visibility. This exactly matches the behavior of native CSS `position: sticky`.
128
+ When you set `constraint="none"`, the sticky items will always stick when they reach the top of the viewport, regardless of their parent container's visibility. Offsets remain relative to the viewport; this differs from native CSS `position: sticky`, which is constrained by its scrolling ancestor.
134
129
 
135
130
  In contrast, the default behavior (without specifying a constraint) only makes items sticky when their parent container is visible in the viewport.
136
131
 
@@ -158,7 +153,7 @@ React Sticky Kit supports Server-Side Rendering (SSR) and Static Site Generation
158
153
  ### Next.js Example
159
154
 
160
155
  ```tsx
161
- // pages/index.tsx
156
+ // app/page.tsx (Next.js App Router)
162
157
  import { StickyContainer, StickyItem } from 'react-sticky-kit'
163
158
  import 'react-sticky-kit/dist/style.css'
164
159
 
@@ -174,28 +169,89 @@ export default function Home() {
174
169
  }
175
170
  ```
176
171
 
172
+ For Pages Router, import the global stylesheet from `pages/_app.tsx`.
173
+
177
174
  ### Astro Example
178
175
 
176
+ Create a React component containing both `StickyContainer` and `StickyItem`, then
177
+ hydrate it from Astro:
178
+
179
179
  ```astro
180
180
  ---
181
- // src/pages/index.astro
182
- import { StickyContainer, StickyItem } from 'react-sticky-kit'
183
- import 'react-sticky-kit/dist/style.css'
181
+ import StickyLayout from '../components/StickyLayout.tsx'
182
+ import 'react-sticky-kit/style'
184
183
  ---
184
+ <StickyLayout client:load />
185
+ ```
185
186
 
186
- <html>
187
- <head>...</head>
188
- <body>
189
- <StickyContainer client:load>
190
- <StickyItem>
191
- <header>Sticky Header</header>
192
- </StickyItem>
193
- <div>Content...</div>
194
- </StickyContainer>
195
- </body>
196
- </html>
187
+ ## Compatibility and updates
188
+
189
+ React 17 and later are supported. Import the stylesheet explicitly, using either
190
+ `react-sticky-kit/style` or `react-sticky-kit/dist/style.css`. ESM, CommonJS and the
191
+ UMD browser build are available; UMD requires a global `React`.
192
+
193
+ The built entry points include `"use client"` for Next.js App Router. Pages Router
194
+ and server rendering remain supported; sticky layout is applied after mounting.
195
+ For Astro, wrap the sticky layout in a React component and hydrate that component
196
+ as a single island.
197
+
198
+ Sticky offsets use the viewport, even when an event comes from a nested scrolling
199
+ element. Ancestor transforms and overflow clipping can affect fixed positioning;
200
+ use native CSS `position: sticky` if you need offsets relative to a scrolling ancestor.
201
+
202
+ When available, `ResizeObserver` updates dynamic content heights and widths, and
203
+ tracks ancestor and preceding sibling sizes that can move the container. Shared,
204
+ scoped `MutationObserver` subscriptions refresh these observations when the surrounding
205
+ DOM structure or relevant classes/styles change. Observers and global scroll/resize
206
+ listeners are shared across containers. No continuous polling is used.
207
+ Without `ResizeObserver`, measurements update on scroll, window resize and component
208
+ commits. Native browser scroll anchoring can move the viewport when content above
209
+ it changes; sticky positions follow the resulting viewport.
210
+
211
+ Wrapper padding, borders and `box-sizing` are accounted for when preserving the
212
+ placeholder and content width. Definite inline heights are retained. Fixed headers
213
+ also follow horizontal scrolling. Per-item layout metrics are cached and invalidated
214
+ by observed dimension changes, window resize, relevant DOM changes and React
215
+ commits. Inactive or fully replaced headers do not have their content heights measured during scrolling.
216
+ `onStickyItemsHeightChange` reports the final total once per animation frame, after
217
+ all scheduled containers have applied their styles, when it changes, including zero when no items remain sticky. It does not emit transient
218
+ per-item totals or callbacks after the container unmounts.
219
+
220
+ ## Performance
221
+
222
+ Scheduled containers share one animation frame. Their geometry reads finish before
223
+ any sticky styles are written, and unchanged layouts skip repeated style handling.
224
+ Inactive content heights are not measured.
225
+ Prefer grouping related sections in one container rather than mounting a container
226
+ for every row. Large numbers of simultaneously stacked headers still require
227
+ per-frame geometry reads. See the [performance audit](docs/performance.md) for
228
+ stress-test findings and limitations.
229
+
230
+ ## Development
231
+
232
+ Use Node.js 22.22.2+ or 24.15.0+ and the pnpm version pinned in `package.json`.
233
+ The development tools require these versions; the published library keeps its
234
+ React 17+ peer dependency range and targets ES2018.
235
+
236
+ ```bash
237
+ pnpm install --frozen-lockfile
238
+ pnpm type-check
239
+ pnpm lint
240
+ pnpm test
241
+ pnpm build
242
+ pnpm check:package
243
+ pnpm check:compatibility # installs the tarball with React 17, 18 and 19
244
+ pnpm exec playwright install --with-deps chromium firefox webkit
245
+ pnpm test:browser
197
246
  ```
198
247
 
248
+ TypeScript 6 is used for development while the ESLint TypeScript plugin supports
249
+ versions below 6.1. Generated declarations use the existing public component API.
250
+
251
+ ## Publish steps
252
+
253
+ `pnpm pub`
254
+
199
255
  ## License
200
256
 
201
257
  MIT
@@ -0,0 +1,29 @@
1
+ export declare const MIN_BASE_Z_INDEX = 20;
2
+ export declare const DEFAULT_BASE_Z_INDEX = 200;
3
+ /** Replace the previous item, stack below it, or disable sticky behavior. */
4
+ export type IStickyMode = 'replace' | 'stack' | 'none';
5
+ export interface IStickyItemMeasurement {
6
+ height: number;
7
+ wrapperHeight: number;
8
+ width: number;
9
+ left: number;
10
+ }
11
+ export interface IStickyItemHandle {
12
+ el: HTMLElement;
13
+ content: HTMLElement;
14
+ mode: Exclude<IStickyMode, 'none'>;
15
+ measure: (rect: DOMRect) => IStickyItemMeasurement;
16
+ invalidate: () => void;
17
+ apply: (layout: (IStickyItemMeasurement & {
18
+ top: number;
19
+ index: number;
20
+ }) | null) => void;
21
+ }
22
+ export interface IStickyGroupContextValue {
23
+ baseZIndex: number;
24
+ register: (handle: IStickyItemHandle) => () => void;
25
+ scheduleUpdate: () => void;
26
+ mode: IStickyMode;
27
+ }
28
+ export declare const StickyGroupContext: import("react").Context<IStickyGroupContextValue | null>;
29
+ export declare function useStickyContext(): IStickyGroupContextValue | null;
@@ -0,0 +1,29 @@
1
+ export declare const MIN_BASE_Z_INDEX = 20;
2
+ export declare const DEFAULT_BASE_Z_INDEX = 200;
3
+ /** Replace the previous item, stack below it, or disable sticky behavior. */
4
+ export type IStickyMode = 'replace' | 'stack' | 'none';
5
+ export interface IStickyItemMeasurement {
6
+ height: number;
7
+ wrapperHeight: number;
8
+ width: number;
9
+ left: number;
10
+ }
11
+ export interface IStickyItemHandle {
12
+ el: HTMLElement;
13
+ content: HTMLElement;
14
+ mode: Exclude<IStickyMode, 'none'>;
15
+ measure: (rect: DOMRect) => IStickyItemMeasurement;
16
+ invalidate: () => void;
17
+ apply: (layout: (IStickyItemMeasurement & {
18
+ top: number;
19
+ index: number;
20
+ }) | null) => void;
21
+ }
22
+ export interface IStickyGroupContextValue {
23
+ baseZIndex: number;
24
+ register: (handle: IStickyItemHandle) => () => void;
25
+ scheduleUpdate: () => void;
26
+ mode: IStickyMode;
27
+ }
28
+ export declare const StickyGroupContext: import("react").Context<IStickyGroupContextValue | null>;
29
+ export declare function useStickyContext(): IStickyGroupContextValue | null;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ export type { IStickyMode } from './context.cjs';
3
+ export * from './sticky-item.cjs';
4
+ export interface IStickyContainerProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ /**
7
+ * The offset from the top of the viewport for sticky elements. Default is 0.
8
+ */
9
+ offsetTop?: number;
10
+ /**
11
+ * base z-index for sticky items. Default is 200. minimum z-index is 20.
12
+ * * - When using the `replace` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` minus its index within the container.
13
+ * * - When using the `stack` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` plus its index.
14
+ * * should be greater than number of sticky items in the container.
15
+ * * use it when you need nest StickyContainer or need to change z-index of sticky items.
16
+ */
17
+ baseZIndex?: number;
18
+ /**
19
+ * Default sticky mode for the group. 'none' disables sticky behavior.
20
+ */
21
+ defaultMode?: 'replace' | 'stack' | 'none';
22
+ /**
23
+ * Callback triggered when the total height of all currently sticky items changes.
24
+ * @param height The total height of all sticky items inside the container.
25
+ */
26
+ onStickyItemsHeightChange?: (height: number) => void;
27
+ /**
28
+ * Define the constraint for sticky behavior
29
+ * - undefined (default): Sticky items will stop being sticky when StickyContainer leaves viewport
30
+ * - 'none': No container boundary; offsets remain viewport-relative
31
+ */
32
+ constraint?: 'none';
33
+ }
34
+ export declare function StickyContainer({ children, offsetTop, baseZIndex, onStickyItemsHeightChange, defaultMode, constraint, className, ...rest }: IStickyContainerProps): React.ReactElement<any, any>;
package/dist/index.d.ts CHANGED
@@ -1,56 +1,34 @@
1
- import { default as default_2 } from 'react';
2
- import { JSX } from 'react/jsx-runtime';
3
-
4
- export declare interface IStickyContainerProps extends default_2.HTMLAttributes<HTMLDivElement> {
5
- children: default_2.ReactNode;
6
- /**
7
- * The offset from the top of the viewport for sticky elements. Default is 0.
8
- */
9
- offsetTop?: number;
10
- /**
11
- * base z-index for sticky items. Default is 200. minimum z-index is 20.
12
- * * - When using the `replace` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` minus its index within the container.
13
- * * - When using the `stack` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` plus its index.
14
- * * should be greater than number of sticky items in the container.
15
- * * for performance reasons, when baseZIndex is changed, the component will not re-render.
16
- * * use it when you need nest StickyContainer or need to change z-index of sticky items.
17
- */
18
- baseZIndex?: number;
19
- /**
20
- * Default sticky mode for the group. 'none' disables sticky behavior.
21
- */
22
- defaultMode?: 'replace' | 'stack' | 'none';
23
- /**
24
- * Callback triggered when the total height of all currently sticky items changes.
25
- * @param height The total height of all sticky items inside the container.
26
- */
27
- onStickyItemsHeightChange?: (height: number) => void;
28
- /**
29
- * Define the constraint for sticky behavior
30
- * - undefined (default): Sticky items will stop being sticky when StickyContainer leaves viewport
31
- * - 'none': No constraints, similar to CSS position:sticky behavior
32
- */
33
- constraint?: 'none';
34
- }
35
-
36
- export declare interface IStickyItemProps extends default_2.HTMLAttributes<HTMLDivElement> {
37
- children: default_2.ReactNode;
38
- /**
39
- * Sticky mode for this item. Defaults to the StickyContainer's mode if not specified.
40
- */
41
- mode?: IStickyMode;
42
- }
43
-
44
- /**
45
- * Sticky mode:
46
- * - 'replace': This item replaces the previous sticky item; its height is set to the previous sticky item's height.
47
- * - 'stack': This item stacks on top of previous sticky items; its height is set to 0.
48
- * - 'none': This item is not sticky.
49
- */
50
- export declare type IStickyMode = 'replace' | 'stack' | 'none';
51
-
52
- export declare function StickyContainer({ children, offsetTop, baseZIndex, onStickyItemsHeightChange, defaultMode, constraint, ...rest }: IStickyContainerProps): JSX.Element;
53
-
54
- export declare function StickyItem({ mode, children, className, ...rest }: IStickyItemProps): JSX.Element;
55
-
56
- export { }
1
+ import React from 'react';
2
+ export type { IStickyMode } from './context.js';
3
+ export * from './sticky-item.js';
4
+ export interface IStickyContainerProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ children: React.ReactNode;
6
+ /**
7
+ * The offset from the top of the viewport for sticky elements. Default is 0.
8
+ */
9
+ offsetTop?: number;
10
+ /**
11
+ * base z-index for sticky items. Default is 200. minimum z-index is 20.
12
+ * * - When using the `replace` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` minus its index within the container.
13
+ * * - When using the `stack` mode, the z-index of a `StickyItem` is calculated as `baseZIndex` plus its index.
14
+ * * should be greater than number of sticky items in the container.
15
+ * * use it when you need nest StickyContainer or need to change z-index of sticky items.
16
+ */
17
+ baseZIndex?: number;
18
+ /**
19
+ * Default sticky mode for the group. 'none' disables sticky behavior.
20
+ */
21
+ defaultMode?: 'replace' | 'stack' | 'none';
22
+ /**
23
+ * Callback triggered when the total height of all currently sticky items changes.
24
+ * @param height The total height of all sticky items inside the container.
25
+ */
26
+ onStickyItemsHeightChange?: (height: number) => void;
27
+ /**
28
+ * Define the constraint for sticky behavior
29
+ * - undefined (default): Sticky items will stop being sticky when StickyContainer leaves viewport
30
+ * - 'none': No container boundary; offsets remain viewport-relative
31
+ */
32
+ constraint?: 'none';
33
+ }
34
+ export declare function StickyContainer({ children, offsetTop, baseZIndex, onStickyItemsHeightChange, defaultMode, constraint, className, ...rest }: IStickyContainerProps): React.ReactElement<any, any>;
@@ -0,0 +1,2 @@
1
+ /** Share observations of ancestors and preceding siblings across all containers. */
2
+ export declare function observeLayoutChanges(container: HTMLElement, callback: () => void): () => void;
@@ -0,0 +1,2 @@
1
+ /** Share observations of ancestors and preceding siblings across all containers. */
2
+ export declare function observeLayoutChanges(container: HTMLElement, callback: () => void): () => void;
@@ -0,0 +1 @@
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("react");c=s(c,1);var l=(0,c.createContext)(null);function u(){return(0,c.useContext)(l)}var d=new Map,f=null;function p(e,t){if(typeof ResizeObserver>`u`)return()=>{};f!=null||(f=new ResizeObserver(e=>{let t=new Map;for(let r of e){var n;for(let e of(n=d.get(r.target))==null?[]:n){let n=t.get(e);n?n.push(r):t.set(e,[r])}}for(let[e,n]of t)e(n)}));let n=d.get(e);return n||(n=new Set,d.set(e,n),f.observe(e)),n.add(t),()=>{n.delete(t),n.size||(d.delete(e),f==null||f.unobserve(e)),d.size||(f==null||f.disconnect(),f=null)}}var m=new Map,h=new Map,g=null,_=!1;function v(){for(let e of m.values())e()}function y(){_||(_=!0,Promise.resolve().then(()=>{_=!1,m.size&&b()}))}function b(){let e=new Set,t=new Set;for(let n of m.keys())for(let r=n;r!=null&&r.parentElement;r=r.parentElement){let n=r.parentElement;e.add(n);for(let t=r.previousElementSibling;t&&!e.has(t);t=t.previousElementSibling)e.add(t);if(t.has(n))break;t.add(n)}let n=[...h.keys()].filter(t=>!e.has(t));n.length&&(g==null||g.disconnect());for(let e of n)h.get(e)(),h.delete(e);for(let t of e){let e=!h.has(t);e&&h.set(t,p(t,v)),(e||n.length)&&(g==null||g.observe(t,{childList:!0,attributes:!0,attributeFilter:[`class`,`style`]}))}}function x(e,t){return m.set(e,t),!g&&typeof MutationObserver<`u`&&(g=new MutationObserver(e=>{e.some(e=>e.type===`childList`)&&y(),v()})),y(),()=>{if(m.delete(e),m.size)y();else{g==null||g.disconnect(),g=null;for(let e of h.values())e();h.clear()}}}var S=new Set,C=new Set,w=null;function T(e){S.has(e)&&(C.add(e),w!=null||(w=requestAnimationFrame(O)))}function E(){for(let e of S)T(e)}function D(){for(let e of S)e.resize(),T(e)}function O(){w=null;let e=[...C];C.clear();let t=[],n=[],r=[];for(let n of e)if(S.has(n))try{let e=n.read();e&&t.push({client:n,write:e})}catch(e){r.push(e)}for(let{client:e,write:i}of t)if(S.has(e))try{let t=i();t&&n.push({client:e,notify:t})}catch(e){r.push(e)}for(let{client:e,notify:t}of n)if(S.has(e))try{t()}catch(e){r.push(e)}if(r.length)throw r[0]}function k(e,t){let n={read:e,resize:t};return S.size||(window.addEventListener(`scroll`,E,{passive:!0,capture:!0}),window.addEventListener(`resize`,D,{passive:!0})),S.add(n),T(n),{schedule:()=>T(n),stop:()=>{S.delete(n),C.delete(n),!C.size&&w!==null&&(cancelAnimationFrame(w),w=null),S.size||(window.removeEventListener(`scroll`,E,!0),window.removeEventListener(`resize`,D))}}}function A({mode:e,children:t,className:n,...r}){var i;let a=u(),o=(0,c.useRef)(null),s=(0,c.useRef)(null),l=a==null?void 0:a.register,d=e==null?a==null?void 0:a.mode:e,f=a==null?void 0:a.baseZIndex,p=(i=r.style)==null?void 0:i.height,m=(0,c.useRef)(null),h=a==null?void 0:a.scheduleUpdate;return(0,c.useEffect)(()=>{let e=o.current,t=s.current;if(!e||!t)return;let n=typeof p==`number`?`${p}px`:p==null?``:p;if(j(e,`height`,n),!l||!d||d===`none`)return;let r=p===void 0||[`auto`,`initial`,`unset`,`revert`,`revert-layer`,`fit-content`,`min-content`,`max-content`].includes(String(p)),i=!1,a=null,c=()=>{if(i){i=!1,a=null,t.classList.remove(`is-sticky`),e.style.height=n;for(let e of[`top`,`left`,`width`,`z-index`])t.style.removeProperty(e)}},u=null,h={el:e,content:t,mode:d,apply:n=>{if(n===null){c();return}let{top:o,wrapperHeight:s,width:l,left:u,index:p}=n;a&&a.top===o&&a.wrapperHeight===s&&a.width===l&&a.left===u&&a.index===p||(a=n,r&&j(e,`height`,`${s}px`),j(t,`top`,`${o}px`),j(t,`left`,`${u}px`),j(t,`width`,`${l}px`),j(t,`zIndex`,`${(f==null?200:f)+(d===`replace`?-p:p)}`),i||(i=!0,t.classList.add(`is-sticky`)))},measure:n=>{u!=null||(u=M(e,t));let r=t.getBoundingClientRect().height;return{height:r,wrapperHeight:r+u.heightInset,width:Math.max(0,n.width-u.widthInset),left:n.left+u.leftInset}},invalidate:()=>{u=null,a=null}};m.current=h;let g=l(h);return()=>{m.current=null,g(),c()}},[l,d,f,p]),(0,c.useEffect)(()=>{var e;(e=m.current)==null||e.invalidate(),h==null||h()}),c.default.createElement(`div`,{...r,className:[`oe-sticky-item`,n].filter(Boolean).join(` `),ref:o},c.default.createElement(`div`,{className:`oe-sticky-content`,ref:s},t))}function j(e,t,n){e.style[t]!==n&&(e.style[t]=n)}function M(e,t){let n=getComputedStyle(e),r=getComputedStyle(t),i=e=>Number.parseFloat(e)||0,a=e=>i(e.paddingLeft)+i(e.paddingRight)+i(e.borderLeftWidth)+i(e.borderRightWidth);return{heightInset:n.boxSizing===`border-box`?i(n.paddingTop)+i(n.paddingBottom)+i(n.borderTopWidth)+i(n.borderBottomWidth):0,widthInset:a(n)+(r.boxSizing===`border-box`?0:a(r)),leftInset:i(n.paddingLeft)+i(n.borderLeftWidth)}}function N({children:e,offsetTop:t=0,baseZIndex:n,onStickyItemsHeightChange:r,defaultMode:i=`replace`,constraint:a,className:o,...s}){let u=(0,c.useRef)(null),d=(0,c.useRef)(new Set),f=(0,c.useRef)(null),m=(0,c.useRef)(new Map),h=(0,c.useRef)(!1),g=(0,c.useRef)(null),_=(0,c.useRef)(new Map),v=(0,c.useRef)(0),y=(0,c.useRef)({offsetTop:t,constraint:a,onStickyItemsHeightChange:r}),b=(0,c.useCallback)(()=>{var e;return(e=g.current)==null?void 0:e.schedule()},[]),S=(0,c.useCallback)(()=>{var e;let t=u.current;if(!t)return;let n=y.current,r=t.getBoundingClientRect();if(!(n.constraint===`none`||r.top<=n.offsetTop&&r.bottom>=n.offsetTop))return()=>{if(h.current){t.classList.remove(`can-sticky`);for(let e of d.current)e.apply(null);h.current=!1}if(v.current!==0)return v.current=0,()=>{var e;return(e=n.onStickyItemsHeightChange)==null?void 0:e.call(n,0)}};let i=((e=f.current)==null?f.current=[...d.current]:e).map(e=>({item:e,rect:e.el.getBoundingClientRect()})).sort((e,t)=>{let n=e.rect.top-t.rect.top;return n===0?e.item.el.compareDocumentPosition(t.item.el)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1:n}),a=n.offsetTop,o=0,s=i.map(({item:e,rect:t},n)=>{var r;if(t.top>a)return null;let s=(r=i[n+1])==null?void 0:r.rect.top;if(e.mode===`replace`&&s!==void 0&&s<a)return null;let c=e.measure(t),l=e.mode===`replace`&&s!==void 0?Math.min(a,s-c.height):a;return o+=c.height,e.mode===`stack`&&(a+=c.height),{...c,top:l,index:n}}),c=n.constraint===`none`?0:Math.min(0,r.bottom-n.offsetTop-o);return()=>{if(h.current=s.some(e=>e!==null),t.classList.toggle(`can-sticky`,h.current),i.forEach(({item:e},t)=>{let n=s[t];n&&(n.top+=c),e.apply(n)}),v.current!==o)return v.current=o,()=>{var e;return(e=n.onStickyItemsHeightChange)==null?void 0:e.call(n,o)}}},[]),C=(0,c.useCallback)(e=>{var t;for(let n of e)(t=m.current.get(n.target))==null||t.invalidate();b()},[b]),w=(0,c.useCallback)(()=>{for(let e of d.current)e.invalidate()},[]),T=(0,c.useCallback)(e=>(d.current.add(e),f.current=null,m.current.set(e.el,e),m.current.set(e.content,e),g.current&&(_.current.set(e.el,p(e.el,C)),_.current.set(e.content,p(e.content,C))),b(),()=>{var t,n;(t=_.current.get(e.el))==null||t(),(n=_.current.get(e.content))==null||n(),_.current.delete(e.el),_.current.delete(e.content),m.current.delete(e.el),m.current.delete(e.content),d.current.delete(e),f.current=null,b()}),[b,C]);(0,c.useEffect)(()=>{g.current=k(S,w);let e;if(typeof ResizeObserver<`u`){u.current&&(_.current.set(u.current,p(u.current,C)),e=x(u.current,()=>{w(),b()}));for(let e of d.current)_.current.set(e.el,p(e.el,C)),_.current.set(e.content,p(e.content,C))}let t=_.current;return()=>{var n;(n=g.current)==null||n.stop(),g.current=null,e==null||e();for(let e of t.values())e();t.clear()}},[S,w,b,C]),(0,c.useEffect)(()=>{y.current={offsetTop:t,constraint:a,onStickyItemsHeightChange:r};for(let e of d.current)e.invalidate();b()});let E=n===void 0?200:Math.max(Number(n)||0,20),D=(0,c.useMemo)(()=>({register:T,scheduleUpdate:b,baseZIndex:E,mode:i}),[T,b,E,i]);return c.default.createElement(l.Provider,{value:D},c.default.createElement(`div`,{...s,ref:u,className:[`oe-sticky-container`,o].filter(Boolean).join(` `)},e))}exports.StickyContainer=N,exports.StickyItem=A;
@@ -1,157 +1,329 @@
1
- import { jsx as w } from "react/jsx-runtime";
2
- import { createContext as Z, useContext as L, useRef as k, useState as T, useEffect as E, useCallback as v, useMemo as _ } from "react";
3
- const O = 20, A = 200, $ = Z(null);
4
- function z() {
5
- return L($);
1
+ "use client";
2
+ import e, { createContext as t, useCallback as n, useContext as r, useEffect as i, useMemo as a, useRef as o } from "react";
3
+ //#region src/context.ts
4
+ var s = t(null);
5
+ function c() {
6
+ return r(s);
6
7
  }
7
- function M({ mode: f, children: y, className: h, ...I }) {
8
- const e = z(), g = k(null), S = k(null), [m, o] = T(!1), l = k({
9
- fixedOffsetTop: (e == null ? void 0 : e.fixedOffsetTop) || 0,
10
- isSticky: m,
11
- baseZIndex: (e == null ? void 0 : e.baseZIndex) || O
12
- });
13
- return l.current.baseZIndex = (e == null ? void 0 : e.baseZIndex) || O, l.current.fixedOffsetTop = (e == null ? void 0 : e.fixedOffsetTop) || 0, l.current.isSticky = m, E(() => {
14
- const t = S.current, a = g.current, n = f || (e == null ? void 0 : e.mode);
15
- if (!e || !a || !t || n === "none" || !n || !e.register) {
16
- o(!1);
17
- return;
18
- }
19
- const x = {
20
- el: a,
21
- update: (B, c, s, r, u) => {
22
- if (!B || c > s)
23
- return l.current.isSticky && o(!1), 0;
24
- const i = t.getBoundingClientRect().height;
25
- let p = s;
26
- if (n === "replace" && typeof r < "u") {
27
- const d = r - (s + i);
28
- if (d < 0 && (p = s + d, d + i < 0))
29
- return l.current.isSticky && o(!1), 0;
30
- }
31
- return a.style.height = `${i}px`, l.current.isSticky || o(!0), t.style.top = `${p}px`, t.style.width = `${a.offsetWidth}px`, t.style.zIndex = `${l.current.baseZIndex + (n === "replace" ? -u : u)}`, n === "replace" ? 0 : i;
32
- }
33
- };
34
- return e.register(x);
35
- }, [e == null ? void 0 : e.mode, e == null ? void 0 : e.register, f]), E(() => {
36
- const t = g.current, a = S.current, n = e == null ? void 0 : e.updateStickyItemsHeight;
37
- if (!m || !t || !a || !n)
38
- return;
39
- const H = n(a.getBoundingClientRect().height);
40
- return () => {
41
- N(t, ["height"]), N(a, ["top", "z-index", "width"]), H();
42
- };
43
- }, [m, e == null ? void 0 : e.updateStickyItemsHeight]), /* @__PURE__ */ w("div", { className: "oe-sticky-item " + (h || ""), ...I, ref: g, children: /* @__PURE__ */ w("div", { className: "oe-sticky-content " + (m ? "is-sticky" : ""), ref: S, children: y }) });
8
+ //#endregion
9
+ //#region src/resize-observer.ts
10
+ var l = /* @__PURE__ */ new Map(), u = null;
11
+ function d(e, t) {
12
+ if (typeof ResizeObserver > "u") return () => {};
13
+ u != null || (u = new ResizeObserver((e) => {
14
+ let t = /* @__PURE__ */ new Map();
15
+ for (let r of e) {
16
+ var n;
17
+ for (let e of (n = l.get(r.target)) == null ? [] : n) {
18
+ let n = t.get(e);
19
+ n ? n.push(r) : t.set(e, [r]);
20
+ }
21
+ }
22
+ for (let [e, n] of t) e(n);
23
+ }));
24
+ let n = l.get(e);
25
+ return n || (n = /* @__PURE__ */ new Set(), l.set(e, n), u.observe(e)), n.add(t), () => {
26
+ n.delete(t), n.size || (l.delete(e), u == null || u.unobserve(e)), l.size || (u == null || u.disconnect(), u = null);
27
+ };
44
28
  }
45
- function N(f, y) {
46
- y.forEach((h) => {
47
- f.style.removeProperty(h);
48
- });
29
+ //#endregion
30
+ //#region src/layout-observer.ts
31
+ var f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = null, h = !1;
32
+ function g() {
33
+ for (let e of f.values()) e();
49
34
  }
50
- function P({
51
- children: f,
52
- offsetTop: y = 0,
53
- baseZIndex: h,
54
- onStickyItemsHeightChange: I,
55
- defaultMode: e = "replace",
56
- constraint: g,
57
- ...S
58
- }) {
59
- const m = k(null), o = k([]), l = k(null), t = k({
60
- fixedOffsetTop: y,
61
- defaultMode: e,
62
- stickyItemsHeight: 0,
63
- onStickyItemsHeightChange: I,
64
- lastCanSticky: !1
65
- });
66
- t.current.onStickyItemsHeightChange = I;
67
- const a = v(() => {
68
- var c;
69
- return g === "none" ? {
70
- top: -1 / 0,
71
- bottom: 1 / 0,
72
- left: -1 / 0,
73
- right: 1 / 0,
74
- width: 1 / 0,
75
- height: 1 / 0,
76
- x: 0,
77
- y: 0,
78
- toJSON: () => ({})
79
- } : ((c = m.current) == null ? void 0 : c.getBoundingClientRect()) || { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0, x: 0, y: 0, toJSON: () => ({}) };
80
- }, [g]), n = v(() => {
81
- const c = m.current;
82
- !c || l.current || (l.current = requestAnimationFrame(() => {
83
- l.current = null;
84
- const s = a(), { fixedOffsetTop: r, stickyItemsHeight: u } = t.current;
85
- let i;
86
- if (g === "none" ? i = !0 : i = !(s.top > r || s.bottom < r), !i) {
87
- t.current.lastCanSticky !== i && (c.classList.toggle("can-sticky", !1), o.current.forEach((C) => C.update(!1, 0, 0, 0, 0)), t.current.lastCanSticky = i);
88
- return;
89
- }
90
- t.current.lastCanSticky = i, u > 0 && c.classList.toggle("can-sticky", !0);
91
- let p, d = 0;
92
- p = r, d = s.bottom - (r + u), d > 0 && (d = 0);
93
- const b = o.current.map((C) => C.el.getBoundingClientRect().top);
94
- o.current.forEach((C, R) => {
95
- p += C.update(i, b[R], p + d, b[R + 1], R);
96
- });
97
- }));
98
- }, [a, g]), H = v((c) => {
99
- const s = t.current.stickyItemsHeight + c;
100
- return t.current.stickyItemsHeight = s, setTimeout(() => {
101
- var r, u;
102
- (u = (r = t.current).onStickyItemsHeightChange) == null || u.call(r, s);
103
- }, 0), () => {
104
- const r = t.current.stickyItemsHeight - c;
105
- t.current.stickyItemsHeight = r, setTimeout(() => {
106
- var u, i;
107
- (i = (u = t.current).onStickyItemsHeightChange) == null || i.call(u, r);
108
- }, 0);
109
- };
110
- }, []);
111
- E(() => {
112
- t.current.fixedOffsetTop = y, t.current.defaultMode = e, setTimeout(() => {
113
- n();
114
- }, 10);
115
- }, [y, e, n]);
116
- const x = v((c) => (o.current.push(c), o.current = W(o.current), n(), () => {
117
- o.current = o.current.filter((s) => s !== c), n();
118
- }), [n]);
119
- E(() => (window.addEventListener("scroll", n, { passive: !0 }), window.addEventListener("resize", n, { passive: !0 }), () => {
120
- window.removeEventListener("scroll", n), window.removeEventListener("resize", n);
121
- }), [n]);
122
- const B = _(() => D(h), [h]);
123
- return /* @__PURE__ */ w(
124
- $.Provider,
125
- {
126
- value: {
127
- register: x,
128
- baseZIndex: B,
129
- updateStickyItemsHeight: H,
130
- fixedOffsetTop: y,
131
- mode: e
132
- },
133
- children: /* @__PURE__ */ w(
134
- "div",
135
- {
136
- ...S,
137
- ref: m,
138
- className: "oe-sticky-container",
139
- children: f
140
- }
141
- )
142
- }
143
- );
35
+ function _() {
36
+ h || (h = !0, Promise.resolve().then(() => {
37
+ h = !1, f.size && v();
38
+ }));
144
39
  }
145
- function D(f) {
146
- return typeof f > "u" ? A : Math.max(Number(f) || 0, O);
40
+ function v() {
41
+ let e = /* @__PURE__ */ new Set(), t = /* @__PURE__ */ new Set();
42
+ for (let n of f.keys()) for (let r = n; r != null && r.parentElement; r = r.parentElement) {
43
+ let n = r.parentElement;
44
+ e.add(n);
45
+ for (let t = r.previousElementSibling; t && !e.has(t); t = t.previousElementSibling) e.add(t);
46
+ if (t.has(n)) break;
47
+ t.add(n);
48
+ }
49
+ let n = [...p.keys()].filter((t) => !e.has(t));
50
+ n.length && (m == null || m.disconnect());
51
+ for (let e of n) p.get(e)(), p.delete(e);
52
+ for (let t of e) {
53
+ let e = !p.has(t);
54
+ e && p.set(t, d(t, g)), (e || n.length) && (m == null || m.observe(t, {
55
+ childList: !0,
56
+ attributes: !0,
57
+ attributeFilter: ["class", "style"]
58
+ }));
59
+ }
147
60
  }
148
- function W(f) {
149
- return f.sort((y, h) => {
150
- const I = y.el.getBoundingClientRect(), e = h.el.getBoundingClientRect();
151
- return I.top - e.top;
152
- });
61
+ function y(e, t) {
62
+ return f.set(e, t), !m && typeof MutationObserver < "u" && (m = new MutationObserver((e) => {
63
+ e.some((e) => e.type === "childList") && _(), g();
64
+ })), _(), () => {
65
+ if (f.delete(e), f.size) _();
66
+ else {
67
+ m == null || m.disconnect(), m = null;
68
+ for (let e of p.values()) e();
69
+ p.clear();
70
+ }
71
+ };
153
72
  }
154
- export {
155
- P as StickyContainer,
156
- M as StickyItem
157
- };
73
+ //#endregion
74
+ //#region src/scheduler.ts
75
+ var b = /* @__PURE__ */ new Set(), x = /* @__PURE__ */ new Set(), S = null;
76
+ function C(e) {
77
+ b.has(e) && (x.add(e), S != null || (S = requestAnimationFrame(E)));
78
+ }
79
+ function w() {
80
+ for (let e of b) C(e);
81
+ }
82
+ function T() {
83
+ for (let e of b) e.resize(), C(e);
84
+ }
85
+ function E() {
86
+ S = null;
87
+ let e = [...x];
88
+ x.clear();
89
+ let t = [], n = [], r = [];
90
+ for (let n of e) if (b.has(n)) try {
91
+ let e = n.read();
92
+ e && t.push({
93
+ client: n,
94
+ write: e
95
+ });
96
+ } catch (e) {
97
+ r.push(e);
98
+ }
99
+ for (let { client: e, write: i } of t) if (b.has(e)) try {
100
+ let t = i();
101
+ t && n.push({
102
+ client: e,
103
+ notify: t
104
+ });
105
+ } catch (e) {
106
+ r.push(e);
107
+ }
108
+ for (let { client: e, notify: t } of n) if (b.has(e)) try {
109
+ t();
110
+ } catch (e) {
111
+ r.push(e);
112
+ }
113
+ if (r.length) throw r[0];
114
+ }
115
+ function D(e, t) {
116
+ let n = {
117
+ read: e,
118
+ resize: t
119
+ };
120
+ return b.size || (window.addEventListener("scroll", w, {
121
+ passive: !0,
122
+ capture: !0
123
+ }), window.addEventListener("resize", T, { passive: !0 })), b.add(n), C(n), {
124
+ schedule: () => C(n),
125
+ stop: () => {
126
+ b.delete(n), x.delete(n), !x.size && S !== null && (cancelAnimationFrame(S), S = null), b.size || (window.removeEventListener("scroll", w, !0), window.removeEventListener("resize", T));
127
+ }
128
+ };
129
+ }
130
+ //#endregion
131
+ //#region src/sticky-item.tsx
132
+ function O({ mode: t, children: n, className: r, ...a }) {
133
+ var s;
134
+ let l = c(), u = o(null), d = o(null), f = l == null ? void 0 : l.register, p = t == null ? l == null ? void 0 : l.mode : t, m = l == null ? void 0 : l.baseZIndex, h = (s = a.style) == null ? void 0 : s.height, g = o(null), _ = l == null ? void 0 : l.scheduleUpdate;
135
+ return i(() => {
136
+ let e = u.current, t = d.current;
137
+ if (!e || !t) return;
138
+ let n = typeof h == "number" ? `${h}px` : h == null ? "" : h;
139
+ if (k(e, "height", n), !f || !p || p === "none") return;
140
+ let r = h === void 0 || [
141
+ "auto",
142
+ "initial",
143
+ "unset",
144
+ "revert",
145
+ "revert-layer",
146
+ "fit-content",
147
+ "min-content",
148
+ "max-content"
149
+ ].includes(String(h)), i = !1, a = null, o = () => {
150
+ if (i) {
151
+ i = !1, a = null, t.classList.remove("is-sticky"), e.style.height = n;
152
+ for (let e of [
153
+ "top",
154
+ "left",
155
+ "width",
156
+ "z-index"
157
+ ]) t.style.removeProperty(e);
158
+ }
159
+ }, s = null, c = {
160
+ el: e,
161
+ content: t,
162
+ mode: p,
163
+ apply: (n) => {
164
+ if (n === null) {
165
+ o();
166
+ return;
167
+ }
168
+ let { top: s, wrapperHeight: c, width: l, left: u, index: d } = n;
169
+ a && a.top === s && a.wrapperHeight === c && a.width === l && a.left === u && a.index === d || (a = n, r && k(e, "height", `${c}px`), k(t, "top", `${s}px`), k(t, "left", `${u}px`), k(t, "width", `${l}px`), k(t, "zIndex", `${(m == null ? 200 : m) + (p === "replace" ? -d : d)}`), i || (i = !0, t.classList.add("is-sticky")));
170
+ },
171
+ measure: (n) => {
172
+ s != null || (s = A(e, t));
173
+ let r = t.getBoundingClientRect().height;
174
+ return {
175
+ height: r,
176
+ wrapperHeight: r + s.heightInset,
177
+ width: Math.max(0, n.width - s.widthInset),
178
+ left: n.left + s.leftInset
179
+ };
180
+ },
181
+ invalidate: () => {
182
+ s = null, a = null;
183
+ }
184
+ };
185
+ g.current = c;
186
+ let l = f(c);
187
+ return () => {
188
+ g.current = null, l(), o();
189
+ };
190
+ }, [
191
+ f,
192
+ p,
193
+ m,
194
+ h
195
+ ]), i(() => {
196
+ var e;
197
+ (e = g.current) == null || e.invalidate(), _ == null || _();
198
+ }), /* @__PURE__ */ e.createElement("div", {
199
+ ...a,
200
+ className: ["oe-sticky-item", r].filter(Boolean).join(" "),
201
+ ref: u
202
+ }, /* @__PURE__ */ e.createElement("div", {
203
+ className: "oe-sticky-content",
204
+ ref: d
205
+ }, n));
206
+ }
207
+ function k(e, t, n) {
208
+ e.style[t] !== n && (e.style[t] = n);
209
+ }
210
+ function A(e, t) {
211
+ let n = getComputedStyle(e), r = getComputedStyle(t), i = (e) => Number.parseFloat(e) || 0, a = (e) => i(e.paddingLeft) + i(e.paddingRight) + i(e.borderLeftWidth) + i(e.borderRightWidth);
212
+ return {
213
+ heightInset: n.boxSizing === "border-box" ? i(n.paddingTop) + i(n.paddingBottom) + i(n.borderTopWidth) + i(n.borderBottomWidth) : 0,
214
+ widthInset: a(n) + (r.boxSizing === "border-box" ? 0 : a(r)),
215
+ leftInset: i(n.paddingLeft) + i(n.borderLeftWidth)
216
+ };
217
+ }
218
+ //#endregion
219
+ //#region src/index.tsx
220
+ function j({ children: t, offsetTop: r = 0, baseZIndex: c, onStickyItemsHeightChange: l, defaultMode: u = "replace", constraint: f, className: p, ...m }) {
221
+ let h = o(null), g = o(/* @__PURE__ */ new Set()), _ = o(null), v = o(/* @__PURE__ */ new Map()), b = o(!1), x = o(null), S = o(/* @__PURE__ */ new Map()), C = o(0), w = o({
222
+ offsetTop: r,
223
+ constraint: f,
224
+ onStickyItemsHeightChange: l
225
+ }), T = n(() => {
226
+ var e;
227
+ return (e = x.current) == null ? void 0 : e.schedule();
228
+ }, []), E = n(() => {
229
+ var e;
230
+ let t = h.current;
231
+ if (!t) return;
232
+ let n = w.current, r = t.getBoundingClientRect();
233
+ if (!(n.constraint === "none" || r.top <= n.offsetTop && r.bottom >= n.offsetTop)) return () => {
234
+ if (b.current) {
235
+ t.classList.remove("can-sticky");
236
+ for (let e of g.current) e.apply(null);
237
+ b.current = !1;
238
+ }
239
+ if (C.current !== 0) return C.current = 0, () => {
240
+ var e;
241
+ return (e = n.onStickyItemsHeightChange) == null ? void 0 : e.call(n, 0);
242
+ };
243
+ };
244
+ let i = ((e = _.current) == null ? _.current = [...g.current] : e).map((e) => ({
245
+ item: e,
246
+ rect: e.el.getBoundingClientRect()
247
+ })).sort((e, t) => {
248
+ let n = e.rect.top - t.rect.top;
249
+ return n === 0 ? e.item.el.compareDocumentPosition(t.item.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1 : n;
250
+ }), a = n.offsetTop, o = 0, s = i.map(({ item: e, rect: t }, n) => {
251
+ var r;
252
+ if (t.top > a) return null;
253
+ let s = (r = i[n + 1]) == null ? void 0 : r.rect.top;
254
+ if (e.mode === "replace" && s !== void 0 && s < a) return null;
255
+ let c = e.measure(t), l = e.mode === "replace" && s !== void 0 ? Math.min(a, s - c.height) : a;
256
+ return o += c.height, e.mode === "stack" && (a += c.height), {
257
+ ...c,
258
+ top: l,
259
+ index: n
260
+ };
261
+ }), c = n.constraint === "none" ? 0 : Math.min(0, r.bottom - n.offsetTop - o);
262
+ return () => {
263
+ if (b.current = s.some((e) => e !== null), t.classList.toggle("can-sticky", b.current), i.forEach(({ item: e }, t) => {
264
+ let n = s[t];
265
+ n && (n.top += c), e.apply(n);
266
+ }), C.current !== o) return C.current = o, () => {
267
+ var e;
268
+ return (e = n.onStickyItemsHeightChange) == null ? void 0 : e.call(n, o);
269
+ };
270
+ };
271
+ }, []), O = n((e) => {
272
+ var t;
273
+ for (let n of e) (t = v.current.get(n.target)) == null || t.invalidate();
274
+ T();
275
+ }, [T]), k = n(() => {
276
+ for (let e of g.current) e.invalidate();
277
+ }, []), A = n((e) => (g.current.add(e), _.current = null, v.current.set(e.el, e), v.current.set(e.content, e), x.current && (S.current.set(e.el, d(e.el, O)), S.current.set(e.content, d(e.content, O))), T(), () => {
278
+ var t, n;
279
+ (t = S.current.get(e.el)) == null || t(), (n = S.current.get(e.content)) == null || n(), S.current.delete(e.el), S.current.delete(e.content), v.current.delete(e.el), v.current.delete(e.content), g.current.delete(e), _.current = null, T();
280
+ }), [T, O]);
281
+ i(() => {
282
+ x.current = D(E, k);
283
+ let e;
284
+ if (typeof ResizeObserver < "u") {
285
+ h.current && (S.current.set(h.current, d(h.current, O)), e = y(h.current, () => {
286
+ k(), T();
287
+ }));
288
+ for (let e of g.current) S.current.set(e.el, d(e.el, O)), S.current.set(e.content, d(e.content, O));
289
+ }
290
+ let t = S.current;
291
+ return () => {
292
+ var n;
293
+ (n = x.current) == null || n.stop(), x.current = null, e == null || e();
294
+ for (let e of t.values()) e();
295
+ t.clear();
296
+ };
297
+ }, [
298
+ E,
299
+ k,
300
+ T,
301
+ O
302
+ ]), i(() => {
303
+ w.current = {
304
+ offsetTop: r,
305
+ constraint: f,
306
+ onStickyItemsHeightChange: l
307
+ };
308
+ for (let e of g.current) e.invalidate();
309
+ T();
310
+ });
311
+ let j = c === void 0 ? 200 : Math.max(Number(c) || 0, 20), M = a(() => ({
312
+ register: A,
313
+ scheduleUpdate: T,
314
+ baseZIndex: j,
315
+ mode: u
316
+ }), [
317
+ A,
318
+ T,
319
+ j,
320
+ u
321
+ ]);
322
+ return /* @__PURE__ */ e.createElement(s.Provider, { value: M }, /* @__PURE__ */ e.createElement("div", {
323
+ ...m,
324
+ ref: h,
325
+ className: ["oe-sticky-container", p].filter(Boolean).join(" ")
326
+ }, t));
327
+ }
328
+ //#endregion
329
+ export { j as StickyContainer, O as StickyItem };
@@ -1 +1 @@
1
- (function(g,I){typeof exports=="object"&&typeof module<"u"?I(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],I):(g=typeof globalThis<"u"?globalThis:g||self,I(g.ReactSticky={},g.jsxRuntime,g.React))})(this,function(g,I,n){"use strict";const N=n.createContext(null);function w(){return n.useContext(N)}const L="";function O({mode:l,children:h,className:k,...E}){const e=w(),m=n.useRef(null),C=n.useRef(null),[p,o]=n.useState(!1),d=n.useRef({fixedOffsetTop:(e==null?void 0:e.fixedOffsetTop)||0,isSticky:p,baseZIndex:(e==null?void 0:e.baseZIndex)||20});return d.current.baseZIndex=(e==null?void 0:e.baseZIndex)||20,d.current.fixedOffsetTop=(e==null?void 0:e.fixedOffsetTop)||0,d.current.isSticky=p,n.useEffect(()=>{const t=C.current,a=m.current,i=l||(e==null?void 0:e.mode);if(!e||!a||!t||i==="none"||!i||!e.register){o(!1);return}const v={el:a,update:(B,c,u,r,f)=>{if(!B||c>u)return d.current.isSticky&&o(!1),0;const s=t.getBoundingClientRect().height;let S=u;if(i==="replace"&&typeof r<"u"){const y=r-(u+s);if(y<0&&(S=u+y,y+s<0))return d.current.isSticky&&o(!1),0}return a.style.height=`${s}px`,d.current.isSticky||o(!0),t.style.top=`${S}px`,t.style.width=`${a.offsetWidth}px`,t.style.zIndex=`${d.current.baseZIndex+(i==="replace"?-f:f)}`,i==="replace"?0:s}};return e.register(v)},[e==null?void 0:e.mode,e==null?void 0:e.register,l]),n.useEffect(()=>{const t=m.current,a=C.current,i=e==null?void 0:e.updateStickyItemsHeight;if(!p||!t||!a||!i)return;const _=i(a.getBoundingClientRect().height);return()=>{b(t,["height"]),b(a,["top","z-index","width"]),_()}},[p,e==null?void 0:e.updateStickyItemsHeight]),I.jsx("div",{className:"oe-sticky-item "+(k||""),...E,ref:m,children:I.jsx("div",{className:"oe-sticky-content "+(p?"is-sticky":""),ref:C,children:h})})}function b(l,h){h.forEach(k=>{l.style.removeProperty(k)})}function Z({children:l,offsetTop:h=0,baseZIndex:k,onStickyItemsHeightChange:E,defaultMode:e="replace",constraint:m,...C}){const p=n.useRef(null),o=n.useRef([]),d=n.useRef(null),t=n.useRef({fixedOffsetTop:h,defaultMode:e,stickyItemsHeight:0,onStickyItemsHeightChange:E,lastCanSticky:!1});t.current.onStickyItemsHeightChange=E;const a=n.useCallback(()=>{var c;return m==="none"?{top:-1/0,bottom:1/0,left:-1/0,right:1/0,width:1/0,height:1/0,x:0,y:0,toJSON:()=>({})}:((c=p.current)==null?void 0:c.getBoundingClientRect())||{top:0,bottom:0,left:0,right:0,width:0,height:0,x:0,y:0,toJSON:()=>({})}},[m]),i=n.useCallback(()=>{const c=p.current;!c||d.current||(d.current=requestAnimationFrame(()=>{d.current=null;const u=a(),{fixedOffsetTop:r,stickyItemsHeight:f}=t.current;let s;if(m==="none"?s=!0:s=!(u.top>r||u.bottom<r),!s){t.current.lastCanSticky!==s&&(c.classList.toggle("can-sticky",!1),o.current.forEach(R=>R.update(!1,0,0,0,0)),t.current.lastCanSticky=s);return}t.current.lastCanSticky=s,f>0&&c.classList.toggle("can-sticky",!0);let S,y=0;S=r,y=u.bottom-(r+f),y>0&&(y=0);const x=o.current.map(R=>R.el.getBoundingClientRect().top);o.current.forEach((R,H)=>{S+=R.update(s,x[H],S+y,x[H+1],H)})}))},[a,m]),_=n.useCallback(c=>{const u=t.current.stickyItemsHeight+c;return t.current.stickyItemsHeight=u,setTimeout(()=>{var r,f;(f=(r=t.current).onStickyItemsHeightChange)==null||f.call(r,u)},0),()=>{const r=t.current.stickyItemsHeight-c;t.current.stickyItemsHeight=r,setTimeout(()=>{var f,s;(s=(f=t.current).onStickyItemsHeightChange)==null||s.call(f,r)},0)}},[]);n.useEffect(()=>{t.current.fixedOffsetTop=h,t.current.defaultMode=e,setTimeout(()=>{i()},10)},[h,e,i]);const v=n.useCallback(c=>(o.current.push(c),o.current=A(o.current),i(),()=>{o.current=o.current.filter(u=>u!==c),i()}),[i]);n.useEffect(()=>(window.addEventListener("scroll",i,{passive:!0}),window.addEventListener("resize",i,{passive:!0}),()=>{window.removeEventListener("scroll",i),window.removeEventListener("resize",i)}),[i]);const B=n.useMemo(()=>T(k),[k]);return I.jsx(N.Provider,{value:{register:v,baseZIndex:B,updateStickyItemsHeight:_,fixedOffsetTop:h,mode:e},children:I.jsx("div",{...C,ref:p,className:"oe-sticky-container",children:l})})}function T(l){return typeof l>"u"?200:Math.max(Number(l)||0,20)}function A(l){return l.sort((h,k)=>{const E=h.el.getBoundingClientRect(),e=k.el.getBoundingClientRect();return E.top-e.top})}g.StickyContainer=Z,g.StickyItem=O,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
1
+ "use client";(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.ReactSticky={},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||!s.call(e,`default`)?r(i,`default`,{value:e,enumerable:!0}):i,e)))(t,1);var l=(0,t.createContext)(null);function u(){return(0,t.useContext)(l)}var d=new Map,f=null;function p(e,t){if(typeof ResizeObserver>`u`)return()=>{};f!=null||(f=new ResizeObserver(e=>{let t=new Map;for(let r of e){var n;for(let e of(n=d.get(r.target))==null?[]:n){let n=t.get(e);n?n.push(r):t.set(e,[r])}}for(let[e,n]of t)e(n)}));let n=d.get(e);return n||(n=new Set,d.set(e,n),f.observe(e)),n.add(t),()=>{n.delete(t),n.size||(d.delete(e),f==null||f.unobserve(e)),d.size||(f==null||f.disconnect(),f=null)}}var m=new Map,h=new Map,g=null,_=!1;function v(){for(let e of m.values())e()}function y(){_||(_=!0,Promise.resolve().then(()=>{_=!1,m.size&&b()}))}function b(){let e=new Set,t=new Set;for(let n of m.keys())for(let r=n;r!=null&&r.parentElement;r=r.parentElement){let n=r.parentElement;e.add(n);for(let t=r.previousElementSibling;t&&!e.has(t);t=t.previousElementSibling)e.add(t);if(t.has(n))break;t.add(n)}let n=[...h.keys()].filter(t=>!e.has(t));n.length&&(g==null||g.disconnect());for(let e of n)h.get(e)(),h.delete(e);for(let t of e){let e=!h.has(t);e&&h.set(t,p(t,v)),(e||n.length)&&(g==null||g.observe(t,{childList:!0,attributes:!0,attributeFilter:[`class`,`style`]}))}}function x(e,t){return m.set(e,t),!g&&typeof MutationObserver<`u`&&(g=new MutationObserver(e=>{e.some(e=>e.type===`childList`)&&y(),v()})),y(),()=>{if(m.delete(e),m.size)y();else{g==null||g.disconnect(),g=null;for(let e of h.values())e();h.clear()}}}var S=new Set,C=new Set,w=null;function T(e){S.has(e)&&(C.add(e),w!=null||(w=requestAnimationFrame(O)))}function E(){for(let e of S)T(e)}function D(){for(let e of S)e.resize(),T(e)}function O(){w=null;let e=[...C];C.clear();let t=[],n=[],r=[];for(let n of e)if(S.has(n))try{let e=n.read();e&&t.push({client:n,write:e})}catch(e){r.push(e)}for(let{client:e,write:i}of t)if(S.has(e))try{let t=i();t&&n.push({client:e,notify:t})}catch(e){r.push(e)}for(let{client:e,notify:t}of n)if(S.has(e))try{t()}catch(e){r.push(e)}if(r.length)throw r[0]}function k(e,t){let n={read:e,resize:t};return S.size||(window.addEventListener(`scroll`,E,{passive:!0,capture:!0}),window.addEventListener(`resize`,D,{passive:!0})),S.add(n),T(n),{schedule:()=>T(n),stop:()=>{S.delete(n),C.delete(n),!C.size&&w!==null&&(cancelAnimationFrame(w),w=null),S.size||(window.removeEventListener(`scroll`,E,!0),window.removeEventListener(`resize`,D))}}}function A({mode:e,children:n,className:r,...i}){var a;let o=u(),s=(0,t.useRef)(null),c=(0,t.useRef)(null),l=o==null?void 0:o.register,d=e==null?o==null?void 0:o.mode:e,f=o==null?void 0:o.baseZIndex,p=(a=i.style)==null?void 0:a.height,m=(0,t.useRef)(null),h=o==null?void 0:o.scheduleUpdate;return(0,t.useEffect)(()=>{let e=s.current,t=c.current;if(!e||!t)return;let n=typeof p==`number`?`${p}px`:p==null?``:p;if(j(e,`height`,n),!l||!d||d===`none`)return;let r=p===void 0||[`auto`,`initial`,`unset`,`revert`,`revert-layer`,`fit-content`,`min-content`,`max-content`].includes(String(p)),i=!1,a=null,o=()=>{if(i){i=!1,a=null,t.classList.remove(`is-sticky`),e.style.height=n;for(let e of[`top`,`left`,`width`,`z-index`])t.style.removeProperty(e)}},u=null,h={el:e,content:t,mode:d,apply:n=>{if(n===null){o();return}let{top:s,wrapperHeight:c,width:l,left:u,index:p}=n;a&&a.top===s&&a.wrapperHeight===c&&a.width===l&&a.left===u&&a.index===p||(a=n,r&&j(e,`height`,`${c}px`),j(t,`top`,`${s}px`),j(t,`left`,`${u}px`),j(t,`width`,`${l}px`),j(t,`zIndex`,`${(f==null?200:f)+(d===`replace`?-p:p)}`),i||(i=!0,t.classList.add(`is-sticky`)))},measure:n=>{u!=null||(u=M(e,t));let r=t.getBoundingClientRect().height;return{height:r,wrapperHeight:r+u.heightInset,width:Math.max(0,n.width-u.widthInset),left:n.left+u.leftInset}},invalidate:()=>{u=null,a=null}};m.current=h;let g=l(h);return()=>{m.current=null,g(),o()}},[l,d,f,p]),(0,t.useEffect)(()=>{var e;(e=m.current)==null||e.invalidate(),h==null||h()}),t.default.createElement(`div`,{...i,className:[`oe-sticky-item`,r].filter(Boolean).join(` `),ref:s},t.default.createElement(`div`,{className:`oe-sticky-content`,ref:c},n))}function j(e,t,n){e.style[t]!==n&&(e.style[t]=n)}function M(e,t){let n=getComputedStyle(e),r=getComputedStyle(t),i=e=>Number.parseFloat(e)||0,a=e=>i(e.paddingLeft)+i(e.paddingRight)+i(e.borderLeftWidth)+i(e.borderRightWidth);return{heightInset:n.boxSizing===`border-box`?i(n.paddingTop)+i(n.paddingBottom)+i(n.borderTopWidth)+i(n.borderBottomWidth):0,widthInset:a(n)+(r.boxSizing===`border-box`?0:a(r)),leftInset:i(n.paddingLeft)+i(n.borderLeftWidth)}}function N({children:e,offsetTop:n=0,baseZIndex:r,onStickyItemsHeightChange:i,defaultMode:a=`replace`,constraint:o,className:s,...c}){let u=(0,t.useRef)(null),d=(0,t.useRef)(new Set),f=(0,t.useRef)(null),m=(0,t.useRef)(new Map),h=(0,t.useRef)(!1),g=(0,t.useRef)(null),_=(0,t.useRef)(new Map),v=(0,t.useRef)(0),y=(0,t.useRef)({offsetTop:n,constraint:o,onStickyItemsHeightChange:i}),b=(0,t.useCallback)(()=>{var e;return(e=g.current)==null?void 0:e.schedule()},[]),S=(0,t.useCallback)(()=>{var e;let t=u.current;if(!t)return;let n=y.current,r=t.getBoundingClientRect();if(!(n.constraint===`none`||r.top<=n.offsetTop&&r.bottom>=n.offsetTop))return()=>{if(h.current){t.classList.remove(`can-sticky`);for(let e of d.current)e.apply(null);h.current=!1}if(v.current!==0)return v.current=0,()=>{var e;return(e=n.onStickyItemsHeightChange)==null?void 0:e.call(n,0)}};let i=((e=f.current)==null?f.current=[...d.current]:e).map(e=>({item:e,rect:e.el.getBoundingClientRect()})).sort((e,t)=>{let n=e.rect.top-t.rect.top;return n===0?e.item.el.compareDocumentPosition(t.item.el)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1:n}),a=n.offsetTop,o=0,s=i.map(({item:e,rect:t},n)=>{var r;if(t.top>a)return null;let s=(r=i[n+1])==null?void 0:r.rect.top;if(e.mode===`replace`&&s!==void 0&&s<a)return null;let c=e.measure(t),l=e.mode===`replace`&&s!==void 0?Math.min(a,s-c.height):a;return o+=c.height,e.mode===`stack`&&(a+=c.height),{...c,top:l,index:n}}),c=n.constraint===`none`?0:Math.min(0,r.bottom-n.offsetTop-o);return()=>{if(h.current=s.some(e=>e!==null),t.classList.toggle(`can-sticky`,h.current),i.forEach(({item:e},t)=>{let n=s[t];n&&(n.top+=c),e.apply(n)}),v.current!==o)return v.current=o,()=>{var e;return(e=n.onStickyItemsHeightChange)==null?void 0:e.call(n,o)}}},[]),C=(0,t.useCallback)(e=>{var t;for(let n of e)(t=m.current.get(n.target))==null||t.invalidate();b()},[b]),w=(0,t.useCallback)(()=>{for(let e of d.current)e.invalidate()},[]),T=(0,t.useCallback)(e=>(d.current.add(e),f.current=null,m.current.set(e.el,e),m.current.set(e.content,e),g.current&&(_.current.set(e.el,p(e.el,C)),_.current.set(e.content,p(e.content,C))),b(),()=>{var t,n;(t=_.current.get(e.el))==null||t(),(n=_.current.get(e.content))==null||n(),_.current.delete(e.el),_.current.delete(e.content),m.current.delete(e.el),m.current.delete(e.content),d.current.delete(e),f.current=null,b()}),[b,C]);(0,t.useEffect)(()=>{g.current=k(S,w);let e;if(typeof ResizeObserver<`u`){u.current&&(_.current.set(u.current,p(u.current,C)),e=x(u.current,()=>{w(),b()}));for(let e of d.current)_.current.set(e.el,p(e.el,C)),_.current.set(e.content,p(e.content,C))}let t=_.current;return()=>{var n;(n=g.current)==null||n.stop(),g.current=null,e==null||e();for(let e of t.values())e();t.clear()}},[S,w,b,C]),(0,t.useEffect)(()=>{y.current={offsetTop:n,constraint:o,onStickyItemsHeightChange:i};for(let e of d.current)e.invalidate();b()});let E=r===void 0?200:Math.max(Number(r)||0,20),D=(0,t.useMemo)(()=>({register:T,scheduleUpdate:b,baseZIndex:E,mode:a}),[T,b,E,a]);return t.default.createElement(l.Provider,{value:D},t.default.createElement(`div`,{...c,ref:u,className:[`oe-sticky-container`,s].filter(Boolean).join(` `)},e))}e.StickyContainer=N,e.StickyItem=A});
@@ -0,0 +1,3 @@
1
+ type Listener = (entries: ResizeObserverEntry[]) => void;
2
+ export declare function observeResize(target: Element, listener: Listener): () => void;
3
+ export {};
@@ -0,0 +1,3 @@
1
+ type Listener = (entries: ResizeObserverEntry[]) => void;
2
+ export declare function observeResize(target: Element, listener: Listener): () => void;
3
+ export {};
@@ -0,0 +1,10 @@
1
+ type Write = () => (() => void) | void;
2
+ type Client = {
3
+ read: () => Write | undefined;
4
+ resize: () => void;
5
+ };
6
+ export declare function subscribeUpdates(read: Client['read'], invalidate: () => void): {
7
+ schedule: () => void;
8
+ stop: () => void;
9
+ };
10
+ export {};
@@ -0,0 +1,10 @@
1
+ type Write = () => (() => void) | void;
2
+ type Client = {
3
+ read: () => Write | undefined;
4
+ resize: () => void;
5
+ };
6
+ export declare function subscribeUpdates(read: Client['read'], invalidate: () => void): {
7
+ schedule: () => void;
8
+ stop: () => void;
9
+ };
10
+ export {};
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type IStickyMode } from './context.cjs';
3
+ export interface IStickyItemProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ children: React.ReactNode;
5
+ /** Sticky mode for this item. Defaults to the StickyContainer's mode. */
6
+ mode?: IStickyMode;
7
+ }
8
+ export declare function StickyItem({ mode, children, className, ...rest }: IStickyItemProps): React.ReactElement<any, any>;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type IStickyMode } from './context.js';
3
+ export interface IStickyItemProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ children: React.ReactNode;
5
+ /** Sticky mode for this item. Defaults to the StickyContainer's mode. */
6
+ mode?: IStickyMode;
7
+ }
8
+ export declare function StickyItem({ mode, children, className, ...rest }: IStickyItemProps): React.ReactElement<any, any>;
package/dist/style.css CHANGED
@@ -1 +1,2 @@
1
- .oe-sticky-container{position:relative}.oe-sticky-container.can-sticky .oe-sticky-content.is-sticky{position:fixed}.oe-sticky-item{position:relative}.oe-sticky-content{will-change:top,position}
1
+ .oe-sticky-container,.oe-sticky-item{position:relative}.oe-sticky-content.is-sticky{position:fixed}
2
+ /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-sticky-kit",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "A lightweight, flexible React sticky container and item component library supporting multiple sticky modes, advanced layouts, and edge cases.",
6
6
  "keywords": [
@@ -20,17 +20,47 @@
20
20
  },
21
21
  "homepage": "https://github.com/oe/react-sticky-kit#readme",
22
22
  "license": "MIT",
23
+ "scripts": {
24
+ "dev": "vite",
25
+ "build": "vite build && tsc -p tsconfig.build.json && node scripts/build-types.mjs",
26
+ "preview": "vite preview",
27
+ "type-check": "tsc --noEmit",
28
+ "lint": "eslint src demo test scripts vite.config.ts vitest.config.ts playwright.config.ts",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "coverage": "vitest run --coverage",
32
+ "pub": "tsx ./scripts/publish.ts",
33
+ "check:package": "node scripts/check-package.mjs",
34
+ "test:browser": "playwright test",
35
+ "prepublishOnly": "pnpm type-check && pnpm lint && pnpm test && pnpm build && pnpm check:package",
36
+ "check:compatibility": "node scripts/check-compatibility.mjs"
37
+ },
23
38
  "files": [
24
39
  "dist"
25
40
  ],
26
- "main": "dist/react-sticky.umd.js",
41
+ "main": "dist/react-sticky.cjs",
27
42
  "module": "dist/react-sticky.es.js",
28
43
  "types": "dist/index.d.ts",
29
44
  "exports": {
30
45
  ".": {
31
- "types": "./dist/index.d.ts",
32
- "import": "./dist/react-sticky.es.js",
33
- "require": "./dist/react-sticky.umd.js"
46
+ "node": {
47
+ "import": {
48
+ "types": "./dist/index.d.cts",
49
+ "default": "./dist/react-sticky.cjs"
50
+ },
51
+ "require": {
52
+ "types": "./dist/index.d.cts",
53
+ "default": "./dist/react-sticky.cjs"
54
+ }
55
+ },
56
+ "import": {
57
+ "types": "./dist/index.d.ts",
58
+ "default": "./dist/react-sticky.es.js"
59
+ },
60
+ "require": {
61
+ "types": "./dist/index.d.cts",
62
+ "default": "./dist/react-sticky.cjs"
63
+ }
34
64
  },
35
65
  "./style": "./dist/style.css",
36
66
  "./dist/style.css": "./dist/style.css"
@@ -41,44 +71,34 @@
41
71
  },
42
72
  "devDependencies": {
43
73
  "@eslint/js": "^9.25.0",
44
- "@testing-library/jest-dom": "^6.1.6",
45
- "@testing-library/react": "^14.1.2",
46
- "@testing-library/user-event": "^14.4.3",
47
- "@types/node": "^22.15.18",
48
- "@types/react": "^19.1.2",
49
- "@types/react-dom": "^19.1.2",
50
- "@typescript-eslint/eslint-plugin": "^8.32.1",
51
- "@typescript-eslint/parser": "^8.32.1",
52
- "@vitejs/plugin-react": "^4.0.0",
53
- "@vitest/coverage-v8": "^3.1.3",
54
- "eslint": "^9.26.0",
74
+ "@playwright/test": "^1.63.0",
75
+ "@testing-library/jest-dom": "^7.0.1",
76
+ "@testing-library/react": "^16.3.3",
77
+ "@types/node": "^24.19.1",
78
+ "@types/react": "^19.3.0",
79
+ "@types/react-dom": "^19.3.0",
80
+ "@typescript-eslint/eslint-plugin": "^8.71.0",
81
+ "@typescript-eslint/parser": "^8.71.0",
82
+ "@vitejs/plugin-react": "^6.1.1",
83
+ "@vitest/coverage-v8": "^5.0.3",
84
+ "eslint": "^9.39.4",
55
85
  "eslint-config-prettier": "^10.1.5",
56
86
  "eslint-plugin-jsx-a11y": "^6.8.0",
57
87
  "eslint-plugin-react": "^7.33.2",
58
- "eslint-plugin-react-hooks": "^5.2.0",
88
+ "eslint-plugin-react-hooks": "^7.1.1",
59
89
  "globals": "^16.0.0",
60
- "identity-obj-proxy": "^3.0.0",
61
- "jsdom": "^26.1.0",
62
- "react": "^19.1.0",
63
- "react-dom": "^19.1.0",
64
- "sass": "^1.88.0",
65
- "ts-node": "^10.9.2",
66
- "tsx": "^4.19.4",
67
- "typescript": "^5.0.0",
68
- "typescript-eslint": "^8.30.1",
69
- "vite": "^4.0.0",
70
- "vite-plugin-dts": "^4.5.4",
71
- "vitest": "^3.1.3"
90
+ "jsdom": "^30.1.1",
91
+ "react": "^19.3.0",
92
+ "react-dom": "^19.3.0",
93
+ "sass": "^1.105.1",
94
+ "tsx": "^4.23.15",
95
+ "typescript": "^6.0.3",
96
+ "vite": "^8.3.2",
97
+ "vitest": "^5.0.3"
72
98
  },
73
- "scripts": {
74
- "dev": "vite",
75
- "build": "vite build",
76
- "preview": "vite preview",
77
- "type-check": "tsc --noEmit",
78
- "lint": "eslint src demo --ext .ts,.tsx,.js,.jsx",
79
- "test": "vitest run",
80
- "test:watch": "vitest",
81
- "coverage": "vitest run --coverage",
82
- "pub": "tsx ./scripts/publish.ts"
83
- }
84
- }
99
+ "packageManager": "pnpm@12.8.1",
100
+ "sideEffects": [
101
+ "**/*.css",
102
+ "**/*.scss"
103
+ ]
104
+ }