sticky-card-stack 0.1.8 → 0.1.10

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
@@ -29,16 +29,8 @@ function App() {
29
29
 
30
30
  return (
31
31
  <StickyCardStack scrollHeight={8}>
32
- <StickyCard
33
- header={<h2>Card 1</h2>}
34
- content={<p>Content</p>}
35
- main={<img src="..." alt="" />}
36
- />
37
- <StickyCard
38
- header={<h2>Card 2</h2>}
39
- content={<p>More content</p>}
40
- main={<img src="..." alt="" />}
41
- />
32
+ <StickyCard><YourComponentA /></StickyCard>
33
+ <StickyCard><YourComponentB /></StickyCard>
42
34
  </StickyCardStack>
43
35
  );
44
36
  }
@@ -64,13 +56,7 @@ Call once at the root of your app. Sets up Lenis smooth scroll and syncs it with
64
56
  | `colorVariants` | `string[]` | — | Optional background colors applied per card by index (cycles if fewer than cards). |
65
57
 
66
58
  ### `StickyCard`
67
-
68
- Each card can be used in two ways:
69
-
70
- - **Structured:** `header`, `content`, and `main` props for the default two-column layout (header top, content bottom-left, main right).
71
- - **Custom:** `children` only; you structure the card yourself.
72
-
73
- Shared prop:
59
+ - **`children`** only; you structure the card yourself.
74
60
 
75
61
  - **`colorOverride`** — Optional hex (or other) color for this card; overrides stack variant/`colorVariants`.
76
62
 
package/dist/scs.js CHANGED
@@ -1,42 +1,42 @@
1
1
  import { jsx as o } from "react/jsx-runtime";
2
- import { createContext as L, useRef as x, useEffect as R, Children as T, useContext as O } from "react";
2
+ import { createContext as O, useRef as x, useEffect as R, Children as T, useContext as U } from "react";
3
3
  import e from "gsap";
4
4
  import { ScrollTrigger as a } from "gsap/ScrollTrigger";
5
- import U from "lenis";
5
+ import H from "lenis";
6
6
  const S = {
7
7
  scrollHeight: 8,
8
8
  cardYOffset: 5,
9
9
  cardScaleStep: 0.075
10
- }, _ = ["#3d2fa9", "#ff7722", "#ff3d33", "#785f47"], X = { variant: 1, color: _[0] }, E = L(X), A = 4;
10
+ }, _ = ["#3d2fa9", "#ff7722", "#ff3d33", "#785f47"], X = { variant: 1, color: _[0] }, E = O(X), A = 4;
11
11
  e.registerPlugin(a);
