react-sticky-kit 0.1.4 → 0.1.5

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
@@ -74,7 +74,7 @@ export default function Example() {
74
74
  ### `<StickyItem />`
75
75
  | Prop | Type | Default | Description |
76
76
  |---------|--------------------------------------|---------|---------------------------------------------|
77
- | `mode` | `'replace' \| 'stack' \| 'none'` | | Sticky mode for this item (overrides group) |
77
+ | `mode` | `'replace' \| 'stack' \| 'none'` | | Sticky mode for this item (overrides StickyContainer) |
78
78
 
79
79
  ## Sticky Modes
80
80
  - **replace**: Only one sticky item is visible at a time, replacing the previous.
@@ -90,7 +90,11 @@ pnpm install
90
90
  pnpm dev
91
91
  ```
92
92
 
93
- Open [http://localhost:5173](http://localhost:5173) and switch between demo pages to explore all features and edge cases.
93
+ Open [http://localhost:5173](http://localhost:5173) and switch between demo pages to explore all features and edge cases:
94
+ * [iOS Contact](http://localhost:5173/#ios-contact) a dead simple iOS contact clone
95
+ * [Mixed mode](http://localhost:5173/#mixed-mode) mix replace/stack/none mode
96
+ * [Nested](http://localhost:5173/#dynamic-height) nest sticky containers
97
+ * [Dynamic sticky items](http://localhost:5173/#nested) dynamic sticky items(add/remove)
94
98
 
95
99
  ## License
96
100
 
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ export declare interface IStickyContainerProps extends default_2.HTMLAttributes<
30
30
  export declare interface IStickyItemProps extends default_2.HTMLAttributes<HTMLDivElement> {
31
31
  children: default_2.ReactNode;
32
32
  /**
33
- * Sticky mode for this item. Defaults to the group's mode if not specified.
33
+ * Sticky mode for this item. Defaults to the StickyContainer's mode if not specified.
34
34
  */
35
35
  mode?: IStickyMode;
36
36
  }
@@ -1,111 +1,119 @@
1
1
  import { jsx as R } from "react/jsx-runtime";
2
- import { createContext as b, useContext as Z, useRef as I, useState as N, useEffect as B, useCallback as w, useMemo as T } from "react";
3
- const x = 20, _ = 200, $ = b(null);
4
- function L() {
5
- return Z($);
2
+ import { createContext as b, useContext as T, useRef as S, useState as Z, useEffect as E, useCallback as w, useMemo as L } from "react";
3
+ const x = 20, N = 200, $ = b(null);
4
+ function _() {
5
+ return T($);
6
6
  }
7
- function M({ mode: s, children: o, className: y, ...h }) {
8
- const e = L(), S = I(null), k = I(null), [r, n] = N(!1), t = I({
7
+ function M({ mode: c, children: o, className: p, ...k }) {
8
+ const e = _(), C = S(null), I = S(null), [r, t] = Z(!1), n = S({
9
9
  fixedOffsetTop: (e == null ? void 0 : e.fixedOffsetTop) || 0,
10
10
  isSticky: r,
11
11
  baseZIndex: (e == null ? void 0 : e.baseZIndex) || x
12
12
  });
13
- return t.current.baseZIndex = (e == null ? void 0 : e.baseZIndex) || x, t.current.fixedOffsetTop = (e == null ? void 0 : e.fixedOffsetTop) || 0, t.current.isSticky = r, B(() => {
14
- const u = k.current, f = S.current, d = s || (e == null ? void 0 : e.mode);
15
- if (!e || !f || !u || d === "none" || !d || !e.register) {
16
- n(!1);
13
+ return n.current.baseZIndex = (e == null ? void 0 : e.baseZIndex) || x, n.current.fixedOffsetTop = (e == null ? void 0 : e.fixedOffsetTop) || 0, n.current.isSticky = r, E(() => {
14
+ const u = I.current, f = C.current, a = c || (e == null ? void 0 : e.mode);
15
+ if (!e || !f || !u || a === "none" || !a || !e.register) {
16
+ t(!1);
17
17
  return;
18
18
  }
19
- const a = {
19
+ const l = {
20
20
  el: f,
21
- update: (l, i, p, C, H) => {
22
- if (!l)
23
- return t.current.isSticky && n(!1), 0;
24
- if (i <= p) {
25
- const g = u.getBoundingClientRect().height;
26
- let v = p;
27
- if (d === "replace" && typeof C < "u") {
28
- const m = C - (p + g);
29
- if (m < 0 && (v = p + m, m + g < 0))
30
- return t.current.isSticky && n(!1), 0;
21
+ update: (d, i, y, m, H) => {
22
+ if (!d)
23
+ return n.current.isSticky && t(!1), 0;
24
+ if (i <= y) {
25
+ const h = u.getBoundingClientRect().height;
26
+ let v = y;
27
+ if (a === "replace" && typeof m < "u") {
28
+ const g = m - (y + h);
29
+ if (g < 0 && (v = y + g, g + h < 0))
30
+ return n.current.isSticky && t(!1), 0;
31
31
  }
32
- return t.current.isSticky || n(!0), u.style.top = `${v}px`, u.style.width = `${f.offsetWidth}px`, u.style.zIndex = `${t.current.baseZIndex + (d === "replace" ? -H : H)}`, f.style.height = `${g}px`, d === "replace" ? 0 : g;
32
+ return f.style.height = `${h}px`, n.current.isSticky || t(!0), u.style.top = `${v}px`, u.style.width = `${f.offsetWidth}px`, u.style.zIndex = `${n.current.baseZIndex + (a === "replace" ? -H : H)}`, a === "replace" ? 0 : h;
33
33
  } else
34
- n(!1);
34
+ t(!1);
35
35
  return 0;
36
36
  }
37
37
  };
38
- return e.register(a);
39
- }, [e == null ? void 0 : e.mode, e == null ? void 0 : e.register, s]), B(() => {
40
- const u = S.current, f = k.current, d = e == null ? void 0 : e.updateStickyItemsHeight;
41
- if (!r || !u || !f || !d)
38
+ return e.register(l);
39
+ }, [e == null ? void 0 : e.mode, e == null ? void 0 : e.register, c]), E(() => {
40
+ const u = C.current, f = I.current, a = e == null ? void 0 : e.updateStickyItemsHeight;
41
+ if (!r || !u || !f || !a)
42
42
  return;
43
- const c = d(f.getBoundingClientRect().height);
43
+ const s = a(f.getBoundingClientRect().height);
44
44
  return () => {
45
- O(u, ["height"]), O(f, ["top", "z-index", "width"]), c();
45
+ O(u, ["height"]), O(f, ["top", "z-index", "width"]), s();
46
46
  };
47
- }, [r, e == null ? void 0 : e.updateStickyItemsHeight]), /* @__PURE__ */ R("div", { className: "oe-sticky-item " + (y || ""), ...h, ref: S, children: /* @__PURE__ */ R("div", { className: "oe-sticky-content " + (r ? "is-sticky" : ""), ref: k, children: o }) });
47
+ }, [r, e == null ? void 0 : e.updateStickyItemsHeight]), /* @__PURE__ */ R("div", { className: "oe-sticky-item " + (p || ""), ...k, ref: C, children: /* @__PURE__ */ R("div", { className: "oe-sticky-content " + (r ? "is-sticky" : ""), ref: I, children: o }) });
48
48
  }
49
- function O(s, o) {
50
- o.forEach((y) => {
51
- s.style.removeProperty(y);
49
+ function O(c, o) {
50
+ o.forEach((p) => {
51
+ c.style.removeProperty(p);
52
52
  });
53
53
  }
54
54
  function P({
55
- children: s,
55
+ children: c,
56
56
  offsetTop: o = 0,
57
- baseZIndex: y,
58
- onStickyItemsHeightChange: h,
57
+ baseZIndex: p,
58
+ onStickyItemsHeightChange: k,
59
59
  defaultMode: e = "replace",
60
- ...S
60
+ ...C
61
61
  }) {
62
- const k = I(null), r = I([]), n = I({
62
+ const I = S(null), r = S([]), t = S({
63
63
  fixedOffsetTop: o,
64
64
  defaultMode: e,
65
65
  stickyItemsHeight: 0,
66
- onStickyItemsHeightChange: h
66
+ onStickyItemsHeightChange: k,
67
+ lastCanSticky: !1
67
68
  });
68
- n.current.onStickyItemsHeightChange = h;
69
- const t = w(() => {
70
- const c = k.current;
71
- if (!c)
69
+ t.current.onStickyItemsHeightChange = k;
70
+ const n = w(() => {
71
+ const s = I.current;
72
+ if (!s)
72
73
  return;
73
- const a = c.getBoundingClientRect(), l = n.current, i = l.fixedOffsetTop, p = l.stickyItemsHeight, C = !(a.top > i || a.bottom < i);
74
- let H = i, g = a.bottom - (i + p);
75
- g > 0 && (g = 0);
76
- const v = r.current.map((m) => m.el.getBoundingClientRect().top);
77
- r.current.forEach((m, E) => {
78
- H += m.update(C, v[E], H + g, v[E + 1], E);
74
+ const l = s.getBoundingClientRect(), d = t.current, i = d.fixedOffsetTop, y = d.stickyItemsHeight, m = !(l.top > i || l.bottom < i);
75
+ if (!m) {
76
+ t.current.lastCanSticky !== m && (s.classList.toggle("can-sticky", !1), r.current.forEach((g) => g.update(!1, 0, 0, 0, 0)), t.current.lastCanSticky = m);
77
+ return;
78
+ }
79
+ t.current.lastCanSticky = m, y > 0 && s.classList.toggle("can-sticky", !0);
80
+ let H = i, h = l.bottom - (i + y);
81
+ h > 0 && (h = 0);
82
+ const v = r.current.map((g) => g.el.getBoundingClientRect().top);
83
+ r.current.forEach((g, B) => {
84
+ H += g.update(m, v[B], H + h, v[B + 1], B);
79
85
  });
80
- }, []), u = w((c) => {
81
- const a = n.current.stickyItemsHeight + c;
82
- return n.current.stickyItemsHeight = a, setTimeout(() => {
83
- var l, i;
84
- (i = (l = n.current).onStickyItemsHeightChange) == null || i.call(l, a);
86
+ }, []), u = w((s) => {
87
+ const l = t.current.stickyItemsHeight + s;
88
+ return t.current.stickyItemsHeight = l, setTimeout(() => {
89
+ var d, i;
90
+ (i = (d = t.current).onStickyItemsHeightChange) == null || i.call(d, l);
85
91
  }, 0), () => {
86
- const l = n.current.stickyItemsHeight - c;
87
- n.current.stickyItemsHeight = l, setTimeout(() => {
88
- var i, p;
89
- (p = (i = n.current).onStickyItemsHeightChange) == null || p.call(i, l);
92
+ const d = t.current.stickyItemsHeight - s;
93
+ t.current.stickyItemsHeight = d, setTimeout(() => {
94
+ var i, y;
95
+ (y = (i = t.current).onStickyItemsHeightChange) == null || y.call(i, d);
90
96
  }, 0);
91
97
  };
92
98
  }, []);
93
- B(() => {
94
- n.current.fixedOffsetTop = o, n.current.defaultMode = e, t();
95
- }, [o, e, t]);
96
- const f = w((c) => (r.current.push(c), r.current = A(r.current), t(), () => {
97
- r.current = r.current.filter((a) => a !== c), t();
98
- }), [t]);
99
- B(() => (window.addEventListener("scroll", t, { passive: !0 }), window.addEventListener("resize", t, { passive: !0 }), () => {
100
- window.removeEventListener("scroll", t), window.removeEventListener("resize", t);
101
- }), [t]);
102
- const d = T(() => z(y), [y]);
99
+ E(() => {
100
+ t.current.fixedOffsetTop = o, t.current.defaultMode = e, setTimeout(() => {
101
+ n();
102
+ }, 10);
103
+ }, [o, e, n]);
104
+ const f = w((s) => (r.current.push(s), r.current = A(r.current), n(), () => {
105
+ r.current = r.current.filter((l) => l !== s), n();
106
+ }), [n]);
107
+ E(() => (window.addEventListener("scroll", n, { passive: !0 }), window.addEventListener("resize", n, { passive: !0 }), () => {
108
+ window.removeEventListener("scroll", n), window.removeEventListener("resize", n);
109
+ }), [n]);
110
+ const a = L(() => z(p), [p]);
103
111
  return /* @__PURE__ */ R(
104
112
  $.Provider,
105
113
  {
106
114
  value: {
107
115
  register: f,
108
- baseZIndex: d,
116
+ baseZIndex: a,
109
117
  updateStickyItemsHeight: u,
110
118
  fixedOffsetTop: o,
111
119
  mode: e
@@ -113,22 +121,22 @@ function P({
113
121
  children: /* @__PURE__ */ R(
114
122
  "div",
115
123
  {
116
- ...S,
117
- ref: k,
124
+ ...C,
125
+ ref: I,
118
126
  className: "oe-sticky-container",
119
- children: s
127
+ children: c
120
128
  }
121
129
  )
122
130
  }
123
131
  );
124
132
  }
125
- function z(s) {
126
- return typeof s > "u" ? _ : Math.max(Number(s) || 0, x);
133
+ function z(c) {
134
+ return typeof c > "u" ? N : Math.max(Number(c) || 0, x);
127
135
  }
128
- function A(s) {
129
- return s.sort((o, y) => {
130
- const h = o.el.getBoundingClientRect(), e = y.el.getBoundingClientRect();
131
- return h.top - e.top;
136
+ function A(c) {
137
+ return c.sort((o, p) => {
138
+ const k = o.el.getBoundingClientRect(), e = p.el.getBoundingClientRect();
139
+ return k.top - e.top;
132
140
  });
133
141
  }
134
142
  export {
@@ -1 +1 @@
1
- (function(p,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],g):(p=typeof globalThis<"u"?globalThis:p||self,g(p.ReactSticky={},p.jsxRuntime,p.React))})(this,function(p,g,n){"use strict";const B=n.createContext(null);function N(){return n.useContext(B)}const $="";function O({mode:c,children:o,className:m,...S}){const e=N(),R=n.useRef(null),E=n.useRef(null),[s,i]=n.useState(!1),t=n.useRef({fixedOffsetTop:(e==null?void 0:e.fixedOffsetTop)||0,isSticky:s,baseZIndex:(e==null?void 0:e.baseZIndex)||20});return t.current.baseZIndex=(e==null?void 0:e.baseZIndex)||20,t.current.fixedOffsetTop=(e==null?void 0:e.fixedOffsetTop)||0,t.current.isSticky=s,n.useEffect(()=>{const f=E.current,d=R.current,l=c||(e==null?void 0:e.mode);if(!e||!d||!f||l==="none"||!l||!e.register){i(!1);return}const y={el:d,update:(a,r,h,C,H)=>{if(!a)return t.current.isSticky&&i(!1),0;if(r<=h){const I=f.getBoundingClientRect().height;let _=h;if(l==="replace"&&typeof C<"u"){const k=C-(h+I);if(k<0&&(_=h+k,k+I<0))return t.current.isSticky&&i(!1),0}return t.current.isSticky||i(!0),f.style.top=`${_}px`,f.style.width=`${d.offsetWidth}px`,f.style.zIndex=`${t.current.baseZIndex+(l==="replace"?-H:H)}`,d.style.height=`${I}px`,l==="replace"?0:I}else i(!1);return 0}};return e.register(y)},[e==null?void 0:e.mode,e==null?void 0:e.register,c]),n.useEffect(()=>{const f=R.current,d=E.current,l=e==null?void 0:e.updateStickyItemsHeight;if(!s||!f||!d||!l)return;const u=l(d.getBoundingClientRect().height);return()=>{x(f,["height"]),x(d,["top","z-index","width"]),u()}},[s,e==null?void 0:e.updateStickyItemsHeight]),g.jsx("div",{className:"oe-sticky-item "+(m||""),...S,ref:R,children:g.jsx("div",{className:"oe-sticky-content "+(s?"is-sticky":""),ref:E,children:o})})}function x(c,o){o.forEach(m=>{c.style.removeProperty(m)})}function Z({children:c,offsetTop:o=0,baseZIndex:m,onStickyItemsHeightChange:S,defaultMode:e="replace",...R}){const E=n.useRef(null),s=n.useRef([]),i=n.useRef({fixedOffsetTop:o,defaultMode:e,stickyItemsHeight:0,onStickyItemsHeightChange:S});i.current.onStickyItemsHeightChange=S;const t=n.useCallback(()=>{const u=E.current;if(!u)return;const y=u.getBoundingClientRect(),a=i.current,r=a.fixedOffsetTop,h=a.stickyItemsHeight,C=!(y.top>r||y.bottom<r);let H=r,I=y.bottom-(r+h);I>0&&(I=0);const _=s.current.map(k=>k.el.getBoundingClientRect().top);s.current.forEach((k,v)=>{H+=k.update(C,_[v],H+I,_[v+1],v)})},[]),f=n.useCallback(u=>{const y=i.current.stickyItemsHeight+u;return i.current.stickyItemsHeight=y,setTimeout(()=>{var a,r;(r=(a=i.current).onStickyItemsHeightChange)==null||r.call(a,y)},0),()=>{const a=i.current.stickyItemsHeight-u;i.current.stickyItemsHeight=a,setTimeout(()=>{var r,h;(h=(r=i.current).onStickyItemsHeightChange)==null||h.call(r,a)},0)}},[]);n.useEffect(()=>{i.current.fixedOffsetTop=o,i.current.defaultMode=e,t()},[o,e,t]);const d=n.useCallback(u=>(s.current.push(u),s.current=w(s.current),t(),()=>{s.current=s.current.filter(y=>y!==u),t()}),[t]);n.useEffect(()=>(window.addEventListener("scroll",t,{passive:!0}),window.addEventListener("resize",t,{passive:!0}),()=>{window.removeEventListener("scroll",t),window.removeEventListener("resize",t)}),[t]);const l=n.useMemo(()=>b(m),[m]);return g.jsx(B.Provider,{value:{register:d,baseZIndex:l,updateStickyItemsHeight:f,fixedOffsetTop:o,mode:e},children:g.jsx("div",{...R,ref:E,className:"oe-sticky-container",children:c})})}function b(c){return typeof c>"u"?200:Math.max(Number(c)||0,20)}function w(c){return c.sort((o,m)=>{const S=o.el.getBoundingClientRect(),e=m.el.getBoundingClientRect();return S.top-e.top})}p.StickyContainer=Z,p.StickyItem=O,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
1
+ (function(g,k){typeof exports=="object"&&typeof module<"u"?k(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],k):(g=typeof globalThis<"u"?globalThis:g||self,k(g.ReactSticky={},g.jsxRuntime,g.React))})(this,function(g,k,s){"use strict";const B=s.createContext(null);function N(){return s.useContext(B)}const $="";function O({mode:u,children:o,className:m,...E}){const e=N(),R=s.useRef(null),C=s.useRef(null),[i,t]=s.useState(!1),n=s.useRef({fixedOffsetTop:(e==null?void 0:e.fixedOffsetTop)||0,isSticky:i,baseZIndex:(e==null?void 0:e.baseZIndex)||20});return n.current.baseZIndex=(e==null?void 0:e.baseZIndex)||20,n.current.fixedOffsetTop=(e==null?void 0:e.fixedOffsetTop)||0,n.current.isSticky=i,s.useEffect(()=>{const f=C.current,l=R.current,d=u||(e==null?void 0:e.mode);if(!e||!l||!f||d==="none"||!d||!e.register){t(!1);return}const a={el:l,update:(y,c,p,I,H)=>{if(!y)return n.current.isSticky&&t(!1),0;if(c<=p){const S=f.getBoundingClientRect().height;let _=p;if(d==="replace"&&typeof I<"u"){const h=I-(p+S);if(h<0&&(_=p+h,h+S<0))return n.current.isSticky&&t(!1),0}return l.style.height=`${S}px`,n.current.isSticky||t(!0),f.style.top=`${_}px`,f.style.width=`${l.offsetWidth}px`,f.style.zIndex=`${n.current.baseZIndex+(d==="replace"?-H:H)}`,d==="replace"?0:S}else t(!1);return 0}};return e.register(a)},[e==null?void 0:e.mode,e==null?void 0:e.register,u]),s.useEffect(()=>{const f=R.current,l=C.current,d=e==null?void 0:e.updateStickyItemsHeight;if(!i||!f||!l||!d)return;const r=d(l.getBoundingClientRect().height);return()=>{x(f,["height"]),x(l,["top","z-index","width"]),r()}},[i,e==null?void 0:e.updateStickyItemsHeight]),k.jsx("div",{className:"oe-sticky-item "+(m||""),...E,ref:R,children:k.jsx("div",{className:"oe-sticky-content "+(i?"is-sticky":""),ref:C,children:o})})}function x(u,o){o.forEach(m=>{u.style.removeProperty(m)})}function T({children:u,offsetTop:o=0,baseZIndex:m,onStickyItemsHeightChange:E,defaultMode:e="replace",...R}){const C=s.useRef(null),i=s.useRef([]),t=s.useRef({fixedOffsetTop:o,defaultMode:e,stickyItemsHeight:0,onStickyItemsHeightChange:E,lastCanSticky:!1});t.current.onStickyItemsHeightChange=E;const n=s.useCallback(()=>{const r=C.current;if(!r)return;const a=r.getBoundingClientRect(),y=t.current,c=y.fixedOffsetTop,p=y.stickyItemsHeight,I=!(a.top>c||a.bottom<c);if(!I){t.current.lastCanSticky!==I&&(r.classList.toggle("can-sticky",!1),i.current.forEach(h=>h.update(!1,0,0,0,0)),t.current.lastCanSticky=I);return}t.current.lastCanSticky=I,p>0&&r.classList.toggle("can-sticky",!0);let H=c,S=a.bottom-(c+p);S>0&&(S=0);const _=i.current.map(h=>h.el.getBoundingClientRect().top);i.current.forEach((h,v)=>{H+=h.update(I,_[v],H+S,_[v+1],v)})},[]),f=s.useCallback(r=>{const a=t.current.stickyItemsHeight+r;return t.current.stickyItemsHeight=a,setTimeout(()=>{var y,c;(c=(y=t.current).onStickyItemsHeightChange)==null||c.call(y,a)},0),()=>{const y=t.current.stickyItemsHeight-r;t.current.stickyItemsHeight=y,setTimeout(()=>{var c,p;(p=(c=t.current).onStickyItemsHeightChange)==null||p.call(c,y)},0)}},[]);s.useEffect(()=>{t.current.fixedOffsetTop=o,t.current.defaultMode=e,setTimeout(()=>{n()},10)},[o,e,n]);const l=s.useCallback(r=>(i.current.push(r),i.current=b(i.current),n(),()=>{i.current=i.current.filter(a=>a!==r),n()}),[n]);s.useEffect(()=>(window.addEventListener("scroll",n,{passive:!0}),window.addEventListener("resize",n,{passive:!0}),()=>{window.removeEventListener("scroll",n),window.removeEventListener("resize",n)}),[n]);const d=s.useMemo(()=>Z(m),[m]);return k.jsx(B.Provider,{value:{register:l,baseZIndex:d,updateStickyItemsHeight:f,fixedOffsetTop:o,mode:e},children:k.jsx("div",{...R,ref:C,className:"oe-sticky-container",children:u})})}function Z(u){return typeof u>"u"?200:Math.max(Number(u)||0,20)}function b(u){return u.sort((o,m)=>{const E=o.el.getBoundingClientRect(),e=m.el.getBoundingClientRect();return E.top-e.top})}g.StickyContainer=T,g.StickyItem=O,Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .oe-sticky-container,.oe-sticky-item{position:relative}.oe-sticky-content{will-change:top,position}.oe-sticky-content.is-sticky{position:fixed}
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}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-sticky-kit",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
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": [