@androbinco/library-cli 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +86 -37
  2. package/package.json +11 -16
  3. package/src/commands/add.js +107 -0
  4. package/src/commands/list.js +51 -0
  5. package/src/index.js +46 -15
  6. package/src/templates/carousel/components/navigation-buttons.tsx +1 -0
  7. package/src/templates/carousel/components/pagination/bullet.pagination.carousel.tsx +69 -0
  8. package/src/templates/carousel/components/pagination/number.pagination.carousel.tsx +30 -0
  9. package/src/templates/carousel/components/pagination/progress/progress.pagination.carousel.tsx +99 -0
  10. package/src/templates/carousel/components/pagination/progress/use-slide-progress.tsx +31 -0
  11. package/src/templates/carousel/components/pagination.tsx +47 -82
  12. package/src/templates/faqs-accordion/examples/faqs-showcase.tsx +42 -0
  13. package/src/templates/faqs-accordion/faqs-accordion.tsx +70 -0
  14. package/src/templates/faqs-accordion/mock-data.ts +38 -0
  15. package/src/templates/faqs-accordion/types.ts +18 -0
  16. package/src/templates/in-view/data.in-view.ts +89 -0
  17. package/src/templates/in-view/examples/in-view-examples.home.tsx +101 -0
  18. package/src/templates/in-view/examples/in-view-grid-showcase.tsx +41 -0
  19. package/src/templates/in-view/in-view-animation.tsx +72 -0
  20. package/src/templates/in-view/in-view-grid.tsx +81 -0
  21. package/src/templates/in-view/in-view-hidden-text.tsx +45 -0
  22. package/src/templates/in-view/in-view-stroke-line.tsx +30 -0
  23. package/src/templates/lenis/examples/providers.tsx +23 -0
  24. package/src/templates/lenis/lenis-provider.tsx +46 -0
  25. package/src/templates/scroll-components/hooks/use-client-dimensions.ts +21 -0
  26. package/src/templates/scroll-components/parallax/examples/parallax-showcase.tsx +87 -0
  27. package/src/templates/scroll-components/parallax/parallax.css +36 -0
  28. package/src/templates/scroll-components/parallax/parallax.tsx +67 -0
  29. package/src/templates/scroll-components/scale-gallery/components/expanding-element.tsx +40 -0
  30. package/src/templates/scroll-components/scale-gallery/examples/scale-gallery-showcase.tsx +68 -0
  31. package/src/templates/scroll-components/scale-gallery/scale-gallery.tsx +57 -0
  32. package/src/templates/scroll-components/scroll-tracker-provider.tsx +78 -0
  33. package/src/templates/scroll-components/scroll-tracker-showcase.tsx +44 -0
  34. package/src/templates/strapi-dynamic-zone/README.md +157 -0
  35. package/src/templates/strapi-dynamic-zone/dynamic-zone.tsx +113 -0
  36. package/src/templates/strapi-dynamic-zone/examples/page.tsx +53 -0
  37. package/src/templates/strapi-dynamic-zone/examples/renderers.tsx +74 -0
  38. package/src/templates/strapi-dynamic-zone/examples/types.ts +41 -0
  39. package/src/templates/strapi-dynamic-zone/index.ts +11 -0
  40. package/src/templates/strapi-dynamic-zone/types.ts +73 -0
  41. package/src/templates/ticker/css-ticker/css-ticker.tsx +61 -0
  42. package/src/templates/ticker/css-ticker/ticker.keyframes.css +86 -0
  43. package/src/templates/ticker/examples/ticker-hover-showcase.home.tsx +57 -0
  44. package/src/templates/ticker/examples/ticker-static-showcase.home.tsx +56 -0
  45. package/src/templates/ticker/hooks/use-ticker-clones.tsx +70 -0
  46. package/src/templates/ticker/hooks/use-ticker-incremental.tsx +72 -0
  47. package/src/templates/ticker/motion-ticker.tsx +93 -0
  48. package/src/utils/components.js +587 -54
  49. package/src/utils/files.js +89 -5
  50. package/src/templates/button/button.tsx +0 -5
  51. package/src/templates/card/card.tsx +0 -5
  52. package/src/templates/example/example.tsx +0 -5
  53. package/src/templates/hero/hero.tsx +0 -5
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { motion, useTransform } from 'motion/react';
3
+ import { ScrollTrackerProvider, useScrollTrackerContext } from './scroll-tracker-provider';
4
+ import { Text } from '@/common/ui/text/text';
5
+
6
+ const ScrollProgressBar = () => {
7
+ const { scrollYProgress } = useScrollTrackerContext();
8
+
9
+ return (
10
+ <motion.div
11
+ className="fixed top-0 left-0 right-0 h-1 bg-gradient-to-r from-blue-500 to-purple-500 origin-left"
12
+ style={{ scaleX: scrollYProgress }}
13
+ />
14
+ );
15
+ };
16
+
17
+ const ScrollContent = () => {
18
+ const { scrollYProgress } = useScrollTrackerContext();
19
+ const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [0.3, 1, 0.3]);
20
+ const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8]);
21
+
22
+ return (
23
+ <motion.div
24
+ className="flex flex-col items-center justify-center h-screen gap-4"
25
+ style={{ opacity, scale }}
26
+ >
27
+ <Text className="text-center" variant="title.6">
28
+ Scroll Progress: {scrollYProgress}
29
+ </Text>
30
+ <div className="w-64 h-64 bg-gradient-to-br from-cyan-400 to-blue-500 rounded-lg" />
31
+ </motion.div>
32
+ );
33
+ };
34
+
35
+ export const ScrollTrackerShowcase = () => {
36
+ return (
37
+ <ScrollTrackerProvider height={500}>
38
+ <ScrollProgressBar />
39
+ <div className='flex h-full w-full flex-col items-center justify-center'>
40
+ <ScrollContent />
41
+ </div>
42
+ </ScrollTrackerProvider>
43
+ );
44
+ };
@@ -0,0 +1,157 @@
1
+ # Strapi Dynamic Zone Renderer
2
+
3
+ A type-safe, composable component for rendering Strapi Dynamic Zones in Next.js applications.
4
+
5
+ ## Features
6
+
7
+ - **Full TypeScript support** - Leverages discriminated unions for type-safe component mapping
8
+ - **Single source of truth** - Your Strapi types define both data shape and rendering
9
+ - **Composable** - Mix and match components, add extra props, customize wrappers
10
+ - **Zero dependencies** - Just React
11
+
12
+ ## Installation
13
+
14
+ Copy the `strapi-dynamic-renderer` folder to your project (e.g., `src/lib/strapi-dynamic-renderer`).
15
+
16
+ ## Quick Start
17
+
18
+ ### 1. Define your component types
19
+
20
+ ```typescript
21
+ // types/page-components.ts
22
+ export type HeroComponent = {
23
+ __component: 'hero.hero';
24
+ id: number;
25
+ title: string;
26
+ subtitle: string;
27
+ };
28
+
29
+ export type CTAComponent = {
30
+ __component: 'cta.cta';
31
+ id: number;
32
+ heading: string;
33
+ buttonText: string;
34
+ };
35
+
36
+ // Union of all dynamic zone components
37
+ export type PageComponent = HeroComponent | CTAComponent;
38
+ ```
39
+
40
+ ### 2. Create your renderers
41
+
42
+ ```typescript
43
+ // renderers/page-renderers.tsx
44
+ import type { ComponentRendererMap } from '@/lib/strapi-dynamic-renderer';
45
+ import type { PageComponent } from '@/types/page-components';
46
+
47
+ export const pageRenderers: ComponentRendererMap<PageComponent> = {
48
+ 'hero.hero': ({ title, subtitle }) => (
49
+ <Hero title={title} subtitle={subtitle} />
50
+ ),
51
+ 'cta.cta': ({ heading, buttonText }) => (
52
+ <CTA heading={heading} buttonText={buttonText} />
53
+ ),
54
+ };
55
+ ```
56
+
57
+ ### 3. Use in your pages
58
+
59
+ ```tsx
60
+ // app/page.tsx
61
+ import { DynamicZone } from '@/lib/strapi-dynamic-renderer';
62
+ import { pageRenderers } from '@/renderers/page-renderers';
63
+
64
+ export default function Page({ data }) {
65
+ return (
66
+ <DynamicZone
67
+ components={data.dynamicZone}
68
+ renderers={pageRenderers}
69
+ />
70
+ );
71
+ }
72
+ ```
73
+
74
+ ## API Reference
75
+
76
+ ### `DynamicZone`
77
+
78
+ Renders an array of Strapi dynamic zone components.
79
+
80
+ ```tsx
81
+ <DynamicZone
82
+ components={PageComponent[]} // Required: Array of components
83
+ renderers={ComponentRendererMap} // Required: Renderer map
84
+ getExtraProps={(comp, idx) => {}} // Optional: Extra props per component
85
+ fallback={(comp) => <div />} // Optional: Fallback for unknown types
86
+ getKey={(comp, idx) => string} // Optional: Custom key generator
87
+ />
88
+ ```
89
+
90
+ ### `createDynamicZone`
91
+
92
+ Factory function to create a pre-bound DynamicZone component.
93
+
94
+ ```tsx
95
+ // Create once
96
+ export const PageZone = createDynamicZone(pageRenderers);
97
+
98
+ // Use anywhere
99
+ <PageZone components={data.Page} />
100
+ ```
101
+
102
+ ## Type Utilities
103
+
104
+ ### `ExtractComponentProps<TUnion, TKey>`
105
+
106
+ Extracts props for a specific component type:
107
+
108
+ ```typescript
109
+ type HeroProps = ExtractComponentProps<PageComponent, 'hero.hero'>;
110
+ // { id: number; title: string; subtitle: string }
111
+ ```
112
+
113
+ ### `ComponentRendererMap<TUnion, TExtra>`
114
+
115
+ Creates a type-safe renderer map:
116
+
117
+ ```typescript
118
+ const renderers: ComponentRendererMap<PageComponent, { index: number }> = {
119
+ 'hero.hero': ({ title, index }) => <Hero title={title} position={index} />,
120
+ };
121
+ ```
122
+
123
+ ## Patterns
124
+
125
+ ### Adding extra props to all renderers
126
+
127
+ ```tsx
128
+ type ExtraProps = { index: number; dataSource: string };
129
+
130
+ const renderers: ComponentRendererMap<PageComponent, ExtraProps> = {
131
+ 'hero.hero': ({ title, index, dataSource }) => (
132
+ <Hero title={title} position={index} source={dataSource} />
133
+ ),
134
+ };
135
+
136
+ <DynamicZone
137
+ components={data}
138
+ renderers={renderers}
139
+ getExtraProps={(_, index) => ({ index, dataSource: 'homepage' })}
140
+ />
141
+ ```
142
+
143
+ ### Development fallback
144
+
145
+ ```tsx
146
+ <DynamicZone
147
+ components={data}
148
+ renderers={renderers}
149
+ fallback={(comp) => (
150
+ process.env.NODE_ENV === 'development' ? (
151
+ <div className="border-2 border-dashed border-red-500 p-4">
152
+ Missing renderer: {comp.__component}
153
+ </div>
154
+ ) : null
155
+ )}
156
+ />
157
+ ```
@@ -0,0 +1,113 @@
1
+ import { Fragment } from "react";
2
+ import type { StrapiComponent, DynamicZoneProps } from "./types";
3
+
4
+ /**
5
+ * Renders an array of Strapi dynamic zone components.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <DynamicZone
10
+ * components={page.dynamicZone}
11
+ * renderers={componentRenderers}
12
+ * getExtraProps={(_, index) => ({ index })}
13
+ * />
14
+ * ```
15
+ */
16
+ export function DynamicZone<
17
+ TUnion extends StrapiComponent,
18
+ TExtra extends object = object
19
+ >({
20
+ components,
21
+ renderers,
22
+ getExtraProps,
23
+ fallback,
24
+ getKey,
25
+ }: DynamicZoneProps<TUnion, TExtra>): React.ReactElement | null {
26
+ if (!components || components.length === 0) {
27
+ return null;
28
+ }
29
+
30
+ const defaultGetKey = (component: TUnion, index: number) =>
31
+ component.id ?? `dynamic-${index}`;
32
+
33
+ const keyGenerator = getKey ?? defaultGetKey;
34
+
35
+ const content = components.map((component, index) => {
36
+ const key = keyGenerator(component, index);
37
+ const extraProps = getExtraProps?.(component, index) as TExtra | undefined;
38
+ const { __component, ...componentProps } = component;
39
+
40
+ const Renderer = renderers[__component as keyof typeof renderers] as
41
+ | ((props: Record<string, unknown> & TExtra) => React.ReactElement | null)
42
+ | undefined;
43
+
44
+ if (!Renderer) {
45
+ if (fallback) {
46
+ return <Fragment key={key}>{fallback(component)}</Fragment>;
47
+ }
48
+
49
+ if (process.env.NODE_ENV === "development") {
50
+ console.warn(
51
+ `[DynamicZone] No renderer found for component: "${__component}"`,
52
+ component
53
+ );
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ const props = {
60
+ ...componentProps,
61
+ ...extraProps,
62
+ } as Parameters<typeof Renderer>[0];
63
+
64
+ return (
65
+ <Fragment key={key}>
66
+ <Renderer {...props} />
67
+ </Fragment>
68
+ );
69
+ });
70
+
71
+ return <>{content}</>;
72
+ }
73
+
74
+ /**
75
+ * Creates a type-safe DynamicZone component bound to specific renderers.
76
+ * Useful when you want to pre-configure renderers and reuse across the app.
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * // In your renderers file
81
+ * export const PageZone = createDynamicZone(pageRenderers);
82
+ *
83
+ * // In your page
84
+ * <PageZone
85
+ * components={data.Page}
86
+ * getExtraProps={(_, i) => ({ index: i })}
87
+ * />
88
+ * ```
89
+ */
90
+ export function createDynamicZone<
91
+ TUnion extends StrapiComponent,
92
+ TExtra extends object = object
93
+ >(
94
+ renderers: DynamicZoneProps<TUnion, TExtra>["renderers"],
95
+ defaultFallback?: DynamicZoneProps<TUnion, TExtra>["fallback"]
96
+ ) {
97
+ return function BoundDynamicZone({
98
+ components,
99
+ getExtraProps,
100
+ fallback = defaultFallback,
101
+ getKey,
102
+ }: Omit<DynamicZoneProps<TUnion, TExtra>, "renderers">) {
103
+ return (
104
+ <DynamicZone
105
+ components={components}
106
+ renderers={renderers}
107
+ getExtraProps={getExtraProps}
108
+ fallback={fallback}
109
+ getKey={getKey}
110
+ />
111
+ );
112
+ };
113
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Example: Using DynamicZone in a Next.js page
3
+ */
4
+
5
+ import { DynamicZone } from "../dynamic-zone";
6
+ import { pageRenderers } from "./renderers";
7
+ import type { PageComponent } from "./types";
8
+
9
+ // Example page data type
10
+ type PageData = {
11
+ title: string;
12
+ dynamicZone: PageComponent[];
13
+ };
14
+
15
+ /**
16
+ * Alternative: Create a pre-bound component in renderers.tsx for cleaner usage
17
+ */
18
+
19
+ // Then use it more concisely:
20
+ import { PageDynamicZone } from "./renderers";
21
+
22
+ export function ExamplePageAlt({ data }: { data: PageData }) {
23
+ return (
24
+ <main>
25
+ <h1>{data.title}</h1>
26
+
27
+ <PageDynamicZone
28
+ components={data.dynamicZone}
29
+ getExtraProps={(_, index) => ({ index })}
30
+ />
31
+ </main>
32
+ );
33
+ }
34
+
35
+ /**
36
+ * With custom fallback for unknown components
37
+ */
38
+ export function ExamplePageWithFallback({ data }: { data: PageData }) {
39
+ return (
40
+ <main>
41
+ <DynamicZone
42
+ components={data.dynamicZone}
43
+ renderers={pageRenderers}
44
+ getExtraProps={(_, index) => ({ index })}
45
+ fallback={(component) => (
46
+ <div style={{ padding: 16, background: "#fee", borderRadius: 8 }}>
47
+ Unknown component: {component.__component}
48
+ </div>
49
+ )}
50
+ />
51
+ </main>
52
+ );
53
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Example: Define your component renderers here.
3
+ * Each key matches a __component value from your Strapi types.
4
+ */
5
+
6
+ import type { ComponentRendererMap } from "../types";
7
+ import type { PageComponent, PageExtraProps } from "./types";
8
+
9
+ // Example placeholder components - replace with your actual components
10
+ const Hero = ({ title, subtitle }: { title: string; subtitle: string }) => (
11
+ <section>
12
+ <h1>{title}</h1>
13
+ <p>{subtitle}</p>
14
+ </section>
15
+ );
16
+
17
+ const CTA = ({
18
+ heading,
19
+ buttonText,
20
+ buttonLink,
21
+ }: {
22
+ heading: string;
23
+ buttonText: string;
24
+ buttonLink: string;
25
+ }) => (
26
+ <section>
27
+ <h2>{heading}</h2>
28
+ <a href={buttonLink}>{buttonText}</a>
29
+ </section>
30
+ );
31
+
32
+ const FeatureGrid = ({
33
+ title,
34
+ features,
35
+ }: {
36
+ title: string;
37
+ features: Array<{ id: number; title: string; description: string }>;
38
+ }) => (
39
+ <section>
40
+ <h2>{title}</h2>
41
+ <div>
42
+ {features.map((f) => (
43
+ <div key={f.id}>
44
+ <h3>{f.title}</h3>
45
+ <p>{f.description}</p>
46
+ </div>
47
+ ))}
48
+ </div>
49
+ </section>
50
+ );
51
+
52
+ /**
53
+ * Component renderer map - fully type-safe!
54
+ * TypeScript will error if:
55
+ * - You miss a component type
56
+ * - You use wrong props for a component
57
+ * - You add a component that doesn't exist in the union
58
+ */
59
+ const pageRenderers: ComponentRendererMap<PageComponent, PageExtraProps> = {
60
+ "hero.hero": ({ title, subtitle, index }) => (
61
+ <Hero title={title} subtitle={subtitle} key={index} />
62
+ ),
63
+
64
+ "cta.cta": ({ heading, buttonText, buttonLink }) => (
65
+ <CTA heading={heading} buttonText={buttonText} buttonLink={buttonLink} />
66
+ ),
67
+
68
+ "features.grid": ({ title, features }) => (
69
+ <FeatureGrid title={title} features={features} />
70
+ ),
71
+ };
72
+ // Create a pre-bound component for cleaner usage
73
+ import { createDynamicZone } from "../dynamic-zone";
74
+ export const PageDynamicZone = createDynamicZone(pageRenderers);
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Example: Define your Strapi component types here.
3
+ * This is your single source of truth for component shapes.
4
+ */
5
+
6
+ // Example component types - replace with your actual Strapi types
7
+ export type HeroComponent = {
8
+ __component: 'hero.hero';
9
+ id: number;
10
+ title: string;
11
+ subtitle: string;
12
+ backgroundImage: { url: string };
13
+ };
14
+
15
+ export type CTAComponent = {
16
+ __component: 'cta.cta';
17
+ id: number;
18
+ heading: string;
19
+ buttonText: string;
20
+ buttonLink: string;
21
+ };
22
+
23
+ export type FeatureGridComponent = {
24
+ __component: 'features.grid';
25
+ id: number;
26
+ title: string;
27
+ features: Array<{
28
+ id: number;
29
+ title: string;
30
+ description: string;
31
+ icon: string;
32
+ }>;
33
+ };
34
+
35
+ // Union of all possible dynamic zone components
36
+ export type PageComponent = HeroComponent | CTAComponent | FeatureGridComponent;
37
+
38
+ // Extra props that get passed to every renderer
39
+ export type PageExtraProps = {
40
+ index: number;
41
+ };
@@ -0,0 +1,11 @@
1
+ // Types
2
+ export type {
3
+ StrapiComponent,
4
+ ExtractComponentProps,
5
+ ComponentRendererMap,
6
+ ComponentKeys,
7
+ DynamicZoneProps,
8
+ } from './types';
9
+
10
+ // Components
11
+ export { DynamicZone, createDynamicZone } from './dynamic-zone';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Strapi Dynamic Zone Type Utilities
3
+ *
4
+ * These types provide type-safe rendering for Strapi Dynamic Zones.
5
+ * Define your component union type with `__component` discriminator,
6
+ * then use these utilities for type-safe prop extraction.
7
+ */
8
+
9
+ /**
10
+ * Base constraint for Strapi dynamic zone components.
11
+ * All components must have a `__component` string identifier.
12
+ */
13
+ export type StrapiComponent = {
14
+ __component: string;
15
+ id?: number | string;
16
+ };
17
+
18
+ /**
19
+ * Extracts the props for a specific component type from a union,
20
+ * omitting the `__component` discriminator.
21
+ *
22
+ * @example
23
+ * type HeroProps = ExtractComponentProps<PageComponent, 'hero.hero'>;
24
+ * // Results in: { title: string; subtitle: string; image: ImageType }
25
+ */
26
+ export type ExtractComponentProps<
27
+ TUnion extends StrapiComponent,
28
+ TComponentKey extends TUnion['__component']
29
+ > = Omit<Extract<TUnion, { __component: TComponentKey }>, '__component'>;
30
+
31
+ /**
32
+ * Creates a type-safe renderer map from a component union.
33
+ * Each key is a `__component` value, each value is a render function.
34
+ *
35
+ * @example
36
+ * const renderers: ComponentRendererMap<PageComponent> = {
37
+ * 'hero.hero': (props) => <Hero {...props} />,
38
+ * 'cta.cta': (props) => <CTA {...props} />,
39
+ * };
40
+ */
41
+ export type ComponentRendererMap<
42
+ TUnion extends StrapiComponent,
43
+ TExtra = object
44
+ > = {
45
+ [K in TUnion['__component']]: (
46
+ props: ExtractComponentProps<TUnion, K> & TExtra
47
+ ) => React.ReactElement | null;
48
+ };
49
+
50
+ /**
51
+ * Utility type to get all component keys from a union.
52
+ */
53
+ export type ComponentKeys<TUnion extends StrapiComponent> =
54
+ TUnion['__component'];
55
+
56
+ /**
57
+ * Props for the DynamicZone component (renders multiple components).
58
+ */
59
+ export type DynamicZoneProps<
60
+ TUnion extends StrapiComponent,
61
+ TExtra = object
62
+ > = {
63
+ /** Array of components from Strapi Dynamic Zone */
64
+ components: TUnion[];
65
+ /** Map of component renderers */
66
+ renderers: ComponentRendererMap<TUnion, TExtra>;
67
+ /** Function to generate extra props per component (receives component and index) */
68
+ getExtraProps?: (component: TUnion, index: number) => TExtra;
69
+ /** Optional fallback for unknown components */
70
+ fallback?: (component: TUnion) => React.ReactElement | null;
71
+ /** Optional key generator (defaults to component.id or index) */
72
+ getKey?: (component: TUnion, index: number) => string | number;
73
+ };
@@ -0,0 +1,61 @@
1
+ 'use client';
2
+ import { Fragment, useRef } from 'react';
3
+
4
+ import { cn } from '@/common/utils/classname-builder';
5
+
6
+ import { useTickerClones } from '../hooks/use-ticker-clones';
7
+ import './ticker.keyframes.css';
8
+
9
+ export const TickerStatic = ({
10
+ direction = 'right',
11
+ children,
12
+ speed = 50,
13
+ }: {
14
+ direction?: 'left' | 'right';
15
+ speed?: number;
16
+ delta?: number;
17
+ children: React.ReactNode;
18
+ }) => {
19
+ const tickerClone = useRef<HTMLDivElement>(null);
20
+ const tickerCard = useRef<HTMLDivElement>(null);
21
+
22
+ const { clonesNeeded } = useTickerClones({
23
+ tickerCard,
24
+ tickerClone,
25
+ direction,
26
+ onCloneWrapper(clone) {
27
+ clone.classList.remove('animate-base-ticker');
28
+ clone.classList.remove('animate-base-ticker-left');
29
+ },
30
+ });
31
+
32
+ const baseTickerClass = cn(
33
+ 'flex w-max flex-row',
34
+ direction === 'right' ? 'animate-base-ticker' : 'animate-base-ticker-left',
35
+ );
36
+ const clonedTickerClass = cn(
37
+ 'absolute top-0 h-full w-max',
38
+ direction === 'right' ? 'animate-cloned-ticker' : 'animate-cloned-ticker-left',
39
+ );
40
+
41
+ return (
42
+ <div className="ticker group w-full overflow-hidden" role="group">
43
+ <div className="relative w-full">
44
+ <div
45
+ ref={tickerCard}
46
+ className={cn(baseTickerClass)}
47
+ style={{ '--ticker-speed': `${speed}s` } as React.CSSProperties}
48
+ >
49
+ {Array.from({ length: clonesNeeded }).map((_, index) => {
50
+ return <Fragment key={index}>{children}</Fragment>;
51
+ })}
52
+ </div>
53
+ <div
54
+ ref={tickerClone}
55
+ className={cn(clonedTickerClass)}
56
+ style={{ '--ticker-speed': `${speed}s` } as React.CSSProperties}
57
+ />
58
+ </div>
59
+ </div>
60
+ );
61
+ };