12
12
  function Y({
13
13
  children: t,
14
14
  scrollHeight: r = S.scrollHeight,
15
15
  cardYOffset: h = S.cardYOffset,
16
- cardScaleStep: m = S.cardScaleStep,
16
+ cardScaleStep: p = S.cardScaleStep,
17
17
  className: w,
18
- colorVariants: d
18
+ colorVariants: u
19
19
  }) {
20
20
  const k = x(null), P = x(null);
21
21
  R(() => {
22
- const u = k.current, n = P.current;
23
- if (!u || !n) return;
22
+ const d = k.current, n = P.current;
23
+ if (!d || !n) return;
24
24
  const s = n.querySelectorAll(".scs-card"), c = s.length;
25
25
  if (c === 0) return;
26
26
  const i = 1 / c;
27
- s.forEach((p, l) => {
28
- e.set(p, {
27
+ s.forEach((m, l) => {
28
+ e.set(m, {
29
29
  xPercent: -50,
30
30
  yPercent: -50 + l * h,
31
- scale: 1 - l * m
31
+ scale: 1 - l * p
32
32
  });
33
33
  });
34
34
  const N = window.innerHeight * r, b = a.create({
35
- trigger: u,
35
+ trigger: d,
36
36
  start: "top top",
37
37
  end: `+=${N}px`,
38
- onUpdate(p) {
39
- const l = p.progress, f = Math.min(
38
+ onUpdate(m) {
39
+ const l = m.progress, f = Math.min(
40
40
  Math.floor(l / i),
41
41
  c - 1
42
42
  ), g = (l - f * i) / i;
@@ -53,11 +53,11 @@ function Y({
53
53
  scale: 1
54
54
  });
55
55
  else {
56
- const v = y - f, D = (v - g) * h, H = 1 - (v - g) * m;
56
+ const v = y - f, D = (v - g) * h, L = 1 - (v - g) * p;
57
57
  e.set(C, {
58
58
  yPercent: -50 + D,
59
59
  rotationX: 0,
60
- scale: H
60
+ scale: L
61
61
  });
62
62
  }
63
63
  });
@@ -66,7 +66,7 @@ function Y({
66
66
  return () => {
67
67
  b.kill();
68
68
  };
69
- }, [r, h, m]);
69
+ }, [r, h, p]);
70
70
  const I = {
71
71
  height: `calc(100svh * ${r})`
72
72
  };
@@ -76,14 +76,14 @@ function Y({
76
76
  ref: k,
77
77
  className: w ? `scs-wrap ${w}` : "scs-wrap",
78
78
  style: I,
79
- children: /* @__PURE__ */ o("section", { className: "scs-stack", children: /* @__PURE__ */ o("div", { ref: P, className: "scs-stack-inner", children: T.map(t, (u, n) => {
80
- const s = T.count(t), c = n % A + 1, i = d && d.length > 0 ? d[n % d.length] : _[n % A];
79
+ children: /* @__PURE__ */ o("section", { className: "scs-stack", children: /* @__PURE__ */ o("div", { ref: P, className: "scs-stack-inner", children: T.map(t, (d, n) => {
80
+ const s = T.count(t), c = n % A + 1, i = u && u.length > 0 ? u[n % u.length] : _[n % A];
81
81
  return /* @__PURE__ */ o(E.Provider, { value: { variant: c, color: i }, children: /* @__PURE__ */ o(
82
82
  "div",
83
83
  {
84
84
  className: "scs-card",
85
85
  style: { zIndex: s - n },
86
- children: u
86
+ children: d
87
87
  }
88
88
  ) });
89
89
  }) }) })
@@ -91,13 +91,13 @@ function Y({
91
91
  );
92
92
  }
93
93
  function j({ children: t }) {
94
- const { color: r } = O(E);
95
- return /* @__PURE__ */ o("div", { style: { backgroundColor: r, width: "100%", minHeight: "100%" }, children: t });
94
+ const { color: r } = U(E);
95
+ return /* @__PURE__ */ o("div", { style: { backgroundColor: r }, children: t });
96
96
  }
97
97
  e.registerPlugin(a);
98
98
  function q() {
99
99
  R(() => {
100
- const t = new U();
100
+ const t = new H();
101
101
  return t.on("scroll", a.update), e.ticker.add((r) => {
102
102
  t.raf(r * 1e3);
103
103
  }), e.ticker.lagSmoothing(0), a.scrollerProxy(document.body, {
package/dist/scs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"scs.js","sources":["../src/lib/types.ts","../src/lib/StickyCardStack.tsx","../src/lib/StickyCard.tsx","../src/lib/useScrollTrigger.ts"],"sourcesContent":["import type { ReactNode } from 'react';\n\n/** Props for the StickyCardStack root component */\nexport interface StickyCardStackProps {\n /** Card elements; each child is rendered as one stacked card */\n children: ReactNode;\n /**\n * Height of the scroll area as a multiple of viewport height.\n * @default 8\n */\n scrollHeight?: number;\n /**\n * Vertical offset between stacked cards (in percent).\n * @default 5\n */\n cardYOffset?: number;\n /**\n * Scale reduction per card in the stack (e.g. 0.075 = 7.5% smaller per card).\n * @default 0.075\n */\n cardScaleStep?: number;\n /** Optional class name for the wrapper element */\n className?: string;\n /**\n * Optional list of background colors (e.g. ['#3d2fa9', '#ff7722']).\n * Applied per card by index (cycles if fewer colors than cards).\n * When not provided, cards use the base CSS variables (.card-1 … .card-4).\n */\n colorVariants?: string[];\n}\n\n/** Props for StickyCard: children only; color comes from StickyCardStack context. */\nexport interface StickyCardProps {\n children: ReactNode;\n}\n\n/** Default values for StickyCardStack animation options */\nexport const STICKY_CARD_STACK_DEFAULTS = {\n scrollHeight: 8,\n cardYOffset: 5,\n cardScaleStep: 0.075,\n} as const;\n","import { createContext, useEffect, useRef, Children } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport type { StickyCardStackProps } from './types';\nimport { STICKY_CARD_STACK_DEFAULTS } from './types';\nimport './StickyCardStack.css';\n\n/** Injected by StickyCardStack: variant (1–4) and per-card color (from colorVariants or defaults). */\nexport interface StickyCardContextValue {\n variant: number;\n color: string;\n}\n\nconst DEFAULT_CARD_COLORS: readonly string[] = ['#3d2fa9', '#ff7722', '#ff3d33', '#785f47'];\nconst defaultContextValue: StickyCardContextValue = { variant: 1, color: DEFAULT_CARD_COLORS[0] };\nexport const StickyCardVariantContext = createContext<StickyCardContextValue>(defaultContextValue);\n\nconst VARIANT_COUNT = 4;\n\ngsap.registerPlugin(ScrollTrigger);\n\n/**\n * A sticky stack of cards that animate on scroll (GSAP + ScrollTrigger).\n * Use with useScrollTrigger() at app root for smooth scrolling.\n */\nexport function StickyCardStack({\n children,\n scrollHeight = STICKY_CARD_STACK_DEFAULTS.scrollHeight,\n cardYOffset = STICKY_CARD_STACK_DEFAULTS.cardYOffset,\n cardScaleStep = STICKY_CARD_STACK_DEFAULTS.cardScaleStep,\n className,\n colorVariants,\n}: StickyCardStackProps) {\n const wrapRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const wrap = wrapRef.current;\n const inner = innerRef.current;\n if (!wrap || !inner) return;\n\n const cards = inner.querySelectorAll<HTMLElement>('.scs-card');\n const totalCards = cards.length;\n if (totalCards === 0) return;\n\n const segmentSize = 1 / totalCards;\n\n cards.forEach((card, i) => {\n gsap.set(card, {\n xPercent: -50,\n yPercent: -50 + i * cardYOffset,\n scale: 1 - i * cardScaleStep,\n });\n });\n\n const scrollHeightPx = window.innerHeight * scrollHeight;\n\n const st = ScrollTrigger.create({\n trigger: wrap,\n start: 'top top',\n end: `+=${scrollHeightPx}px`,\n onUpdate(self) {\n const progress = self.progress;\n const activeIndex = Math.min(\n Math.floor(progress / segmentSize),\n totalCards - 1\n );\n const segmentProgress =\n (progress - activeIndex * segmentSize) / segmentSize;\n\n cards.forEach((card, i) => {\n if (i < activeIndex) {\n gsap.set(card, {\n yPercent: -250,\n rotationX: 35,\n });\n } else if (i === activeIndex) {\n gsap.set(card, {\n yPercent: gsap.utils.interpolate(-50, -200, segmentProgress),\n rotationX: gsap.utils.interpolate(0, 35, segmentProgress),\n scale: 1,\n });\n } else {\n const behindIndex = i - activeIndex;\n const currentYOffset = (behindIndex - segmentProgress) * cardYOffset;\n const currentScale =\n 1 - (behindIndex - segmentProgress) * cardScaleStep;\n gsap.set(card, {\n yPercent: -50 + currentYOffset,\n rotationX: 0,\n scale: currentScale,\n });\n }\n });\n },\n });\n\n return () => {\n st.kill();\n };\n }, [scrollHeight, cardYOffset, cardScaleStep]);\n\n const wrapStyle = {\n height: `calc(100svh * ${scrollHeight})`,\n };\n\n return (\n <div\n ref={wrapRef}\n className={className ? `scs-wrap ${className}` : 'scs-wrap'}\n style={wrapStyle}\n >\n <section className=\"scs-stack\">\n <div ref={innerRef} className=\"scs-stack-inner\">\n {Children.map(children, (child, index) => {\n const totalCards = Children.count(children);\n const variant = (index % VARIANT_COUNT) + 1;\n const color =\n colorVariants && colorVariants.length > 0\n ? colorVariants[index % colorVariants.length]\n : DEFAULT_CARD_COLORS[(index % VARIANT_COUNT)];\n return (\n <StickyCardVariantContext.Provider value={{ variant, color }}>\n <div\n className=\"scs-card\"\n style={{ zIndex: totalCards - index }}\n >\n {child}\n </div>\n </StickyCardVariantContext.Provider>\n );\n })}\n </div>\n </section>\n </div>\n );\n}\n","import { useContext, type ReactElement } from 'react';\nimport { StickyCardVariantContext } from './StickyCardStack';\nimport type { StickyCardProps } from './types';\n\n/**\n * A single card for use inside StickyCardStack.\n * Pass children; background uses context color from the stack.\n */\nexport function StickyCard({ children }: StickyCardProps): ReactElement {\n const { color } = useContext(StickyCardVariantContext);\n return (\n <div style={{ backgroundColor: color, width: '100%', minHeight: '100%' }}>\n {children}\n </div>\n );\n}\n","import { useEffect } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport Lenis from 'lenis';\n\ngsap.registerPlugin(ScrollTrigger);\n\n/**\n * Sets up Lenis smooth scroll and syncs it with GSAP ScrollTrigger.\n * Call once at app root (e.g. in your root layout or App) when using StickyCardStack.\n */\nexport function useScrollTrigger(): void {\n useEffect(() => {\n const lenis = new Lenis();\n\n lenis.on('scroll', ScrollTrigger.update);\n\n gsap.ticker.add((time) => {\n lenis.raf(time * 1000);\n });\n gsap.ticker.lagSmoothing(0);\n\n ScrollTrigger.scrollerProxy(document.body, {\n scrollTop(value) {\n if (arguments.length && typeof value === 'number') {\n lenis.scrollTo(value, { immediate: true });\n }\n return lenis.scroll;\n },\n getBoundingClientRect() {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n },\n });\n\n return () => {\n gsap.ticker.remove(lenis.raf);\n lenis.destroy();\n };\n }, []);\n}\n"],"names":["STICKY_CARD_STACK_DEFAULTS","DEFAULT_CARD_COLORS","defaultContextValue","StickyCardVariantContext","createContext","VARIANT_COUNT","gsap","ScrollTrigger","StickyCardStack","children","scrollHeight","cardYOffset","cardScaleStep","className","colorVariants","wrapRef","useRef","innerRef","useEffect","wrap","inner","cards","totalCards","segmentSize","card","i","scrollHeightPx","st","self","progress","activeIndex","segmentProgress","behindIndex","currentYOffset","currentScale","wrapStyle","jsx","Children","child","index","variant","color","StickyCard","useContext","useScrollTrigger","lenis","Lenis","time","value"],"mappings":";;;;;AAqCO,MAAMA,IAA6B;AAAA,EACxC,cAAc;AAAA,EACd,aAAa;AAAA,EACb,eAAe;AACjB,GC5BMC,IAAyC,CAAC,WAAW,WAAW,WAAW,SAAS,GACpFC,IAA8C,EAAE,SAAS,GAAG,OAAOD,EAAoB,CAAC,EAAA,GACjFE,IAA2BC,EAAsCF,CAAmB,GAE3FG,IAAgB;AAEtBC,EAAK,eAAeC,CAAa;AAM1B,SAASC,EAAgB;AAAA,EAC9B,UAAAC;AAAA,EACA,cAAAC,IAAeV,EAA2B;AAAA,EAC1C,aAAAW,IAAcX,EAA2B;AAAA,EACzC,eAAAY,IAAgBZ,EAA2B;AAAA,EAC3C,WAAAa;AAAA,EACA,eAAAC;AACF,GAAyB;AACvB,QAAMC,IAAUC,EAAuB,IAAI,GACrCC,IAAWD,EAAuB,IAAI;AAE5C,EAAAE,EAAU,MAAM;AACd,UAAMC,IAAOJ,EAAQ,SACfK,IAAQH,EAAS;AACvB,QAAI,CAACE,KAAQ,CAACC,EAAO;AAErB,UAAMC,IAAQD,EAAM,iBAA8B,WAAW,GACvDE,IAAaD,EAAM;AACzB,QAAIC,MAAe,EAAG;AAEtB,UAAMC,IAAc,IAAID;AAExB,IAAAD,EAAM,QAAQ,CAACG,GAAMC,MAAM;AACzB,MAAAnB,EAAK,IAAIkB,GAAM;AAAA,QACb,UAAU;AAAA,QACV,UAAU,MAAMC,IAAId;AAAA,QACpB,OAAO,IAAIc,IAAIb;AAAA,MAAA,CAChB;AAAA,IACH,CAAC;AAED,UAAMc,IAAiB,OAAO,cAAchB,GAEtCiB,IAAKpB,EAAc,OAAO;AAAA,MAC9B,SAASY;AAAA,MACT,OAAO;AAAA,MACP,KAAK,KAAKO,CAAc;AAAA,MACxB,SAASE,GAAM;AACb,cAAMC,IAAWD,EAAK,UAChBE,IAAc,KAAK;AAAA,UACvB,KAAK,MAAMD,IAAWN,CAAW;AAAA,UACjCD,IAAa;AAAA,QAAA,GAETS,KACHF,IAAWC,IAAcP,KAAeA;AAE3C,QAAAF,EAAM,QAAQ,CAACG,GAAMC,MAAM;AACzB,cAAIA,IAAIK;AACN,YAAAxB,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAU;AAAA,cACV,WAAW;AAAA,YAAA,CACZ;AAAA,mBACQC,MAAMK;AACf,YAAAxB,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAUlB,EAAK,MAAM,YAAY,KAAK,MAAMyB,CAAe;AAAA,cAC3D,WAAWzB,EAAK,MAAM,YAAY,GAAG,IAAIyB,CAAe;AAAA,cACxD,OAAO;AAAA,YAAA,CACR;AAAA,eACI;AACL,kBAAMC,IAAcP,IAAIK,GAClBG,KAAkBD,IAAcD,KAAmBpB,GACnDuB,IACJ,KAAKF,IAAcD,KAAmBnB;AACxC,YAAAN,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAU,MAAMS;AAAA,cAChB,WAAW;AAAA,cACX,OAAOC;AAAA,YAAA,CACR;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IAAA,CACD;AAED,WAAO,MAAM;AACX,MAAAP,EAAG,KAAA;AAAA,IACL;AAAA,EACF,GAAG,CAACjB,GAAcC,GAAaC,CAAa,CAAC;AAE7C,QAAMuB,IAAY;AAAA,IAChB,QAAQ,iBAAiBzB,CAAY;AAAA,EAAA;AAGvC,SACE,gBAAA0B;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKrB;AAAA,MACL,WAAWF,IAAY,YAAYA,CAAS,KAAK;AAAA,MACjD,OAAOsB;AAAA,MAEP,UAAA,gBAAAC,EAAC,WAAA,EAAQ,WAAU,aACjB,4BAAC,OAAA,EAAI,KAAKnB,GAAU,WAAU,mBAC3B,UAAAoB,EAAS,IAAI5B,GAAU,CAAC6B,GAAOC,MAAU;AACxC,cAAMjB,IAAae,EAAS,MAAM5B,CAAQ,GACpC+B,IAAWD,IAAQlC,IAAiB,GACpCoC,IACJ3B,KAAiBA,EAAc,SAAS,IACpCA,EAAcyB,IAAQzB,EAAc,MAAM,IAC1Cb,EAAqBsC,IAAQlC,CAAc;AACjD,eACE,gBAAA+B,EAACjC,EAAyB,UAAzB,EAAkC,OAAO,EAAE,SAAAqC,GAAS,OAAAC,KACnD,UAAA,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,QAAQd,IAAaiB,EAAA;AAAA,YAE7B,UAAAD;AAAA,UAAA;AAAA,QAAA,GAEL;AAAA,MAEJ,CAAC,GACH,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;AChIO,SAASI,EAAW,EAAE,UAAAjC,KAA2C;AACtE,QAAM,EAAE,OAAAgC,EAAA,IAAUE,EAAWxC,CAAwB;AACrD,SACE,gBAAAiC,EAAC,OAAA,EAAI,OAAO,EAAE,iBAAiBK,GAAO,OAAO,QAAQ,WAAW,OAAA,GAC7D,UAAAhC,EAAA,CACH;AAEJ;ACVAH,EAAK,eAAeC,CAAa;AAM1B,SAASqC,IAAyB;AACvC,EAAA1B,EAAU,MAAM;AACd,UAAM2B,IAAQ,IAAIC,EAAA;AAElB,WAAAD,EAAM,GAAG,UAAUtC,EAAc,MAAM,GAEvCD,EAAK,OAAO,IAAI,CAACyC,MAAS;AACxB,MAAAF,EAAM,IAAIE,IAAO,GAAI;AAAA,IACvB,CAAC,GACDzC,EAAK,OAAO,aAAa,CAAC,GAE1BC,EAAc,cAAc,SAAS,MAAM;AAAA,MACzC,UAAUyC,GAAO;AACf,eAAI,UAAU,UAAU,OAAOA,KAAU,YACvCH,EAAM,SAASG,GAAO,EAAE,WAAW,IAAM,GAEpCH,EAAM;AAAA,MACf;AAAA,MACA,wBAAwB;AACtB,eAAO;AAAA,UACL,KAAK;AAAA,UACL,MAAM;AAAA,UACN,OAAO,OAAO;AAAA,UACd,QAAQ,OAAO;AAAA,QAAA;AAAA,MAEnB;AAAA,IAAA,CACD,GAEM,MAAM;AACX,MAAAvC,EAAK,OAAO,OAAOuC,EAAM,GAAG,GAC5BA,EAAM,QAAA;AAAA,IACR;AAAA,EACF,GAAG,CAAA,CAAE;AACP;"}
1
+ {"version":3,"file":"scs.js","sources":["../src/lib/types.ts","../src/lib/StickyCardStack.tsx","../src/lib/StickyCard.tsx","../src/lib/useScrollTrigger.ts"],"sourcesContent":["import type { ReactNode } from 'react';\n\n/** Props for the StickyCardStack root component */\nexport interface StickyCardStackProps {\n /** Card elements; each child is rendered as one stacked card */\n children: ReactNode;\n /**\n * Height of the scroll area as a multiple of viewport height.\n * @default 8\n */\n scrollHeight?: number;\n /**\n * Vertical offset between stacked cards (in percent).\n * @default 5\n */\n cardYOffset?: number;\n /**\n * Scale reduction per card in the stack (e.g. 0.075 = 7.5% smaller per card).\n * @default 0.075\n */\n cardScaleStep?: number;\n /** Optional class name for the wrapper element */\n className?: string;\n /**\n * Optional list of background colors (e.g. ['#3d2fa9', '#ff7722']).\n * Applied per card by index (cycles if fewer colors than cards).\n * When not provided, cards use the base CSS variables (.card-1 … .card-4).\n */\n colorVariants?: string[];\n}\n\n/** Props for StickyCard: children only; color comes from StickyCardStack context. */\nexport interface StickyCardProps {\n children: ReactNode;\n}\n\n/** Default values for StickyCardStack animation options */\nexport const STICKY_CARD_STACK_DEFAULTS = {\n scrollHeight: 8,\n cardYOffset: 5,\n cardScaleStep: 0.075,\n} as const;\n","import { createContext, useEffect, useRef, Children } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport type { StickyCardStackProps } from './types';\nimport { STICKY_CARD_STACK_DEFAULTS } from './types';\nimport './StickyCardStack.css';\n\n/** Injected by StickyCardStack: variant (1–4) and per-card color (from colorVariants or defaults). */\nexport interface StickyCardContextValue {\n variant: number;\n color: string;\n}\n\nconst DEFAULT_CARD_COLORS: readonly string[] = ['#3d2fa9', '#ff7722', '#ff3d33', '#785f47'];\nconst defaultContextValue: StickyCardContextValue = { variant: 1, color: DEFAULT_CARD_COLORS[0] };\nexport const StickyCardVariantContext = createContext<StickyCardContextValue>(defaultContextValue);\n\nconst VARIANT_COUNT = 4;\n\ngsap.registerPlugin(ScrollTrigger);\n\n/**\n * A sticky stack of cards that animate on scroll (GSAP + ScrollTrigger).\n * Use with useScrollTrigger() at app root for smooth scrolling.\n */\nexport function StickyCardStack({\n children,\n scrollHeight = STICKY_CARD_STACK_DEFAULTS.scrollHeight,\n cardYOffset = STICKY_CARD_STACK_DEFAULTS.cardYOffset,\n cardScaleStep = STICKY_CARD_STACK_DEFAULTS.cardScaleStep,\n className,\n colorVariants,\n}: StickyCardStackProps) {\n const wrapRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const wrap = wrapRef.current;\n const inner = innerRef.current;\n if (!wrap || !inner) return;\n\n const cards = inner.querySelectorAll<HTMLElement>('.scs-card');\n const totalCards = cards.length;\n if (totalCards === 0) return;\n\n const segmentSize = 1 / totalCards;\n\n cards.forEach((card, i) => {\n gsap.set(card, {\n xPercent: -50,\n yPercent: -50 + i * cardYOffset,\n scale: 1 - i * cardScaleStep,\n });\n });\n\n const scrollHeightPx = window.innerHeight * scrollHeight;\n\n const st = ScrollTrigger.create({\n trigger: wrap,\n start: 'top top',\n end: `+=${scrollHeightPx}px`,\n onUpdate(self) {\n const progress = self.progress;\n const activeIndex = Math.min(\n Math.floor(progress / segmentSize),\n totalCards - 1\n );\n const segmentProgress =\n (progress - activeIndex * segmentSize) / segmentSize;\n\n cards.forEach((card, i) => {\n if (i < activeIndex) {\n gsap.set(card, {\n yPercent: -250,\n rotationX: 35,\n });\n } else if (i === activeIndex) {\n gsap.set(card, {\n yPercent: gsap.utils.interpolate(-50, -200, segmentProgress),\n rotationX: gsap.utils.interpolate(0, 35, segmentProgress),\n scale: 1,\n });\n } else {\n const behindIndex = i - activeIndex;\n const currentYOffset = (behindIndex - segmentProgress) * cardYOffset;\n const currentScale =\n 1 - (behindIndex - segmentProgress) * cardScaleStep;\n gsap.set(card, {\n yPercent: -50 + currentYOffset,\n rotationX: 0,\n scale: currentScale,\n });\n }\n });\n },\n });\n\n return () => {\n st.kill();\n };\n }, [scrollHeight, cardYOffset, cardScaleStep]);\n\n const wrapStyle = {\n height: `calc(100svh * ${scrollHeight})`,\n };\n\n return (\n <div\n ref={wrapRef}\n className={className ? `scs-wrap ${className}` : 'scs-wrap'}\n style={wrapStyle}\n >\n <section className=\"scs-stack\">\n <div ref={innerRef} className=\"scs-stack-inner\">\n {Children.map(children, (child, index) => {\n const totalCards = Children.count(children);\n const variant = (index % VARIANT_COUNT) + 1;\n const color =\n colorVariants && colorVariants.length > 0\n ? colorVariants[index % colorVariants.length]\n : DEFAULT_CARD_COLORS[(index % VARIANT_COUNT)];\n return (\n <StickyCardVariantContext.Provider value={{ variant, color }}>\n <div\n className=\"scs-card\"\n style={{ zIndex: totalCards - index }}\n >\n {child}\n </div>\n </StickyCardVariantContext.Provider>\n );\n })}\n </div>\n </section>\n </div>\n );\n}\n","import { useContext, type ReactElement } from 'react';\nimport { StickyCardVariantContext } from './StickyCardStack';\nimport type { StickyCardProps } from './types';\n\n/**\n * A single card for use inside StickyCardStack.\n * Pass children; background uses context color from the stack.\n */\nexport function StickyCard({ children }: StickyCardProps): ReactElement {\n const { color } = useContext(StickyCardVariantContext);\n return (\n <div style={{ backgroundColor: color }}>\n {children}\n </div>\n );\n}\n","import { useEffect } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport Lenis from 'lenis';\n\ngsap.registerPlugin(ScrollTrigger);\n\n/**\n * Sets up Lenis smooth scroll and syncs it with GSAP ScrollTrigger.\n * Call once at app root (e.g. in your root layout or App) when using StickyCardStack.\n */\nexport function useScrollTrigger(): void {\n useEffect(() => {\n const lenis = new Lenis();\n\n lenis.on('scroll', ScrollTrigger.update);\n\n gsap.ticker.add((time) => {\n lenis.raf(time * 1000);\n });\n gsap.ticker.lagSmoothing(0);\n\n ScrollTrigger.scrollerProxy(document.body, {\n scrollTop(value) {\n if (arguments.length && typeof value === 'number') {\n lenis.scrollTo(value, { immediate: true });\n }\n return lenis.scroll;\n },\n getBoundingClientRect() {\n return {\n top: 0,\n left: 0,\n width: window.innerWidth,\n height: window.innerHeight,\n };\n },\n });\n\n return () => {\n gsap.ticker.remove(lenis.raf);\n lenis.destroy();\n };\n }, []);\n}\n"],"names":["STICKY_CARD_STACK_DEFAULTS","DEFAULT_CARD_COLORS","defaultContextValue","StickyCardVariantContext","createContext","VARIANT_COUNT","gsap","ScrollTrigger","StickyCardStack","children","scrollHeight","cardYOffset","cardScaleStep","className","colorVariants","wrapRef","useRef","innerRef","useEffect","wrap","inner","cards","totalCards","segmentSize","card","i","scrollHeightPx","st","self","progress","activeIndex","segmentProgress","behindIndex","currentYOffset","currentScale","wrapStyle","jsx","Children","child","index","variant","color","StickyCard","useContext","useScrollTrigger","lenis","Lenis","time","value"],"mappings":";;;;;AAqCO,MAAMA,IAA6B;AAAA,EACxC,cAAc;AAAA,EACd,aAAa;AAAA,EACb,eAAe;AACjB,GC5BMC,IAAyC,CAAC,WAAW,WAAW,WAAW,SAAS,GACpFC,IAA8C,EAAE,SAAS,GAAG,OAAOD,EAAoB,CAAC,EAAA,GACjFE,IAA2BC,EAAsCF,CAAmB,GAE3FG,IAAgB;AAEtBC,EAAK,eAAeC,CAAa;AAM1B,SAASC,EAAgB;AAAA,EAC9B,UAAAC;AAAA,EACA,cAAAC,IAAeV,EAA2B;AAAA,EAC1C,aAAAW,IAAcX,EAA2B;AAAA,EACzC,eAAAY,IAAgBZ,EAA2B;AAAA,EAC3C,WAAAa;AAAA,EACA,eAAAC;AACF,GAAyB;AACvB,QAAMC,IAAUC,EAAuB,IAAI,GACrCC,IAAWD,EAAuB,IAAI;AAE5C,EAAAE,EAAU,MAAM;AACd,UAAMC,IAAOJ,EAAQ,SACfK,IAAQH,EAAS;AACvB,QAAI,CAACE,KAAQ,CAACC,EAAO;AAErB,UAAMC,IAAQD,EAAM,iBAA8B,WAAW,GACvDE,IAAaD,EAAM;AACzB,QAAIC,MAAe,EAAG;AAEtB,UAAMC,IAAc,IAAID;AAExB,IAAAD,EAAM,QAAQ,CAACG,GAAMC,MAAM;AACzB,MAAAnB,EAAK,IAAIkB,GAAM;AAAA,QACb,UAAU;AAAA,QACV,UAAU,MAAMC,IAAId;AAAA,QACpB,OAAO,IAAIc,IAAIb;AAAA,MAAA,CAChB;AAAA,IACH,CAAC;AAED,UAAMc,IAAiB,OAAO,cAAchB,GAEtCiB,IAAKpB,EAAc,OAAO;AAAA,MAC9B,SAASY;AAAA,MACT,OAAO;AAAA,MACP,KAAK,KAAKO,CAAc;AAAA,MACxB,SAASE,GAAM;AACb,cAAMC,IAAWD,EAAK,UAChBE,IAAc,KAAK;AAAA,UACvB,KAAK,MAAMD,IAAWN,CAAW;AAAA,UACjCD,IAAa;AAAA,QAAA,GAETS,KACHF,IAAWC,IAAcP,KAAeA;AAE3C,QAAAF,EAAM,QAAQ,CAACG,GAAMC,MAAM;AACzB,cAAIA,IAAIK;AACN,YAAAxB,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAU;AAAA,cACV,WAAW;AAAA,YAAA,CACZ;AAAA,mBACQC,MAAMK;AACf,YAAAxB,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAUlB,EAAK,MAAM,YAAY,KAAK,MAAMyB,CAAe;AAAA,cAC3D,WAAWzB,EAAK,MAAM,YAAY,GAAG,IAAIyB,CAAe;AAAA,cACxD,OAAO;AAAA,YAAA,CACR;AAAA,eACI;AACL,kBAAMC,IAAcP,IAAIK,GAClBG,KAAkBD,IAAcD,KAAmBpB,GACnDuB,IACJ,KAAKF,IAAcD,KAAmBnB;AACxC,YAAAN,EAAK,IAAIkB,GAAM;AAAA,cACb,UAAU,MAAMS;AAAA,cAChB,WAAW;AAAA,cACX,OAAOC;AAAA,YAAA,CACR;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IAAA,CACD;AAED,WAAO,MAAM;AACX,MAAAP,EAAG,KAAA;AAAA,IACL;AAAA,EACF,GAAG,CAACjB,GAAcC,GAAaC,CAAa,CAAC;AAE7C,QAAMuB,IAAY;AAAA,IAChB,QAAQ,iBAAiBzB,CAAY;AAAA,EAAA;AAGvC,SACE,gBAAA0B;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKrB;AAAA,MACL,WAAWF,IAAY,YAAYA,CAAS,KAAK;AAAA,MACjD,OAAOsB;AAAA,MAEP,UAAA,gBAAAC,EAAC,WAAA,EAAQ,WAAU,aACjB,4BAAC,OAAA,EAAI,KAAKnB,GAAU,WAAU,mBAC3B,UAAAoB,EAAS,IAAI5B,GAAU,CAAC6B,GAAOC,MAAU;AACxC,cAAMjB,IAAae,EAAS,MAAM5B,CAAQ,GACpC+B,IAAWD,IAAQlC,IAAiB,GACpCoC,IACJ3B,KAAiBA,EAAc,SAAS,IACpCA,EAAcyB,IAAQzB,EAAc,MAAM,IAC1Cb,EAAqBsC,IAAQlC,CAAc;AACjD,eACE,gBAAA+B,EAACjC,EAAyB,UAAzB,EAAkC,OAAO,EAAE,SAAAqC,GAAS,OAAAC,KACnD,UAAA,gBAAAL;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,QAAQd,IAAaiB,EAAA;AAAA,YAE7B,UAAAD;AAAA,UAAA;AAAA,QAAA,GAEL;AAAA,MAEJ,CAAC,GACH,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;AChIO,SAASI,EAAW,EAAE,UAAAjC,KAA2C;AACtE,QAAM,EAAE,OAAAgC,EAAA,IAAUE,EAAWxC,CAAwB;AACrD,2BACG,OAAA,EAAI,OAAO,EAAE,iBAAiBsC,EAAA,GAC5B,UAAAhC,GACH;AAEJ;ACVAH,EAAK,eAAeC,CAAa;AAM1B,SAASqC,IAAyB;AACvC,EAAA1B,EAAU,MAAM;AACd,UAAM2B,IAAQ,IAAIC,EAAA;AAElB,WAAAD,EAAM,GAAG,UAAUtC,EAAc,MAAM,GAEvCD,EAAK,OAAO,IAAI,CAACyC,MAAS;AACxB,MAAAF,EAAM,IAAIE,IAAO,GAAI;AAAA,IACvB,CAAC,GACDzC,EAAK,OAAO,aAAa,CAAC,GAE1BC,EAAc,cAAc,SAAS,MAAM;AAAA,MACzC,UAAUyC,GAAO;AACf,eAAI,UAAU,UAAU,OAAOA,KAAU,YACvCH,EAAM,SAASG,GAAO,EAAE,WAAW,IAAM,GAEpCH,EAAM;AAAA,MACf;AAAA,MACA,wBAAwB;AACtB,eAAO;AAAA,UACL,KAAK;AAAA,UACL,MAAM;AAAA,UACN,OAAO,OAAO;AAAA,UACd,QAAQ,OAAO;AAAA,QAAA;AAAA,MAEnB;AAAA,IAAA,CACD,GAEM,MAAM;AACX,MAAAvC,EAAK,OAAO,OAAOuC,EAAM,GAAG,GAC5BA,EAAM,QAAA;AAAA,IACR;AAAA,EACF,GAAG,CAAA,CAAE;AACP;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sticky-card-stack",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "React sticky card stack with GSAP ScrollTrigger and Lenis smooth scroll",
5
5
  "type": "module",
6
6
  "main": "./dist/scs.js",