gsap-react-marquee 0.3.1 → 0.3.2

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
@@ -1,150 +1,232 @@
1
1
  # GSAP React Marquee
2
2
 
3
- A high-performance React marquee component powered by GSAP animations with intelligent container detection and seamless looping.
3
+ `gsap-react-marquee` is a React marquee component powered by GSAP. It supports horizontal and vertical scrolling, seamless looping, optional fill mode, pause-on-hover, scroll-follow speed changes, draggable interaction, gradient overlays, and TypeScript types.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install gsap-react-marquee
9
- # or
10
- yarn add gsap-react-marquee
11
- # or
12
- pnpm add gsap-react-marquee
8
+ npm install gsap-react-marquee gsap @gsap/react
13
9
  ```
14
10
 
15
- ## Usage
11
+ ```bash
12
+ yarn add gsap-react-marquee gsap @gsap/react
13
+ ```
14
+
15
+ ```bash
16
+ pnpm add gsap-react-marquee gsap @gsap/react
17
+ ```
18
+
19
+ `react`, `react-dom`, `gsap`, and `@gsap/react` are peer dependencies and must be installed by the consuming app.
20
+
21
+ ## Basic Usage
16
22
 
17
23
  ```tsx
18
24
  import Marquee from "gsap-react-marquee";
19
25
 
