react-sticky-kit 0.1.3 → 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 +9 -3
- package/dist/index.d.ts +1 -1
- package/dist/react-sticky.es.js +84 -78
- package/dist/react-sticky.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -40,7 +40,9 @@ pnpm add react-sticky-kit
|
|
|
40
40
|
|
|
41
41
|
```tsx
|
|
42
42
|
import { StickyContainer, StickyItem } from 'react-sticky-kit';
|
|
43
|
-
|
|
43
|
+
// !! Import styles for sticky components
|
|
44
|
+
import 'react-sticky-kit/dist/style.css';
|
|
45
|
+
// or `import 'react-sticky-kit/style';` for more clean style path(require modern bundler tools)
|
|
44
46
|
|
|
45
47
|
export default function Example() {
|
|
46
48
|
return (
|
|
@@ -72,7 +74,7 @@ export default function Example() {
|
|
|
72
74
|
### `<StickyItem />`
|
|
73
75
|
| Prop | Type | Default | Description |
|
|
74
76
|
|---------|--------------------------------------|---------|---------------------------------------------|
|
|
75
|
-
| `mode` | `'replace' \| 'stack' \| 'none'` | | Sticky mode for this item (overrides
|
|
77
|
+
| `mode` | `'replace' \| 'stack' \| 'none'` | | Sticky mode for this item (overrides StickyContainer) |
|
|
76
78
|
|
|
77
79
|
## Sticky Modes
|
|
78
80
|
- **replace**: Only one sticky item is visible at a time, replacing the previous.
|
|
@@ -88,7 +90,11 @@ pnpm install
|
|
|
88
90
|
pnpm dev
|
|
89
91
|
```
|
|
90
92
|
|
|
91
|
-
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)
|
|
92
98
|
|
|
93
99
|
## License
|
|
94
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
|
|
33
|
+
* Sticky mode for this item. Defaults to the StickyContainer's mode if not specified.
|
|
34
34
|
*/
|
|
35
35
|
mode?: IStickyMode;
|
|
36
36
|
}
|
package/dist/react-sticky.es.js
CHANGED
|
@@ -1,106 +1,113 @@
|
|
|
1
1
|
import { jsx as R } from "react/jsx-runtime";
|
|
2
|
-
import { createContext as b, useContext as
|
|
3
|
-
const x = 20, $ = b(null);
|
|
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
4
|
function _() {
|
|
5
|
-
return
|
|
5
|
+
return T($);
|
|
6
6
|
}
|
|
7
|
-
function
|
|
8
|
-
const e = _(),
|
|
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
|
|
14
|
-
const u =
|
|
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
15
|
if (!e || !f || !u || a === "none" || !a || !e.register) {
|
|
16
|
-
|
|
16
|
+
t(!1);
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
const
|
|
19
|
+
const l = {
|
|
20
20
|
el: f,
|
|
21
|
-
update: (
|
|
22
|
-
if (!
|
|
23
|
-
return
|
|
24
|
-
if (i <=
|
|
25
|
-
const
|
|
26
|
-
let v =
|
|
27
|
-
if (a === "replace" && typeof
|
|
28
|
-
const g =
|
|
29
|
-
if (g < 0 && (v =
|
|
30
|
-
return
|
|
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
|
|
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
|
-
|
|
34
|
+
t(!1);
|
|
35
35
|
return 0;
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
return e.register(
|
|
39
|
-
}, [e == null ? void 0 : e.mode, e == null ? void 0 : e.register,
|
|
40
|
-
const u =
|
|
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
41
|
if (!r || !u || !f || !a)
|
|
42
42
|
return;
|
|
43
|
-
const
|
|
43
|
+
const s = a(f.getBoundingClientRect().height);
|
|
44
44
|
return () => {
|
|
45
|
-
O(u, ["height"]), O(f, ["top", "z-index", "width"]),
|
|
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 " + (
|
|
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(
|
|
50
|
-
o.forEach((
|
|
51
|
-
|
|
49
|
+
function O(c, o) {
|
|
50
|
+
o.forEach((p) => {
|
|
51
|
+
c.style.removeProperty(p);
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
children: s,
|
|
54
|
+
function P({
|
|
55
|
+
children: c,
|
|
57
56
|
offsetTop: o = 0,
|
|
58
|
-
baseZIndex:
|
|
59
|
-
onStickyItemsHeightChange:
|
|
57
|
+
baseZIndex: p,
|
|
58
|
+
onStickyItemsHeightChange: k,
|
|
60
59
|
defaultMode: e = "replace",
|
|
61
|
-
...
|
|
60
|
+
...C
|
|
62
61
|
}) {
|
|
63
|
-
const
|
|
62
|
+
const I = S(null), r = S([]), t = S({
|
|
64
63
|
fixedOffsetTop: o,
|
|
65
64
|
defaultMode: e,
|
|
66
65
|
stickyItemsHeight: 0,
|
|
67
|
-
onStickyItemsHeightChange:
|
|
66
|
+
onStickyItemsHeightChange: k,
|
|
67
|
+
lastCanSticky: !1
|
|
68
68
|
});
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
69
|
+
t.current.onStickyItemsHeightChange = k;
|
|
70
|
+
const n = w(() => {
|
|
71
|
+
const s = I.current;
|
|
72
|
+
if (!s)
|
|
73
73
|
return;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
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);
|
|
77
82
|
const v = r.current.map((g) => g.el.getBoundingClientRect().top);
|
|
78
|
-
r.current.forEach((g,
|
|
79
|
-
H += g.update(
|
|
83
|
+
r.current.forEach((g, B) => {
|
|
84
|
+
H += g.update(m, v[B], H + h, v[B + 1], B);
|
|
80
85
|
});
|
|
81
|
-
}, []), u = w((
|
|
82
|
-
const
|
|
83
|
-
return
|
|
84
|
-
var
|
|
85
|
-
(i = (
|
|
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);
|
|
86
91
|
}, 0), () => {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
var i,
|
|
90
|
-
(
|
|
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);
|
|
91
96
|
}, 0);
|
|
92
97
|
};
|
|
93
98
|
}, []);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}),
|
|
103
|
-
|
|
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]);
|
|
104
111
|
return /* @__PURE__ */ R(
|
|
105
112
|
$.Provider,
|
|
106
113
|
{
|
|
@@ -114,26 +121,25 @@ function U({
|
|
|
114
121
|
children: /* @__PURE__ */ R(
|
|
115
122
|
"div",
|
|
116
123
|
{
|
|
117
|
-
...
|
|
118
|
-
ref:
|
|
124
|
+
...C,
|
|
125
|
+
ref: I,
|
|
119
126
|
className: "oe-sticky-container",
|
|
120
|
-
|
|
121
|
-
children: s
|
|
127
|
+
children: c
|
|
122
128
|
}
|
|
123
129
|
)
|
|
124
130
|
}
|
|
125
131
|
);
|
|
126
132
|
}
|
|
127
|
-
function z(
|
|
128
|
-
return typeof
|
|
133
|
+
function z(c) {
|
|
134
|
+
return typeof c > "u" ? N : Math.max(Number(c) || 0, x);
|
|
129
135
|
}
|
|
130
|
-
function A(
|
|
131
|
-
return
|
|
132
|
-
const
|
|
133
|
-
return
|
|
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;
|
|
134
140
|
});
|
|
135
141
|
}
|
|
136
142
|
export {
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
P as StickyContainer,
|
|
144
|
+
M as StickyItem
|
|
139
145
|
};
|
package/dist/react-sticky.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
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
|
|
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.
|
|
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": [
|
|
@@ -39,7 +39,9 @@
|
|
|
39
39
|
"import": "./dist/react-sticky.es.js",
|
|
40
40
|
"require": "./dist/react-sticky.umd.js",
|
|
41
41
|
"types": "./dist/index.d.ts"
|
|
42
|
-
}
|
|
42
|
+
},
|
|
43
|
+
"./style": "./dist/style.css",
|
|
44
|
+
"./dist/style.css": "./dist/style.css"
|
|
43
45
|
},
|
|
44
46
|
"peerDependencies": {
|
|
45
47
|
"react": ">=17.0.0",
|