20
- function App() {
26
+ export function App() {
21
27
  return (
22
- <Marquee dir="left" speed={100} fill={true} spacing={16}>
23
- <div>Hello world</div>
28
+ <Marquee dir="left" speed={100} spacing={16}>
29
+ <span>Scrolling content</span>
24
30
  </Marquee>
25
31
  );
26
32
  }
27
33
  ```
28
34
 
29
- ## Features
30
-
31
- - **Intelligent Container Detection**: Automatically detects whether containers have fixed dimensions or adapt to content, preventing recursive expansion loops
32
- - **Seamless Looping**: Advanced duplicate calculation ensures smooth infinite scrolling without gaps
33
- - **High Performance**: Built with GSAP for optimal animation performance
34
- - **Responsive Design**: Adapts to different screen sizes and container dimensions
35
- - **Multiple Directions**: Support for horizontal (left/right) and vertical (up/down) scrolling with proper axis handling
36
- - **Smart Gradient Overlays**: Automatic gradient positioning based on marquee orientation
37
- - **Interactive Controls**: Optional draggable interface and scroll synchronization
38
- - **TypeScript Support**: Full type safety and IntelliSense support
35
+ The package injects its base CSS through the bundled entrypoint, so no separate stylesheet import is required.
39
36
 
40
- ## Props
37
+ ## Examples
41
38
 
42
- | Prop | Type | Default | Description |
43
- | --------------- | ------------------------------------- | -------- | ------------------------------------------------------------- |
44
- | `children` | `ReactNode` | – | Content to render inside the marquee |
45
- | `className` | `string` | – | Additional CSS classes for styling |
46
- | `dir` | `"right" \| "left" \| "up" \| "down"` | `"left"` | Direction of the marquee movement |
47
- | `loop` | `number` | `-1` | Number of loops (`-1` = infinite) |
48
- | `paused` | `boolean` | `false` | Whether the marquee animation should be paused |
49
- | `delay` | `number` | `0` | Delay before the animation starts (in seconds) |
50
- | `speed` | `number` | `100` | Speed of the marquee animation in px/s |
51
- | `fill` | `boolean` | `false` | Whether the marquee should continuously fill the space |
52
- | `pauseOnHover` | `boolean` | `false` | Pause the marquee when hovering |
53
- | `gradient` | `boolean` | `false` | Enable gradient overlay (auto-adapts to orientation) |
54
- | `gradientColor` | `string` | – | Color of the gradient if enabled |
55
- | `spacing` | `number` | `16` | Spacing between repeated elements in px |
56
- | `draggable` | `boolean` | `false` | Enable dragging to scroll manually |
57
- | `scrollFollow` | `boolean` | `false` | Sync marquee with page scroll direction |
58
- | `scrollSpeed` | `number` | `2.5` | Speed factor when syncing with page scroll (max: 4, min: 1.1) |
39
+ ### Continuous Fill
59
40
 
60
- ## Advanced Features
41
+ Use `fill` when a short piece of content should repeat enough times to cover the visible marquee area.
61
42
 
62
- ### Intelligent Container Detection
43
+ ```tsx
44
+ <Marquee fill spacing={24} speed={80}>
45
+ <span>React</span>
46
+ <span>GSAP</span>
47
+ <span>Animation</span>
48
+ </Marquee>
49
+ ```
63
50
 
64
- The component automatically detects container dimensions to prevent recursive expansion:
51
+ ### Vertical Marquee
65
52
 
66
- - **Fixed Width Containers**: Uses container dimensions for optimal duplicate calculation
67
- - **Auto-Width Containers**: Falls back to viewport dimensions to prevent layout loops
68
- - **Safety Limits**: Maximum of 15 duplicates to prevent performance issues
69
- - **Development Logging**: Debug information in development mode
53
+ ```tsx
54
+ <Marquee dir="up" speed={80} spacing={12}>
55
+ <div>Item 1</div>
56
+ <div>Item 2</div>
57
+ <div>Item 3</div>
58
+ </Marquee>
59
+ ```
70
60
 
71
- ### Seamless Looping Algorithm
61
+ ### Gradient Overlay
72
62
 
73
- Enhanced duplicate calculation ensures perfect infinite scrolling:
63
+ When `gradient` is enabled, the component detects the nearest non-transparent background color and uses it for the edge fade. You can override the color with `gradientColor`.
74
64
 
75
- - **Smart Target Size**: Intelligently determines the space to fill (width for horizontal, height for vertical)
76
- - **Gap Prevention**: Calculates exact duplicates needed to eliminate visual gaps
77
- - **Performance Optimized**: Minimal DOM elements for maximum performance
65
+ ```tsx
66
+ <Marquee gradient gradientColor="#ffffff">
67
+ <span>Faded edges</span>
68
+ </Marquee>
69
+ ```
78
70
 
79
- ### Orientation-Aware Animations
71
+ ### Pause On Hover
80
72
 
81
- The marquee automatically adapts its animation system based on direction:
73
+ ```tsx
74
+ <Marquee pauseOnHover>
75
+ <span>Hover to pause</span>
76
+ </Marquee>
77
+ ```
82
78
 
83
- - **Horizontal (`left`/`right`)**: Uses `xPercent` for X-axis animations with `flexDirection: row`
84
- - **Vertical (`up`/`down`)**: Uses `yPercent` for Y-axis animations with `flexDirection: column`
85
- - **Smart Gradients**: Gradient overlays automatically position themselves based on scroll direction
86
- - Horizontal: Side gradients (left and right edges)
87
- - Vertical: Top and bottom gradients
79
+ ### Scroll-Follow
88
80
 
89
- ### Interactive Features
81
+ `scrollFollow` changes the marquee timeline speed and direction based on vertical wheel movement.
90
82
 
91
- - **Draggable Support**: Drag to manually control the marquee position
92
- - **Scroll Synchronization**: Link marquee speed to page scroll direction
93
- - **Pause on Hover**: Temporarily stop animation when hovering
94
- - **Inertia Scrolling**: Smooth momentum-based scrolling when dragging (requires GSAP InertiaPlugin)
83
+ ```tsx
84
+ <Marquee scrollFollow scrollSpeed={3}>
85
+ <span>Scroll the page or wheel over the document</span>
86
+ </Marquee>
87
+ ```
95
88
 
96
- ## Examples
89
+ ### Draggable
97
90
 
98
- ### Basic Marquee
91
+ `draggable` lets users drag the marquee track manually. Momentum throwing uses GSAP's `InertiaPlugin`. The package imports the plugin from `gsap/all.js`; if your GSAP setup does not include access to InertiaPlugin, dragging still initializes but momentum behavior may be limited by GSAP availability.
99
92
 
100
93
  ```tsx
101
- <Marquee dir="left" speed={50}>
102
- <span>Scrolling text goes here</span>
94
+ <Marquee draggable pauseOnHover>
95
+ <img src="/image-1.jpg" alt="Gallery image 1" />
96
+ <img src="/image-2.jpg" alt="Gallery image 2" />
97
+ <img src="/image-3.jpg" alt="Gallery image 3" />
103
98
  </Marquee>
104
99
  ```
105
100
 
106
- ### Vertical Marquee with Gradient
101
+ ### Forwarded Ref
102
+
103
+ The component forwards a ref to the root marquee container. Both object refs and callback refs are supported.
107
104
 
108
105
  ```tsx
109
- <Marquee dir="up" speed={80} gradient={true} gradient>
110
- <div>Item 1</div>
111
- <div>Item 2</div>
112
- <div>Item 3</div>
113
- </Marquee>
106
+ import { useRef } from "react";
107
+ import Marquee from "gsap-react-marquee";
108
+
109
+ export function Example() {
110
+ const ref = useRef<HTMLDivElement | null>(null);
111
+
112
+ return (
113
+ <Marquee ref={ref} fill>
114
+ <span>Measured container</span>
115
+ </Marquee>
116
+ );
117
+ }
114
118
  ```
115
119
 
116
- ### Interactive Draggable Marquee
120
+ ## Props
117
121
 
118
- ```tsx
119
- <Marquee dir="right" speed={100} draggable={true} pauseOnHover={true}>
120
- <img src="image1.jpg" alt="1" />
121
- <img src="image2.jpg" alt="2" />
122
- <img src="image3.jpg" alt="3" />
123
- </Marquee>
122
+ | Prop | Type | Default | Description |
123
+ | --- | --- | --- | --- |
124
+ | `children` | `ReactNode` | Required | Content rendered inside each marquee item. |
125
+ | `className` | `string` | `undefined` | Class applied to each `.gsap-react-marquee-content` element. |
126
+ | `dir` | `"left" \| "right" \| "up" \| "down"` | `"left"` | Direction of movement. |
127
+ | `loop` | `number` | `-1` | Number of timeline repeats. `-1` means infinite. |
128
+ | `paused` | `boolean` | `false` | Starts the timeline paused. |
129
+ | `delay` | `number` | `0` | Delay in seconds before the timeline starts. |
130
+ | `speed` | `number` | `100` | Animation speed in pixels per second. |
131
+ | `fill` | `boolean` | `false` | Repeats content enough times to cover the measured marquee area. |
132
+ | `pauseOnHover` | `boolean` | `false` | Pauses on pointer hover and resumes on leave. |
133
+ | `gradient` | `boolean` | `false` | Enables edge gradient overlays. |
134
+ | `gradientColor` | `string` | `undefined` | Explicit gradient color. Overrides automatic background detection. |
135
+ | `spacing` | `number` | `16` | Gap between marquee items, in pixels. |
136
+ | `draggable` | `boolean` | `false` | Enables manual drag control. |
137
+ | `scrollFollow` | `boolean` | `false` | Adjusts timeline speed from wheel/scroll direction. |
138
+ | `scrollSpeed` | `number` | `2.5` | Scroll-follow multiplier. Clamped between `1.1` and `4`. |
139
+
140
+ ## How Sizing Works
141
+
142
+ The component measures the root container and first content item after mount. It then creates enough cloned marquee items for the selected mode and starts a GSAP timeline.
143
+
144
+ In normal mode (`fill={false}`), the component renders one original item plus one clone. This is suitable when your content is already large enough to create a continuous loop.
145
+
146
+ In fill mode (`fill={true}`), the component calculates how many clones are required to cover the measured target size. The duplicate count is capped to prevent excessive DOM growth, and the component re-measures when the container, the first content item, child content, or unloaded images change size.
147
+
148
+ If the container has no reliable defined size, the component falls back to the viewport width or height as its measurement target. This avoids recursive expansion when the marquee is placed inside content-sized layouts.
149
+
150
+ ## Styling
151
+
152
+ The root element receives these classes:
153
+
154
+ ```html
155
+ <div class="gsap-react-marquee-container">
156
+ <div class="gsap-react-marquee">
157
+ <div class="gsap-react-marquee-content">...</div>
158
+ </div>
159
+ </div>
124
160
  ```
125
161
 
126
- ### Scroll-Synced Marquee
162
+ Vertical marquees also receive:
163
+
164
+ ```html
165
+ <div class="gsap-react-marquee-container gsap-react-marquee-vertical">
166
+ ```
167
+
168
+ Use `className` to style the repeated content wrapper:
127
169
 
128
170
  ```tsx
129
- <Marquee dir="left" speed={120} scrollFollow={true} scrollSpeed={3}>
130
- <div>Scroll the page to see the effect</div>
171
+ <Marquee className="items-center gap-4">
172
+ <span>One</span>
173
+ <span>Two</span>
131
174
  </Marquee>
132
175
  ```
133
176
 
134
- ## Changelog
177
+ For predictable measurement, give the marquee or its parent a stable width for horizontal marquees and a stable height for vertical marquees.
178
+
179
+ ## Runtime Notes
180
+
181
+ - The component uses `useLayoutEffect`, `ResizeObserver`, `requestAnimationFrame`, and DOM measurements, so it is intended for client-side rendering.
182
+ - In SSR frameworks such as Next.js, render it from a client component. Add `"use client"` to the file that imports and renders the marquee.
183
+ - Images that are not complete at mount are watched and trigger a re-measure after `load` or `error`.
184
+ - Changing animation props such as `dir`, `speed`, `delay`, `fill`, `draggable`, `spacing`, `loop`, or `paused` re-initializes the GSAP timeline.
185
+
186
+ ## Troubleshooting
187
+
188
+ ### The marquee has gaps
189
+
190
+ Use `fill={true}` for short content, increase `spacing` only as much as needed, and make sure images/fonts have stable dimensions. For image-heavy marquees, set explicit image width and height to reduce layout shifts.
191
+
192
+ ### Vertical marquee does not move correctly
193
+
194
+ Give the container or one of its parents a real height. Vertical mode measures height, not width.
195
+
196
+ ### The marquee expands the page
197
+
198
+ Place it in a container with an explicit width or max width. In fill mode, the component falls back to viewport measurement when it detects content-sized containers, but explicit layout constraints are still more predictable.
199
+
200
+ ### Dragging has no momentum
201
+
202
+ Momentum depends on GSAP `InertiaPlugin` availability. If the plugin is not available in your GSAP installation, dragging can still work without inertia-style throwing.
203
+
204
+ ## Development
205
+
206
+ Install dependencies:
207
+
208
+ ```bash
209
+ pnpm install
210
+ ```
211
+
212
+ Run a TypeScript check:
213
+
214
+ ```bash
215
+ pnpm exec tsc --noEmit
216
+ ```
217
+
218
+ Build the package:
135
219
 
136
- ### v0.3.0
220
+ ```bash
221
+ pnpm run build
222
+ ```
223
+
224
+ Preview the published package contents:
137
225
 
138
- - 🎨 **BREAKING**: Removed `alignVertical` prop - vertical marquees now use native flex-column layout
139
- - Added proper Y-axis animations for vertical directions (`up`/`down`)
140
- - 🎨 Smart gradient overlays that auto-adapt to marquee orientation
141
- - 🔧 Refactored animation engine to support both X and Y axis seamlessly
142
- - 📊 Improved dimension calculations for vertical marquees
226
+ ```bash
227
+ npm pack --dry-run
228
+ ```
143
229
 
144
- ### v0.2.4
230
+ ## License
145
231
 
146
- - ✨ Added intelligent container detection to prevent recursive expansion
147
- - 🚀 Enhanced duplicate calculation algorithm for better performance
148
- - 🔧 Improved seamless looping with smarter target width calculation
149
- - 📝 Added comprehensive debug logging for development
150
- - 🛡️ Added safety limits to prevent extreme duplicate scenarios
232
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),t=require("@gsap/react"),r=require("gsap"),a=require("gsap/all.js"),n=require("react"),s=require("clsx"),o=require("tailwind-merge");!function(e,t){void 0===t&&(t={});var r=t.insertAt;if("undefined"!=typeof document){var a=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style");n.type="text/css","top"===r&&a.firstChild?a.insertBefore(n,a.firstChild):a.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e))}}('.gsap-react-marquee-container{display:flex;overflow:hidden;position:relative;white-space:nowrap;width:100%}.gsap-react-marquee-container:after{background:linear-gradient(270deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);left:0}.gsap-react-marquee-container:after,.gsap-react-marquee-container:before{content:"";height:100%;pointer-events:none;position:absolute;top:0;width:15%;z-index:10}.gsap-react-marquee-container:before{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);right:0}.gsap-react-marquee-vertical:after{background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;top:60%;width:100%}.gsap-react-marquee-vertical:before{background:linear-gradient(1turn,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;right:auto;top:0;width:100%}.gsap-react-marquee{flex:1;height:max-content;width:auto}.gsap-react-marquee,.gsap-react-marquee-content{display:flex;line-height:100%;white-space:nowrap}.gsap-react-marquee-content{overflow:hidden;width:max-content}');const i=new Set(["","auto","fit-content","min-content","max-content","-moz-fit-content","-webkit-fit-content"]),l=(...e)=>o.twMerge(s.clsx(e)),c=e=>{let t=e;for(;t;){const e=window.getComputedStyle(t).backgroundColor;if(e&&"rgba(0, 0, 0, 0)"!==e&&"transparent"!==e)return e;t=t.parentElement}return"transparent"},u=(e,t,a,n,s)=>{const{spacing:o=16}=s;r.gsap.set(e,{gap:`${o}px`,flexDirection:n?"column":"row"}),r.gsap.set(t,{gap:`${o}px`}),r.gsap.set(a,{overflow:n?"visible":"hidden"})},p=(e,t)=>{const r=e.style[t];if(r)return!i.has(r);const a=window.getComputedStyle(e)[t];if(i.has(a))return!1;const n=e.parentElement;if(!n)return!0;const s=window.getComputedStyle(n)[t];return!("100%"===a&&i.has(s))},d=(e,t)=>p(e,t?"height":"width")?t?e.offsetHeight:e.offsetWidth:t?window.innerHeight:window.innerWidth,g=d,f=(e,t,r)=>{const{fill:a=!1}=r;if(!a||e<=0||t<=0)return 1;const n=e<t?Math.ceil(t/e):1;return Math.min(n,15)},m=f,h=(e,t,r)=>{const{fill:a=!1}=r;return a?"auto":e<=t?"100%":`${e}px`},v=h,w=(e,t,n,s,o,i,l)=>{const{spacing:c=16,speed:u=100,delay:p=0,paused:d=!1,draggable:g=!1}=l,f=e.length-1;if(f<0)return;const m=[],h=[],v=i?"yPercent":"xPercent",w=i?"y":"x",x=i?"height":"width";r.gsap.set(e,{[v]:(e,t)=>{const a=parseFloat(String(r.gsap.getProperty(t,x,"px"))),n=parseFloat(String(r.gsap.getProperty(t,w,"px"))),s=Number(r.gsap.getProperty(t,v));return m[e]=a,h[e]=n/a*100+s,h[e]}}),r.gsap.set(e,{[w]:0});const y=e[f],q=i?y.offsetTop:y.offsetLeft,b=i?y.offsetHeight:y.offsetWidth,S=q+h[f]/100*m[f]-t+b+c;let C,E,T,k;e.forEach((e,r)=>{const a=m[r],s=h[r]/100*a,o=(i?e.offsetTop:e.offsetLeft)+s-t+a;n.to(e,{[v]:(s-o)/a*100,duration:o/u},0).fromTo(e,{[v]:(s-o+S)/a*100},{[v]:h[r],duration:(S-o)/u,immediateRender:!1},o/u)}),n.delay(p);const A=()=>r.gsap.delayedCall(p,()=>{n.reverse(),n.eventCallback("onReverseComplete",()=>{n.totalTime(n.rawTime()+100*n.duration())})});if(s){if(d)return void n.pause();n.progress(1).pause(),C=A()}if("function"==typeof a.Draggable&&g){const e=document.createElement("div");k=e;const t=r.gsap.utils.wrap(0,1);let l,c;const u=()=>{if(!T)return;const e=i?T.startY-T.y:T.startX-T.x;n.progress(t(c+e*l))};a.InertiaPlugin,T=a.Draggable.create(e,{trigger:o,type:i?"y":"x",onPress(){r.gsap.killTweensOf(n),n.pause(),c=n.progress(),l=1/S,r.gsap.set(e,{[w]:c/-l})},onDrag:u,onThrowUpdate:u,overshootTolerance:0,inertia:!0,onThrowComplete(){s?d?n.pause():(n.progress(n.progress()).pause(),null==E||E.kill(),E=A()):n.play()}})[0]}return()=>{null==C||C.kill(),null==E||E.kill(),null==T||T.kill(),null==k||k.remove()}},x=w;r.gsap.registerPlugin(t.useGSAP,a.Observer,a.InertiaPlugin,a.Draggable);const y=n.forwardRef((s,o)=>{var i;const{children:p,className:g,dir:m="left",loop:v=-1,paused:x=!1,delay:y=0,fill:q=!1,scrollFollow:b=!1,scrollSpeed:S=2.5,gradient:C=!1,gradientColor:E=null,pauseOnHover:T=!1,spacing:k=16,speed:A=100,draggable:L=!1}=s,P=n.useRef(null),M=n.useRef(null),[N,W]=n.useState(1),[O,R]=n.useState(null),[j,D]=n.useState(0),H=n.useCallback(e=>{P.current=e,"function"!=typeof o?o&&(o.current=e):o(e)},[o]);n.useLayoutEffect(()=>{if(!C||!P.current)return;const e=c(P.current);R(e)},[C]);const z="up"===m||"down"===m,F="down"===m||"right"===m;n.useLayoutEffect(()=>{const e=P.current;if(!e)return;const t=e.querySelector(".gsap-react-marquee .gsap-react-marquee-content");let r=null;const a=()=>{null==r&&(r=requestAnimationFrame(()=>{D(e=>e+1),r=null}))},n="undefined"!=typeof ResizeObserver?new ResizeObserver(a):null;n&&(n.observe(e),t&&n.observe(t));const s=Array.from(e.querySelectorAll("img")),o=()=>a();return s.forEach(e=>{e.complete||(e.addEventListener("load",o),e.addEventListener("error",o))}),()=>{null==n||n.disconnect(),s.forEach(e=>{e.removeEventListener("load",o),e.removeEventListener("error",o)}),null!=r&&cancelAnimationFrame(r)}},[p,g]),t.useGSAP((e,t)=>{if(!M.current||!P.current||!t)return;const n=P.current,s={fill:q,spacing:k,speed:A,delay:y,paused:x,draggable:L},o=r.gsap.utils.toArray(n.querySelectorAll(".gsap-react-marquee")),i=r.gsap.utils.toArray(n.querySelectorAll(".gsap-react-marquee .gsap-react-marquee-content"));if(!i.length)return;u(n,o,i,z,s);const l=z?n.offsetHeight:n.offsetWidth,c=z?i[0].offsetHeight:i[0].offsetWidth,p=d(n,z),g=z?i[0].offsetTop:i[0].offsetLeft;let m=null;const C=Math.min(4,Math.max(1.1,S)),E=f(c,p,s);if(N!==E)return void W(E);const O=r.gsap.timeline({paused:x,repeat:v,defaults:{ease:"none"},onReverseComplete(){O.totalTime(O.rawTime()+100*O.duration())}}),R=o.map(e=>z?e.offsetHeight:e.offsetWidth).reduce((e,t)=>e+t,0),j=h(q?0:R/2,l,s);r.gsap.set(o,{[z?"minHeight":"minWidth"]:j,flex:q?"0 0 auto":"1"});const D=w(q?i:o,g,O,F,o,z,s);b&&(m=a.Observer.create({onChangeY(e){let t=C*(F?-1:1);e.deltaY<0&&(t*=-1),r.gsap.timeline({defaults:{ease:"none"}}).to(O,{timeScale:t*C,duration:.2,overwrite:!0}).to(O,{timeScale:t/C,duration:1},"+=0.3")}}));const H=t(()=>{O.pause()}),B=t(()=>{F?O.reverse():O.play()});return T&&(n.addEventListener("mouseenter",H),n.addEventListener("mouseleave",B)),()=>{n.removeEventListener("mouseenter",H),n.removeEventListener("mouseleave",B),r.gsap.killTweensOf(O),O.kill(),null==m||m.kill(),null==D||D()}},{dependencies:[N,m,v,x,y,q,b,S,T,k,A,L,g,p,j],revertOnUpdate:!0});const B=null!==(i=null!=E?E:C?O:null)&&void 0!==i?i:"transparent",G=n.useMemo(()=>!Number.isFinite(N)||N<=0?null:Array.from({length:N},(t,r)=>e.jsx("div",{className:l("gsap-react-marquee"),children:e.jsx("div",{className:l("gsap-react-marquee-content",g),children:p})},r)),[N,g,p]);return e.jsxs("div",{ref:H,style:{"--gradient-color":B},className:l("gsap-react-marquee-container",{"gsap-react-marquee-vertical":z}),children:[e.jsx("div",{ref:M,className:l("gsap-react-marquee"),children:e.jsx("div",{className:l("gsap-react-marquee-content",g),children:p})}),G]})});y.displayName="GSAPReactMarquee",exports.calculateDuplicateCount=f,exports.calculateDuplicates=m,exports.cn=l,exports.coreAnimation=x,exports.createMarqueeAnimation=w,exports.default=y,exports.getEffectiveBackgroundColor=c,exports.getMinSize=h,exports.getMinWidth=v,exports.getTargetSize=d,exports.getTargetWidth=g,exports.hasDefinedWidth=e=>p(e,"width"),exports.setupContainerStyles=u;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { ClassValue } from 'clsx';
4
+ import { gsap } from 'gsap';
4
5
 
5
6
  type GSAPReactMarqueeProps = {
6
7
  children: ReactNode;
@@ -22,14 +23,19 @@ type GSAPReactMarqueeProps = {
22
23
 
23
24
  declare const GSAPReactMarquee: react.ForwardRefExoticComponent<GSAPReactMarqueeProps & react.RefAttributes<HTMLDivElement>>;
24
25
 
26
+ type GSAPTimeline = ReturnType<typeof gsap.timeline>;
25
27
  declare const cn: (...inputs: ClassValue[]) => string;
26
28
  declare const getEffectiveBackgroundColor: (el: HTMLElement) => string;
27
- declare const setupContainerStyles: (containerMarquee: HTMLElement, marquees: HTMLElement[], marqueesChildren: HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => void;
29
+ declare const setupContainerStyles: (containerElement: HTMLElement, marqueeElements: HTMLElement[], contentElements: HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => void;
28
30
  declare const hasDefinedWidth: (element: HTMLElement) => boolean;
31
+ declare const getTargetSize: (containerElement: HTMLElement, isVertical: boolean) => number;
29
32
  declare const getTargetWidth: (containerElement: HTMLElement, isVertical: boolean) => number;
30
- declare const calculateDuplicates: (marqueeChildrenWidth: number, containerMarqueeWidth: number, props: GSAPReactMarqueeProps) => number;
31
- declare const getMinWidth: (totalSize: number, containerSize: number, props: GSAPReactMarqueeProps) => string | number;
32
- declare const coreAnimation: (elementsToAnimate: HTMLElement[], startPos: number, tl: gsap.core.Timeline, isReverse: boolean, draggableTrigger: HTMLElement | HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => void;
33
+ declare const calculateDuplicateCount: (contentSize: number, targetSize: number, props: GSAPReactMarqueeProps) => number;
34
+ declare const calculateDuplicates: (contentSize: number, targetSize: number, props: GSAPReactMarqueeProps) => number;
35
+ declare const getMinSize: (itemSize: number, containerSize: number, props: GSAPReactMarqueeProps) => string | number;
36
+ declare const getMinWidth: (itemSize: number, containerSize: number, props: GSAPReactMarqueeProps) => string | number;
37
+ declare const createMarqueeAnimation: (items: HTMLElement[], startPosition: number, timeline: GSAPTimeline, isReverse: boolean, dragTrigger: HTMLElement | HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => (() => void) | undefined;
38
+ declare const coreAnimation: (items: HTMLElement[], startPosition: number, timeline: GSAPTimeline, isReverse: boolean, dragTrigger: HTMLElement | HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => (() => void) | undefined;
33
39
 
34
- export { calculateDuplicates, cn, coreAnimation, GSAPReactMarquee as default, getEffectiveBackgroundColor, getMinWidth, getTargetWidth, hasDefinedWidth, setupContainerStyles };
40
+ export { calculateDuplicateCount, calculateDuplicates, cn, coreAnimation, createMarqueeAnimation, GSAPReactMarquee as default, getEffectiveBackgroundColor, getMinSize, getMinWidth, getTargetSize, getTargetWidth, hasDefinedWidth, setupContainerStyles };
35
41
  export type { GSAPReactMarqueeProps };
package/dist/index.esm.js CHANGED
@@ -1 +1 @@
1
- import e,{forwardRef as t,useRef as r,useState as n,useLayoutEffect as o,useMemo as a}from"react";import{useGSAP as i}from"@gsap/react";import l from"gsap";import{Draggable as s,InertiaPlugin as c,Observer as u}from"gsap/all";import{clsx as f}from"clsx";import{twMerge as p}from"tailwind-merge";var d,m,y={exports:{}},g={},v={};"production"===process.env.NODE_ENV?y.exports=function(){if(d)return g;d=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function r(t,r,n){var o=null;if(void 0!==n&&(o=""+n),void 0!==r.key&&(o=""+r.key),"key"in r)for(var a in n={},r)"key"!==a&&(n[a]=r[a]);else n=r;return r=n.ref,{$$typeof:e,type:t,key:o,ref:void 0!==r?r:null,props:n}}return g.Fragment=t,g.jsx=r,g.jsxs=r,g}():y.exports=(m||(m=1,"production"!==process.env.NODE_ENV&&function(){function t(e){if(null==e)return null;if("function"==typeof e)return e.$$typeof===O?null:e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case d:return"Fragment";case y:return"Profiler";case m:return"StrictMode";case w:return"Suspense";case S:return"SuspenseList";case _:return"Activity"}if("object"==typeof e)switch(e.tag,e.$$typeof){case p:return"Portal";case h:return(e.displayName||"Context")+".Provider";case g:return(e._context.displayName||"Context")+".Consumer";case b:var r=e.render;return(e=e.displayName)||(e=""!==(e=r.displayName||r.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case k:return null!==(r=e.displayName||null)?r:t(e.type)||"Memo";case x:r=e._payload,e=e._init;try{return t(e(r))}catch(e){}}return null}function r(e){return""+e}function n(e){try{r(e);var t=!1}catch(e){t=!0}if(t){var n=(t=console).error,o="function"==typeof Symbol&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",o),r(e)}}function o(e){if(e===d)return"<>";if("object"==typeof e&&null!==e&&e.$$typeof===x)return"<...>";try{var r=t(e);return r?"<"+r+">":"<...>"}catch(e){return"<...>"}}function a(){return Error("react-stack-top-frame")}function i(){var e=t(this.type);return q[e]||(q[e]=!0),void 0!==(e=this.props.ref)?e:null}function l(e,r,o,a,l,u,p,d){var m,y=r.children;if(void 0!==y)if(a){if(N(y)){for(a=0;a<y.length;a++)s(y[a]);Object.freeze&&Object.freeze(y)}}else s(y);if(E.call(r,"key")){y=t(e);var g=Object.keys(r).filter(function(e){return"key"!==e});a=0<g.length?"{key: someKey, "+g.join(": ..., ")+": ...}":"{key: someKey}",A[y+a]||(g=0<g.length?"{"+g.join(": ..., ")+": ...}":"{}",A[y+a]=!0)}if(y=null,void 0!==o&&(n(o),y=""+o),function(e){if(E.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return void 0!==e.key}(r)&&(n(r.key),y=""+r.key),"key"in r)for(var v in o={},r)"key"!==v&&(o[v]=r[v]);else o=r;return y&&function(e){function t(){c||(c=!0)}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}(o,"function"==typeof e&&(e.displayName||e.name)),function(e,t,r,n,o,a,l,s){return r=a.ref,e={$$typeof:f,type:e,key:t,props:a,_owner:o},null!==(void 0!==r?r:null)?Object.defineProperty(e,"ref",{enumerable:!1,get:i}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:l}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:s}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}(e,y,u,0,null===(m=j.A)?null:m.getOwner(),o,p,d)}function s(e){"object"==typeof e&&null!==e&&e.$$typeof===f&&e._store&&(e._store.validated=1)}var c,u=e,f=Symbol.for("react.transitional.element"),p=Symbol.for("react.portal"),d=Symbol.for("react.fragment"),m=Symbol.for("react.strict_mode"),y=Symbol.for("react.profiler"),g=Symbol.for("react.consumer"),h=Symbol.for("react.context"),b=Symbol.for("react.forward_ref"),w=Symbol.for("react.suspense"),S=Symbol.for("react.suspense_list"),k=Symbol.for("react.memo"),x=Symbol.for("react.lazy"),_=Symbol.for("react.activity"),O=Symbol.for("react.client.reference"),j=u.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,E=Object.prototype.hasOwnProperty,N=Array.isArray,T=console.createTask?console.createTask:function(){return null},q={},C=(u={react_stack_bottom_frame:function(e){return e()}}).react_stack_bottom_frame.bind(u,a)(),P=T(o(a)),A={};v.Fragment=d,v.jsx=function(e,t,r,n,a){var i=1e4>j.recentlyCreatedOwnerStacks++;return l(e,t,r,!1,0,a,i?Error("react-stack-top-frame"):C,i?T(o(e)):P)},v.jsxs=function(e,t,r,n,a){var i=1e4>j.recentlyCreatedOwnerStacks++;return l(e,t,r,!0,0,a,i?Error("react-stack-top-frame"):C,i?T(o(e)):P)}}()),v);var h=y.exports;!function(e,t){void 0===t&&(t={});var r=t.insertAt;if("undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css","top"===r&&n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}('.gsap-react-marquee-container{display:flex;overflow:hidden;position:relative;white-space:preserve nowrap;width:100%}.gsap-react-marquee-container:after{background:linear-gradient(270deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);left:0}.gsap-react-marquee-container:after,.gsap-react-marquee-container:before{content:"";height:100%;pointer-events:none;position:absolute;top:0;width:15%;z-index:10}.gsap-react-marquee-container:before{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);right:0}.gsap-react-marquee-vertical:after{background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;top:60%;width:100%}.gsap-react-marquee-vertical:before{background:linear-gradient(1turn,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;right:auto;top:0;width:100%}.gsap-react-marquee{flex:1;height:max-content;width:auto}.gsap-react-marquee,.gsap-react-marquee-content{display:flex;line-height:100%;white-space:preserve nowrap}.gsap-react-marquee-content{overflow:hidden;width:max-content}');const b=(...e)=>p(f(e)),w=e=>{let t=e;for(;t;){const e=window.getComputedStyle(t).backgroundColor;if(e&&"rgba(0, 0, 0, 0)"!==e&&"transparent"!==e)return e;t=t.parentElement}return"transparent"},S=(e,t,r,n,o)=>{const{spacing:a=16}=o;l.set(e,{gap:`${a}px`,flexDirection:n?"column":"row"}),l.set(t,{gap:`${a}px`}),n&&l.set(r,{overflow:"visible"})},k=e=>{if(e.style.width&&"auto"!==e.style.width)return!0;const t=window.getComputedStyle(e).width;if("auto"===t||!t)return!1;const r=e.parentElement;if(r){const e=window.getComputedStyle(r);if("100%"===t&&"auto"===e.width)return!1}return!0},x=(e,t)=>k(e)?t?e.offsetHeight:e.offsetWidth:t?window.innerHeight:window.innerWidth,_=(e,t,r)=>r.fill&&e<t?Math.ceil(t/e):1,O=(e,t,r)=>{const{fill:n=!1}=r;return n?"auto":e<t?"100%":e>t?`${e}px`:`${t}px`},j=(e,t,r,n,o,a,i)=>{const{spacing:c=16,speed:u=100,delay:f=0,paused:p=!1}=i,d=[],m=[],y=e.length-1,g=a?"yPercent":"xPercent",v=a?"y":"x",h=a?"height":"width";l.set(e,{[g]:(e,t)=>{const r=d[e]=parseFloat(String(l.getProperty(t,h,"px")));return m[e]=parseFloat(String(l.getProperty(t,v,"px")))/r*100+Number(l.getProperty(t,g)),m[e]}}),l.set(e,{[v]:0});const b=e[y],w=a?b.offsetTop:b.offsetLeft,S=a?b.offsetHeight:b.offsetWidth,k=w+m[y]/100*d[y]-t+S+c;if(e.forEach((e,n)=>{const o=m[n]/100*d[n],i=(a?e.offsetTop:e.offsetLeft)+o-t+d[n];r.to(e,{[g]:(o-i)/d[n]*100,duration:i/u},0).fromTo(e,{[g]:(o-i+k)/d[n]*100},{[g]:m[n],duration:(o-i+k-o)/u,immediateRender:!1},i/u)}),r.delay(f),n){if(p)return void r.pause();r.progress(1).pause(),l.delayedCall(f,()=>{r.reverse(),r.eventCallback("onReverseComplete",()=>{r.totalTime(r.rawTime()+100*r.duration())})})}let x;if("function"==typeof s&&i.draggable){x=document.createElement("div");const e=l.utils.wrap(0,1);let t,i;const c=()=>{const n=a?u.startY-u.y:u.startX-u.x;r.progress(e(i+n*t))},u=s.create(x,{trigger:o,type:a?"y":"x",onPress(){l.killTweensOf(r),r.pause(),i=r.progress(),t=1/k,l.set(x,{[v]:i/-t})},onDrag:c,onThrowUpdate:c,overshootTolerance:0,inertia:!0,onThrowComplete:()=>{if(n){if(p)return void r.pause();r.progress(r.progress()).pause(),l.delayedCall(f,()=>{r.reverse(),r.eventCallback("onReverseComplete",()=>{r.totalTime(r.rawTime()+100*r.duration())})})}else r.play()}})[0]}};l.registerPlugin(i,u,c,s);const E=t((e,t)=>{const{children:s,className:c,dir:f="left",loop:p=-1,paused:d=!1,fill:m=!1,scrollFollow:y=!1,scrollSpeed:g=2.5,gradient:v=!1,gradientColor:k=null,pauseOnHover:x=!1,spacing:E=16,speed:N=100}=e,T=r(null),q=t||T,C=r(null),[P,A]=n(1),[$,R]=n(null),[L,F]=n(0);o(()=>{if(!v||!(null==q?void 0:q.current))return;const e=w(q.current);R(e)},[v]);const W="up"===f||"down"===f,H="down"===f||"right"===f;o(()=>{const e=q.current;if(!e)return;const t=e.querySelector(".gsap-react-marquee .gsap-react-marquee-content");let r=null;const n=()=>{null==r&&(r=requestAnimationFrame(()=>{F(e=>e+1),r=null}))},o=t?new ResizeObserver(n):null;t&&o&&o.observe(t);const a=Array.from(e.querySelectorAll("img")),i=()=>n();return a.forEach(e=>{e.complete||(e.addEventListener("load",i),e.addEventListener("error",i))}),()=>{null==o||o.disconnect(),a.forEach(e=>{e.removeEventListener("load",i),e.removeEventListener("error",i)}),null!=r&&cancelAnimationFrame(r)}},[s]),i((t,r)=>{if(!(null==C?void 0:C.current)||!q.current||!r)return;const n=null==q?void 0:q.current,o=l.utils.toArray(n.querySelectorAll(".gsap-react-marquee")),a=l.utils.toArray(n.querySelectorAll(".gsap-react-marquee .gsap-react-marquee-content"));if(!C.current||!a)return;const i=l.timeline({paused:d,repeat:p,defaults:{ease:"none"},onReverseComplete(){i.totalTime(i.rawTime()+100*i.duration())}});S(n,o,a,W,e);const s=W?n.offsetHeight:n.offsetWidth,c=W?a[0].offsetHeight:a[0].offsetWidth,f=W?a[0].offsetTop:a[0].offsetLeft;let v=null;const h=Math.min(4,Math.max(1.1,g));A(_(c,s,e));const b=l.utils.toArray(o).map(e=>W?e.offsetHeight:e.offsetWidth).reduce((e,t)=>e+t,0),w=O(b/(1===P?2:P),s,e);l.set(o,{[W?"minHeight":"minWidth"]:w,flex:m?"0 0 auto":"1"}),j(m?a:o,f,i,H,o,W,e),y&&(v=u.create({onChangeY(e){let t=h*(H?-1:1);e.deltaY<0&&(t*=-1),l.timeline({defaults:{ease:"none"}}).to(i,{timeScale:t*h,duration:.2,overwrite:!0}).to(i,{timeScale:t/h,duration:1},"+=0.3")}}));const k=r(()=>{i.pause()}),E=r(()=>{H?i.reverse():i.play()});return x&&(n.addEventListener("mouseenter",k),n.addEventListener("mouseleave",E)),()=>{n.removeEventListener("mouseenter",k),n.removeEventListener("mouseleave",E),i.kill(),null==v||v.kill()}},{dependencies:[P,f,p,d,m,y,g,v,k,x,E,N,s,L],revertOnUpdate:!0});const z=a(()=>!Number.isFinite(P)||P<=0?null:Array.from({length:P},(e,t)=>h.jsx("div",{className:b("gsap-react-marquee"),children:h.jsx("div",{className:b("gsap-react-marquee-content",c),children:s})},t)),[P,c,s]);return h.jsxs("div",{ref:q,style:{"--gradient-color":k||(v&&$?$:"transparent")},className:b("gsap-react-marquee-container",{"gsap-react-marquee-vertical":W}),children:[h.jsx("div",{ref:C,className:b("gsap-react-marquee"),children:h.jsx("div",{className:b("gsap-react-marquee-content",c),children:s})}),z]})});E.displayName="GSAPReactMarquee";export{_ as calculateDuplicates,b as cn,j as coreAnimation,E as default,w as getEffectiveBackgroundColor,O as getMinWidth,x as getTargetWidth,k as hasDefinedWidth,S as setupContainerStyles};
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useGSAP as r}from"@gsap/react";import{gsap as n}from"gsap";import{Draggable as a,InertiaPlugin as o,Observer as i}from"gsap/all.js";import{forwardRef as l,useRef as s,useState as c,useCallback as u,useLayoutEffect as d,useMemo as p}from"react";import{clsx as f}from"clsx";import{twMerge as m}from"tailwind-merge";!function(e,t){void 0===t&&(t={});var r=t.insertAt;if("undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===r&&n.firstChild?n.insertBefore(a,n.firstChild):n.appendChild(a),a.styleSheet?a.styleSheet.cssText=e:a.appendChild(document.createTextNode(e))}}('.gsap-react-marquee-container{display:flex;overflow:hidden;position:relative;white-space:nowrap;width:100%}.gsap-react-marquee-container:after{background:linear-gradient(270deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);left:0}.gsap-react-marquee-container:after,.gsap-react-marquee-container:before{content:"";height:100%;pointer-events:none;position:absolute;top:0;width:15%;z-index:10}.gsap-react-marquee-container:before{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);right:0}.gsap-react-marquee-vertical:after{background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;top:60%;width:100%}.gsap-react-marquee-vertical:before{background:linear-gradient(1turn,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;right:auto;top:0;width:100%}.gsap-react-marquee{flex:1;height:max-content;width:auto}.gsap-react-marquee,.gsap-react-marquee-content{display:flex;line-height:100%;white-space:nowrap}.gsap-react-marquee-content{overflow:hidden;width:max-content}');const g=new Set(["","auto","fit-content","min-content","max-content","-moz-fit-content","-webkit-fit-content"]),h=(...e)=>m(f(e)),v=e=>{let t=e;for(;t;){const e=window.getComputedStyle(t).backgroundColor;if(e&&"rgba(0, 0, 0, 0)"!==e&&"transparent"!==e)return e;t=t.parentElement}return"transparent"},w=(e,t,r,a,o)=>{const{spacing:i=16}=o;n.set(e,{gap:`${i}px`,flexDirection:a?"column":"row"}),n.set(t,{gap:`${i}px`}),n.set(r,{overflow:a?"visible":"hidden"})},y=(e,t)=>{const r=e.style[t];if(r)return!g.has(r);const n=window.getComputedStyle(e)[t];if(g.has(n))return!1;const a=e.parentElement;if(!a)return!0;const o=window.getComputedStyle(a)[t];return!("100%"===n&&g.has(o))},q=e=>y(e,"width"),x=(e,t)=>y(e,t?"height":"width")?t?e.offsetHeight:e.offsetWidth:t?window.innerHeight:window.innerWidth,b=x,E=(e,t,r)=>{const{fill:n=!1}=r;if(!n||e<=0||t<=0)return 1;const a=e<t?Math.ceil(t/e):1;return Math.min(a,15)},S=E,T=(e,t,r)=>{const{fill:n=!1}=r;return n?"auto":e<=t?"100%":`${e}px`},k=T,C=(e,t,r,o,i,l,s)=>{const{spacing:c=16,speed:u=100,delay:d=0,paused:p=!1,draggable:f=!1}=s,m=e.length-1;if(m<0)return;const g=[],h=[],v=l?"yPercent":"xPercent",w=l?"y":"x",y=l?"height":"width";n.set(e,{[v]:(e,t)=>{const r=parseFloat(String(n.getProperty(t,y,"px"))),a=parseFloat(String(n.getProperty(t,w,"px"))),o=Number(n.getProperty(t,v));return g[e]=r,h[e]=a/r*100+o,h[e]}}),n.set(e,{[w]:0});const q=e[m],x=l?q.offsetTop:q.offsetLeft,b=l?q.offsetHeight:q.offsetWidth,E=x+h[m]/100*g[m]-t+b+c;let S,T,k,C;e.forEach((e,n)=>{const a=g[n],o=h[n]/100*a,i=(l?e.offsetTop:e.offsetLeft)+o-t+a;r.to(e,{[v]:(o-i)/a*100,duration:i/u},0).fromTo(e,{[v]:(o-i+E)/a*100},{[v]:h[n],duration:(E-i)/u,immediateRender:!1},i/u)}),r.delay(d);const A=()=>n.delayedCall(d,()=>{r.reverse(),r.eventCallback("onReverseComplete",()=>{r.totalTime(r.rawTime()+100*r.duration())})});if(o){if(p)return void r.pause();r.progress(1).pause(),S=A()}if("function"==typeof a&&f){const e=document.createElement("div");C=e;const t=n.utils.wrap(0,1);let s,c;const u=()=>{if(!k)return;const e=l?k.startY-k.y:k.startX-k.x;r.progress(t(c+e*s))};k=a.create(e,{trigger:i,type:l?"y":"x",onPress(){n.killTweensOf(r),r.pause(),c=r.progress(),s=1/E,n.set(e,{[w]:c/-s})},onDrag:u,onThrowUpdate:u,overshootTolerance:0,inertia:!0,onThrowComplete(){o?p?r.pause():(r.progress(r.progress()).pause(),null==T||T.kill(),T=A()):r.play()}})[0]}return()=>{null==S||S.kill(),null==T||T.kill(),null==k||k.kill(),null==C||C.remove()}},A=C;n.registerPlugin(r,i,o,a);const L=l((a,o)=>{var l;const{children:f,className:m,dir:g="left",loop:y=-1,paused:q=!1,delay:b=0,fill:S=!1,scrollFollow:k=!1,scrollSpeed:A=2.5,gradient:L=!1,gradientColor:N=null,pauseOnHover:H=!1,spacing:P=16,speed:W=100,draggable:F=!1}=a,O=s(null),R=s(null),[M,z]=c(1),[Y,$]=c(null),[j,B]=c(0),D=u(e=>{O.current=e,"function"!=typeof o?o&&(o.current=e):o(e)},[o]);d(()=>{if(!L||!O.current)return;const e=v(O.current);$(e)},[L]);const U="up"===g||"down"===g,G="down"===g||"right"===g;d(()=>{const e=O.current;if(!e)return;const t=e.querySelector(".gsap-react-marquee .gsap-react-marquee-content");let r=null;const n=()=>{null==r&&(r=requestAnimationFrame(()=>{B(e=>e+1),r=null}))},a="undefined"!=typeof ResizeObserver?new ResizeObserver(n):null;a&&(a.observe(e),t&&a.observe(t));const o=Array.from(e.querySelectorAll("img")),i=()=>n();return o.forEach(e=>{e.complete||(e.addEventListener("load",i),e.addEventListener("error",i))}),()=>{null==a||a.disconnect(),o.forEach(e=>{e.removeEventListener("load",i),e.removeEventListener("error",i)}),null!=r&&cancelAnimationFrame(r)}},[f,m]),r((e,t)=>{if(!R.current||!O.current||!t)return;const r=O.current,a={fill:S,spacing:P,speed:W,delay:b,paused:q,draggable:F},o=n.utils.toArray(r.querySelectorAll(".gsap-react-marquee")),l=n.utils.toArray(r.querySelectorAll(".gsap-react-marquee .gsap-react-marquee-content"));if(!l.length)return;w(r,o,l,U,a);const s=U?r.offsetHeight:r.offsetWidth,c=U?l[0].offsetHeight:l[0].offsetWidth,u=x(r,U),d=U?l[0].offsetTop:l[0].offsetLeft;let p=null;const f=Math.min(4,Math.max(1.1,A)),m=E(c,u,a);if(M!==m)return void z(m);const g=n.timeline({paused:q,repeat:y,defaults:{ease:"none"},onReverseComplete(){g.totalTime(g.rawTime()+100*g.duration())}}),h=o.map(e=>U?e.offsetHeight:e.offsetWidth).reduce((e,t)=>e+t,0),v=T(S?0:h/2,s,a);n.set(o,{[U?"minHeight":"minWidth"]:v,flex:S?"0 0 auto":"1"});const L=C(S?l:o,d,g,G,o,U,a);k&&(p=i.create({onChangeY(e){let t=f*(G?-1:1);e.deltaY<0&&(t*=-1),n.timeline({defaults:{ease:"none"}}).to(g,{timeScale:t*f,duration:.2,overwrite:!0}).to(g,{timeScale:t/f,duration:1},"+=0.3")}}));const N=t(()=>{g.pause()}),Y=t(()=>{G?g.reverse():g.play()});return H&&(r.addEventListener("mouseenter",N),r.addEventListener("mouseleave",Y)),()=>{r.removeEventListener("mouseenter",N),r.removeEventListener("mouseleave",Y),n.killTweensOf(g),g.kill(),null==p||p.kill(),null==L||L()}},{dependencies:[M,g,y,q,b,S,k,A,H,P,W,F,m,f,j],revertOnUpdate:!0});const X=null!==(l=null!=N?N:L?Y:null)&&void 0!==l?l:"transparent",I=p(()=>!Number.isFinite(M)||M<=0?null:Array.from({length:M},(t,r)=>e("div",{className:h("gsap-react-marquee"),children:e("div",{className:h("gsap-react-marquee-content",m),children:f})},r)),[M,m,f]);return t("div",{ref:D,style:{"--gradient-color":X},className:h("gsap-react-marquee-container",{"gsap-react-marquee-vertical":U}),children:[e("div",{ref:R,className:h("gsap-react-marquee"),children:e("div",{className:h("gsap-react-marquee-content",m),children:f})}),I]})});L.displayName="GSAPReactMarquee";export{E as calculateDuplicateCount,S as calculateDuplicates,h as cn,A as coreAnimation,C as createMarqueeAnimation,L as default,v as getEffectiveBackgroundColor,T as getMinSize,k as getMinWidth,x as getTargetSize,b as getTargetWidth,q as hasDefinedWidth,w as setupContainerStyles};
package/package.json CHANGED
@@ -3,20 +3,22 @@
3
3
  "author": "David Domenico Piscopo",
4
4
  "description": "A high-performance React marquee component powered by GSAP",
5
5
  "license": "MIT",
6
- "version": "0.3.1",
6
+ "version": "0.3.2",
7
7
  "type": "module",
8
- "main": "dist/index.cjs.js",
8
+ "main": "dist/index.cjs",
9
9
  "module": "dist/index.esm.js",
10
10
  "types": "dist/index.d.ts",
11
11
  "exports": {
12
12
  ".": {
13
13
  "import": "./dist/index.esm.js",
14
- "require": "./dist/index.cjs.js",
14
+ "require": "./dist/index.cjs",
15
15
  "types": "./dist/index.d.ts"
16
16
  }
17
17
  },
18
18
  "files": [
19
- "dist",
19
+ "dist/index.cjs",
20
+ "dist/index.esm.js",
21
+ "dist/index.d.ts",
20
22
  "README.md",
21
23
  "LICENSE"
22
24
  ],
@@ -45,28 +47,26 @@
45
47
  "homepage": "https://gsap-react-marquee-docs.vercel.app/",
46
48
  "peerDependencies": {
47
49
  "@gsap/react": "^2.1.1",
48
- "clsx": "^2.1.0",
49
50
  "gsap": "^3.12.0",
50
51
  "react": ">=18",
51
- "react-dom": ">=18",
52
- "tailwind-merge": "^2.2.0"
52
+ "react-dom": ">=18"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@gsap/react": "^2.1.1",
56
56
  "@rollup/plugin-commonjs": "^25.0.7",
57
57
  "@rollup/plugin-node-resolve": "^15.2.3",
58
+ "@rollup/plugin-terser": "^0.4.4",
58
59
  "@rollup/plugin-typescript": "^11.1.6",
59
60
  "@types/react": "^18.3.3",
60
61
  "@types/react-dom": "^18.3.0",
61
- "clsx": "^2.1.1",
62
62
  "rollup": "^4.18.0",
63
63
  "rollup-plugin-dts": "^6.1.1",
64
64
  "rollup-plugin-postcss": "^4.0.2",
65
- "tailwind-merge": "^2.3.0",
66
65
  "tslib": "^2.8.1",
67
66
  "typescript": "^5.5.2"
68
67
  },
69
68
  "dependencies": {
70
- "@rollup/plugin-terser": "^0.4.4"
69
+ "clsx": "^2.1.1",
70
+ "tailwind-merge": "^2.3.0"
71
71
  }
72
72
  }
@@ -1 +0,0 @@
1
- .gsap-react-marquee-container:after{background:linear-gradient(270deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);left:0}.gsap-react-marquee-container:after,.gsap-react-marquee-container:before{content:"";height:100%;pointer-events:none;position:absolute;top:0;width:15%;z-index:10}.gsap-react-marquee-container:before{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);right:0}.gsap-react-marquee{flex:1;height:max-content;width:auto}.gsap-react-marquee,.gsap-react-marquee-content{display:flex;line-height:100%;white-space:preserve nowrap}.gsap-react-marquee-content{overflow:hidden;width:max-content}
package/dist/index.cjs.js DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t,r=require("react"),n=require("@gsap/react"),a=require("gsap"),o=require("gsap/all"),i=require("clsx"),s=require("tailwind-merge"),l={exports:{}},c={},u={};"production"===process.env.NODE_ENV?l.exports=function(){if(e)return c;e=1;var t=Symbol.for("react.transitional.element"),r=Symbol.for("react.fragment");function n(e,r,n){var a=null;if(void 0!==n&&(a=""+n),void 0!==r.key&&(a=""+r.key),"key"in r)for(var o in n={},r)"key"!==o&&(n[o]=r[o]);else n=r;return r=n.ref,{$$typeof:t,type:e,key:a,ref:void 0!==r?r:null,props:n}}return c.Fragment=r,c.jsx=n,c.jsxs=n,c}():l.exports=(t||(t=1,"production"!==process.env.NODE_ENV&&function(){function e(t){if(null==t)return null;if("function"==typeof t)return t.$$typeof===q?null:t.displayName||t.name||null;if("string"==typeof t)return t;switch(t){case m:return"Fragment";case y:return"Profiler";case g:return"StrictMode";case w:return"Suspense";case S:return"SuspenseList";case _:return"Activity"}if("object"==typeof t)switch(t.tag,t.$$typeof){case p:return"Portal";case h:return(t.displayName||"Context")+".Provider";case v:return(t._context.displayName||"Context")+".Consumer";case b:var r=t.render;return(t=t.displayName)||(t=""!==(t=r.displayName||r.name||"")?"ForwardRef("+t+")":"ForwardRef"),t;case x:return null!==(r=t.displayName||null)?r:e(t.type)||"Memo";case k:r=t._payload,t=t._init;try{return e(t(r))}catch(e){}}return null}function t(e){return""+e}function n(e){try{t(e);var r=!1}catch(e){r=!0}if(r){var n=(r=console).error,a="function"==typeof Symbol&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(r,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",a),t(e)}}function a(t){if(t===m)return"<>";if("object"==typeof t&&null!==t&&t.$$typeof===k)return"<...>";try{var r=e(t);return r?"<"+r+">":"<...>"}catch(e){return"<...>"}}function o(){return Error("react-stack-top-frame")}function i(){var t=e(this.type);return N[t]||(N[t]=!0),void 0!==(t=this.props.ref)?t:null}function s(t,r,a,o,s,u,f,p){var m,g=r.children;if(void 0!==g)if(o){if(j(g)){for(o=0;o<g.length;o++)l(g[o]);Object.freeze&&Object.freeze(g)}}else l(g);if(E.call(r,"key")){g=e(t);var y=Object.keys(r).filter(function(e){return"key"!==e});o=0<y.length?"{key: someKey, "+y.join(": ..., ")+": ...}":"{key: someKey}",A[g+o]||(y=0<y.length?"{"+y.join(": ..., ")+": ...}":"{}",A[g+o]=!0)}if(g=null,void 0!==a&&(n(a),g=""+a),function(e){if(E.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return void 0!==e.key}(r)&&(n(r.key),g=""+r.key),"key"in r)for(var v in a={},r)"key"!==v&&(a[v]=r[v]);else a=r;return g&&function(e){function t(){c||(c=!0)}t.isReactWarning=!0,Object.defineProperty(e,"key",{get:t,configurable:!0})}(a,"function"==typeof t&&(t.displayName||t.name)),function(e,t,r,n,a,o,s,l){return r=o.ref,e={$$typeof:d,type:e,key:t,props:o,_owner:a},null!==(void 0!==r?r:null)?Object.defineProperty(e,"ref",{enumerable:!1,get:i}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:s}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:l}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}(t,g,u,0,null===(m=O.A)?null:m.getOwner(),a,f,p)}function l(e){"object"==typeof e&&null!==e&&e.$$typeof===d&&e._store&&(e._store.validated=1)}var c,f=r,d=Symbol.for("react.transitional.element"),p=Symbol.for("react.portal"),m=Symbol.for("react.fragment"),g=Symbol.for("react.strict_mode"),y=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),h=Symbol.for("react.context"),b=Symbol.for("react.forward_ref"),w=Symbol.for("react.suspense"),S=Symbol.for("react.suspense_list"),x=Symbol.for("react.memo"),k=Symbol.for("react.lazy"),_=Symbol.for("react.activity"),q=Symbol.for("react.client.reference"),O=f.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,E=Object.prototype.hasOwnProperty,j=Array.isArray,T=console.createTask?console.createTask:function(){return null},N={},C=(f={react_stack_bottom_frame:function(e){return e()}}).react_stack_bottom_frame.bind(f,o)(),P=T(a(o)),A={};u.Fragment=m,u.jsx=function(e,t,r,n,o){var i=1e4>O.recentlyCreatedOwnerStacks++;return s(e,t,r,!1,0,o,i?Error("react-stack-top-frame"):C,i?T(a(e)):P)},u.jsxs=function(e,t,r,n,o){var i=1e4>O.recentlyCreatedOwnerStacks++;return s(e,t,r,!0,0,o,i?Error("react-stack-top-frame"):C,i?T(a(e)):P)}}()),u);var f=l.exports;!function(e,t){void 0===t&&(t={});var r=t.insertAt;if("undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===r&&n.firstChild?n.insertBefore(a,n.firstChild):n.appendChild(a),a.styleSheet?a.styleSheet.cssText=e:a.appendChild(document.createTextNode(e))}}('.gsap-react-marquee-container{display:flex;overflow:hidden;position:relative;white-space:preserve nowrap;width:100%}.gsap-react-marquee-container:after{background:linear-gradient(270deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);left:0}.gsap-react-marquee-container:after,.gsap-react-marquee-container:before{content:"";height:100%;pointer-events:none;position:absolute;top:0;width:15%;z-index:10}.gsap-react-marquee-container:before{background:linear-gradient(90deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);right:0}.gsap-react-marquee-vertical:after{background:linear-gradient(180deg,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;top:60%;width:100%}.gsap-react-marquee-vertical:before{background:linear-gradient(1turn,hsla(0,0%,100%,0) 0,var(--gradient-color) 75%);height:50%;left:0;right:auto;top:0;width:100%}.gsap-react-marquee{flex:1;height:max-content;width:auto}.gsap-react-marquee,.gsap-react-marquee-content{display:flex;line-height:100%;white-space:preserve nowrap}.gsap-react-marquee-content{overflow:hidden;width:max-content}');const d=(...e)=>s.twMerge(i.clsx(e)),p=e=>{let t=e;for(;t;){const e=window.getComputedStyle(t).backgroundColor;if(e&&"rgba(0, 0, 0, 0)"!==e&&"transparent"!==e)return e;t=t.parentElement}return"transparent"},m=(e,t,r,n,o)=>{const{spacing:i=16}=o;a.set(e,{gap:`${i}px`,flexDirection:n?"column":"row"}),a.set(t,{gap:`${i}px`}),n&&a.set(r,{overflow:"visible"})},g=e=>{if(e.style.width&&"auto"!==e.style.width)return!0;const t=window.getComputedStyle(e).width;if("auto"===t||!t)return!1;const r=e.parentElement;if(r){const e=window.getComputedStyle(r);if("100%"===t&&"auto"===e.width)return!1}return!0},y=(e,t,r)=>r.fill&&e<t?Math.ceil(t/e):1,v=(e,t,r)=>{const{fill:n=!1}=r;return n?"auto":e<t?"100%":e>t?`${e}px`:`${t}px`},h=(e,t,r,n,i,s,l)=>{const{spacing:c=16,speed:u=100,delay:f=0,paused:d=!1}=l,p=[],m=[],g=e.length-1,y=s?"yPercent":"xPercent",v=s?"y":"x",h=s?"height":"width";a.set(e,{[y]:(e,t)=>{const r=p[e]=parseFloat(String(a.getProperty(t,h,"px")));return m[e]=parseFloat(String(a.getProperty(t,v,"px")))/r*100+Number(a.getProperty(t,y)),m[e]}}),a.set(e,{[v]:0});const b=e[g],w=s?b.offsetTop:b.offsetLeft,S=s?b.offsetHeight:b.offsetWidth,x=w+m[g]/100*p[g]-t+S+c;if(e.forEach((e,n)=>{const a=m[n]/100*p[n],o=(s?e.offsetTop:e.offsetLeft)+a-t+p[n];r.to(e,{[y]:(a-o)/p[n]*100,duration:o/u},0).fromTo(e,{[y]:(a-o+x)/p[n]*100},{[y]:m[n],duration:(a-o+x-a)/u,immediateRender:!1},o/u)}),r.delay(f),n){if(d)return void r.pause();r.progress(1).pause(),a.delayedCall(f,()=>{r.reverse(),r.eventCallback("onReverseComplete",()=>{r.totalTime(r.rawTime()+100*r.duration())})})}let k;if("function"==typeof o.Draggable&&l.draggable){k=document.createElement("div");const e=a.utils.wrap(0,1);let t,l;const c=()=>{const n=s?u.startY-u.y:u.startX-u.x;r.progress(e(l+n*t))};o.InertiaPlugin;const u=o.Draggable.create(k,{trigger:i,type:s?"y":"x",onPress(){a.killTweensOf(r),r.pause(),l=r.progress(),t=1/x,a.set(k,{[v]:l/-t})},onDrag:c,onThrowUpdate:c,overshootTolerance:0,inertia:!0,onThrowComplete:()=>{if(n){if(d)return void r.pause();r.progress(r.progress()).pause(),a.delayedCall(f,()=>{r.reverse(),r.eventCallback("onReverseComplete",()=>{r.totalTime(r.rawTime()+100*r.duration())})})}else r.play()}})[0]}};a.registerPlugin(n.useGSAP,o.Observer,o.InertiaPlugin,o.Draggable);const b=r.forwardRef((e,t)=>{const{children:i,className:s,dir:l="left",loop:c=-1,paused:u=!1,fill:g=!1,scrollFollow:b=!1,scrollSpeed:w=2.5,gradient:S=!1,gradientColor:x=null,pauseOnHover:k=!1,spacing:_=16,speed:q=100}=e,O=r.useRef(null),E=t||O,j=r.useRef(null),[T,N]=r.useState(1),[C,P]=r.useState(null),[A,R]=r.useState(0);r.useLayoutEffect(()=>{if(!S||!(null==E?void 0:E.current))return;const e=p(E.current);P(e)},[S]);const L="up"===l||"down"===l,$="down"===l||"right"===l;r.useLayoutEffect(()=>{const e=E.current;if(!e)return;const t=e.querySelector(".gsap-react-marquee .gsap-react-marquee-content");let r=null;const n=()=>{null==r&&(r=requestAnimationFrame(()=>{R(e=>e+1),r=null}))},a=t?new ResizeObserver(n):null;t&&a&&a.observe(t);const o=Array.from(e.querySelectorAll("img")),i=()=>n();return o.forEach(e=>{e.complete||(e.addEventListener("load",i),e.addEventListener("error",i))}),()=>{null==a||a.disconnect(),o.forEach(e=>{e.removeEventListener("load",i),e.removeEventListener("error",i)}),null!=r&&cancelAnimationFrame(r)}},[i]),n.useGSAP((t,r)=>{if(!(null==j?void 0:j.current)||!E.current||!r)return;const n=null==E?void 0:E.current,i=a.utils.toArray(n.querySelectorAll(".gsap-react-marquee")),s=a.utils.toArray(n.querySelectorAll(".gsap-react-marquee .gsap-react-marquee-content"));if(!j.current||!s)return;const l=a.timeline({paused:u,repeat:c,defaults:{ease:"none"},onReverseComplete(){l.totalTime(l.rawTime()+100*l.duration())}});m(n,i,s,L,e);const f=L?n.offsetHeight:n.offsetWidth,d=L?s[0].offsetHeight:s[0].offsetWidth,p=L?s[0].offsetTop:s[0].offsetLeft;let S=null;const x=Math.min(4,Math.max(1.1,w));N(y(d,f,e));const _=a.utils.toArray(i).map(e=>L?e.offsetHeight:e.offsetWidth).reduce((e,t)=>e+t,0),q=v(_/(1===T?2:T),f,e);a.set(i,{[L?"minHeight":"minWidth"]:q,flex:g?"0 0 auto":"1"}),h(g?s:i,p,l,$,i,L,e),b&&(S=o.Observer.create({onChangeY(e){let t=x*($?-1:1);e.deltaY<0&&(t*=-1),a.timeline({defaults:{ease:"none"}}).to(l,{timeScale:t*x,duration:.2,overwrite:!0}).to(l,{timeScale:t/x,duration:1},"+=0.3")}}));const O=r(()=>{l.pause()}),C=r(()=>{$?l.reverse():l.play()});return k&&(n.addEventListener("mouseenter",O),n.addEventListener("mouseleave",C)),()=>{n.removeEventListener("mouseenter",O),n.removeEventListener("mouseleave",C),l.kill(),null==S||S.kill()}},{dependencies:[T,l,c,u,g,b,w,S,x,k,_,q,i,A],revertOnUpdate:!0});const W=r.useMemo(()=>!Number.isFinite(T)||T<=0?null:Array.from({length:T},(e,t)=>f.jsx("div",{className:d("gsap-react-marquee"),children:f.jsx("div",{className:d("gsap-react-marquee-content",s),children:i})},t)),[T,s,i]);return f.jsxs("div",{ref:E,style:{"--gradient-color":x||(S&&C?C:"transparent")},className:d("gsap-react-marquee-container",{"gsap-react-marquee-vertical":L}),children:[f.jsx("div",{ref:j,className:d("gsap-react-marquee"),children:f.jsx("div",{className:d("gsap-react-marquee-content",s),children:i})}),W]})});b.displayName="GSAPReactMarquee",exports.calculateDuplicates=y,exports.cn=d,exports.coreAnimation=h,exports.default=b,exports.getEffectiveBackgroundColor=p,exports.getMinWidth=v,exports.getTargetWidth=(e,t)=>g(e)?t?e.offsetHeight:e.offsetWidth:t?window.innerHeight:window.innerWidth,exports.hasDefinedWidth=g,exports.setupContainerStyles=m;
@@ -1,4 +0,0 @@
1
- import "./gsap-react-marquee.style.css";
2
- import type { GSAPReactMarqueeProps } from "./gsap-react-marquee.type";
3
- declare const GSAPReactMarquee: import("react").ForwardRefExoticComponent<GSAPReactMarqueeProps & import("react").RefAttributes<HTMLDivElement>>;
4
- export default GSAPReactMarquee;
@@ -1,2 +0,0 @@
1
- export declare const marqueeStyles = "\n.gsap-react-marquee-container::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: 0;\n width: 15%;\n height: 100%;\n background: linear-gradient(\n 270deg,\n rgba(255, 255, 255, 0) 0%,\n var(--gradient-color) 75%\n );\n z-index: 10;\n pointer-events: none;\n}\n\n.gsap-react-marquee-container::before {\n content: \"\";\n position: absolute;\n top: 0;\n right: 0;\n width: 15%;\n height: 100%;\n background: linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0) 0%,\n var(--gradient-color) 75%\n );\n z-index: 10;\n pointer-events: none;\n}\n\n.gsap-react-marquee {\n width: auto;\n height: max-content;\n line-height: 100%;\n white-space: preserve nowrap;\n display: flex;\n flex: 1;\n}\n\n.gsap-react-marquee-content {\n width: max-content;\n line-height: 100%;\n white-space: preserve nowrap;\n display: flex;\n overflow: hidden;\n}\n";
2
- export declare const injectStyles: () => void;
@@ -1,18 +0,0 @@
1
- import type { ReactNode } from "react";
2
- export type GSAPReactMarqueeProps = {
3
- children: ReactNode;
4
- className?: string;
5
- dir?: "right" | "left" | "up" | "down";
6
- loop?: number;
7
- paused?: boolean;
8
- delay?: number;
9
- speed?: number;
10
- fill?: boolean;
11
- pauseOnHover?: boolean;
12
- gradient?: boolean;
13
- gradientColor?: string;
14
- spacing?: number;
15
- draggable?: boolean;
16
- scrollFollow?: boolean;
17
- scrollSpeed?: number;
18
- };
@@ -1,10 +0,0 @@
1
- import { type ClassValue } from "clsx";
2
- import type { GSAPReactMarqueeProps } from "./gsap-react-marquee.type";
3
- export declare const cn: (...inputs: ClassValue[]) => string;
4
- export declare const getEffectiveBackgroundColor: (el: HTMLElement) => string;
5
- export declare const setupContainerStyles: (containerMarquee: HTMLElement, marquees: HTMLElement[], marqueesChildren: HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => void;
6
- export declare const hasDefinedWidth: (element: HTMLElement) => boolean;
7
- export declare const getTargetWidth: (containerElement: HTMLElement, isVertical: boolean) => number;
8
- export declare const calculateDuplicates: (marqueeChildrenWidth: number, containerMarqueeWidth: number, props: GSAPReactMarqueeProps) => number;
9
- export declare const getMinWidth: (totalSize: number, containerSize: number, props: GSAPReactMarqueeProps) => string | number;
10
- export declare const coreAnimation: (elementsToAnimate: HTMLElement[], startPos: number, tl: gsap.core.Timeline, isReverse: boolean, draggableTrigger: HTMLElement | HTMLElement[], isVertical: boolean, props: GSAPReactMarqueeProps) => void;
@@ -1,3 +0,0 @@
1
- export { default } from "./components/gsap-react-marquee";
2
- export type { GSAPReactMarqueeProps } from "./components/gsap-react-marquee.type";
3
- export * from "./components/gsap-reactmarquee.utils";