@udixio/ui-react 2.9.6 → 2.9.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAO9C;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,4MAqBlB,UAAU,CAAC,aAAa,CAAC,4CA0S3B,CAAC"}
1
+ {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAO9C;;;;GAIG;AACH,eAAO,MAAM,IAAI,GAAI,4MAqBlB,UAAU,CAAC,aAAa,CAAC,4CA2S3B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Chips.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chips.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAY,cAAc,EAAE,MAAM,eAAe,CAAC;AAMzD,eAAO,MAAM,KAAK,GAAI,sEAOnB,UAAU,CAAC,cAAc,CAAC,4CAwQ5B,CAAC"}
1
+ {"version":3,"file":"Chips.d.ts","sourceRoot":"","sources":["../../../src/lib/components/Chips.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAY,cAAc,EAAE,MAAM,eAAe,CAAC;AAMzD,eAAO,MAAM,KAAK,GAAI,sEAOnB,UAAU,CAAC,cAAc,CAAC,4CAiT5B,CAAC"}
@@ -1,14 +1,38 @@
1
- import { CustomScrollInterface } from './custom-scroll';
2
- import { ReactProps } from '../utils';
1
+ import { ReactNode } from 'react';
2
+ export type SmoothScrollProps = {
3
+ /**
4
+ * Duration of the scroll animation in seconds or as a CSS string (e.g., '1s', '500ms').
5
+ * Default: 1.2
6
+ */
7
+ transition?: number | string;
8
+ /**
9
+ * Easing function for the scroll animation.
10
+ * Default: easeOutQuint
11
+ */
12
+ easing?: (t: number) => number;
13
+ /**
14
+ * Scroll orientation.
15
+ * Default: 'vertical'
16
+ */
17
+ orientation?: 'vertical' | 'horizontal';
18
+ /**
19
+ * Enable smooth scrolling on touch devices.
20
+ * Default: false (native touch scrolling is usually preferred)
21
+ */
22
+ smoothTouch?: boolean;
23
+ /**
24
+ * Multiplier for touch scroll sensitivity.
25
+ * Default: 2
26
+ */
27
+ touchMultiplier?: number;
28
+ /**
29
+ * Children elements (optional, component works at document level)
30
+ */
31
+ children?: ReactNode;
32
+ };
3
33
  /**
4
- * WARNING: using this component is not recommended for now.
5
- * It may block or alter certain scroll events (wheel/touch/keyboard) depending on the context.
6
- * Rework it later (e.g., via Lenis or another solution) before using it in production.
34
+ * SmoothScroll component using Lenis for smooth scrolling.
35
+ * This component enables smooth scrolling at the document level.
7
36
  */
8
- export declare const SmoothScroll: ({ transition, orientation, throttleDuration, }: {
9
- transition?: {
10
- ease: "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut" | "backIn" | "backOut" | "backInOut" | "anticipate" | ((t: number) => number);
11
- duration?: number;
12
- };
13
- } & ReactProps<CustomScrollInterface>) => import("react/jsx-runtime").JSX.Element | null;
37
+ export declare const SmoothScroll: ({ transition, easing, orientation, smoothTouch, touchMultiplier, children, }: SmoothScrollProps) => import("react/jsx-runtime").JSX.Element | null;
14
38
  //# sourceMappingURL=smooth-scroll.effect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"smooth-scroll.effect.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/smooth-scroll.effect.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAItC;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,gDAI1B;IACD,UAAU,CAAC,EAAE;QACX,IAAI,EACA,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,GACX,YAAY,GACZ,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,GAAG,UAAU,CAAC,qBAAqB,CAAC,mDA6GpC,CAAC"}
1
+ {"version":3,"file":"smooth-scroll.effect.d.ts","sourceRoot":"","sources":["../../../src/lib/effects/smooth-scroll.effect.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B;;;OAGG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,8EAO1B,iBAAiB,mDAmDnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@udixio/ui-react",
3
- "version": "2.9.6",
3
+ "version": "2.9.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -28,6 +28,7 @@
28
28
  "motion": "^12.23.0",
29
29
  "tailwind-merge": "^3.3.1",
30
30
  "uuid": "^11.0.3",
31
+ "lenis": "^1.2.3",
31
32
  "@fortawesome/fontawesome-svg-core": "^7.0.0",
32
33
  "@fortawesome/free-regular-svg-icons": "^7.0.0",
33
34
  "@fortawesome/free-solid-svg-icons": "^7.0.0",
@@ -36,8 +37,8 @@
36
37
  "devDependencies": {
37
38
  "react": "^19.1.1",
38
39
  "react-dom": "^19.1.1",
39
- "@udixio/theme": "2.1.9",
40
- "@udixio/tailwind": "2.4.7"
40
+ "@udixio/theme": "2.1.10",
41
+ "@udixio/tailwind": "2.4.8"
41
42
  },
42
43
  "repository": {
43
44
  "type": "git",
@@ -114,7 +114,8 @@ export const Chip = ({
114
114
  }
115
115
  };
116
116
 
117
- const isInteractive = !!onToggle || !!onRemove || !!onClick || !!href;
117
+ const isInteractive =
118
+ !!onToggle || !!onRemove || !!onClick || !!href || !!editable;
118
119
 
119
120
  if (activated) {
120
121
  icon = faCheck;
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { ReactProps } from '../utils';
3
3
  import { ChipItem, ChipsInterface } from '../interfaces';
4
4
  import { useChipsStyle } from '../styles';
@@ -34,12 +34,19 @@ export const Chips = ({
34
34
 
35
35
  React.useEffect(() => {
36
36
  if (isFocused) {
37
- ref.current?.focus();
37
+ if (variant == 'input') {
38
+ ghostChipRef.current?.focus();
39
+ } else {
40
+ ref.current?.focus();
41
+ }
38
42
  }
39
43
  }, [isFocused]);
40
44
 
41
45
  const chipRefs = React.useRef<(HTMLElement | null)[]>([]);
42
46
 
47
+ // Guard to prevent multiple chip creation from fast typing
48
+ const isCreatingRef = React.useRef(false);
49
+
43
50
  const updateItems = React.useCallback(
44
51
  (updater: (prev: ChipItem[]) => ChipItem[]) => {
45
52
  onItemsChange?.(updater(list));
@@ -64,6 +71,10 @@ export const Chips = ({
64
71
  (seedLabel = '') => {
65
72
  if (variant !== 'input') return;
66
73
 
74
+ // Guard against multiple rapid creations
75
+ if (isCreatingRef.current) return;
76
+ isCreatingRef.current = true;
77
+
67
78
  const newItem: ChipItem = {
68
79
  label: seedLabel,
69
80
  } as ChipItem;
@@ -77,6 +88,8 @@ export const Chips = ({
77
88
 
78
89
  requestAnimationFrame(() => {
79
90
  setSelectedChip(newId);
91
+ // Reset guard after chip is selected
92
+ isCreatingRef.current = false;
80
93
  });
81
94
  },
82
95
  [variant, onItemsChange, list, getInternalId],
@@ -102,6 +115,11 @@ export const Chips = ({
102
115
  }, [selectedChip, list, getInternalId]);
103
116
 
104
117
  // MODE ITEMS (source de vérité locale ou contrôlée)
118
+
119
+ const ghostChipRef = useRef<HTMLButtonElement>(null);
120
+
121
+ const isGhostChip = (isFocused || list.length === 0) && variant === 'input';
122
+
105
123
  return (
106
124
  <div
107
125
  ref={ref}
@@ -114,7 +132,9 @@ export const Chips = ({
114
132
  setIsFocused(true);
115
133
  }
116
134
  }}
117
- onBlur={() => setIsFocused(false)}
135
+ onBlur={() => {
136
+ setIsFocused(false);
137
+ }}
118
138
  onKeyDown={(e) => {
119
139
  if (variant !== 'input') return;
120
140
 
@@ -160,13 +180,7 @@ export const Chips = ({
160
180
  setSelectedChip(elId);
161
181
  return;
162
182
  }
163
-
164
183
  if (isContainerFocused) {
165
- if (key === 'Enter') {
166
- e.preventDefault();
167
- createAndStartEdit('');
168
- return;
169
- }
170
184
  if (key === 'Backspace') {
171
185
  e.preventDefault();
172
186
  // Focus last chip if any
@@ -176,12 +190,6 @@ export const Chips = ({
176
190
  }
177
191
  return;
178
192
  }
179
- // Start creation when typing a printable character
180
- if (key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey) {
181
- createAndStartEdit(key);
182
- e.preventDefault();
183
- return;
184
- }
185
193
  }
186
194
  }}
187
195
  >
@@ -203,7 +211,7 @@ export const Chips = ({
203
211
  onEditCancel: () => {
204
212
  setIsFocused(true);
205
213
  },
206
- onChange: (next: ChipItem[]) => {
214
+ onChange: () => {
207
215
  if (chipRefs.current.length == index + 1) {
208
216
  const el = ref.current!;
209
217
  requestAnimationFrame(() => {
@@ -275,6 +283,39 @@ export const Chips = ({
275
283
  </style>
276
284
  </>
277
285
  )}
286
+ {isGhostChip && (
287
+ <Chip
288
+ ref={ghostChipRef}
289
+ className="opacity-0"
290
+ draggable={draggable}
291
+ editable={true}
292
+ editing={true}
293
+ onChange={(v) => {
294
+ v = v.replace(/(&nbsp;)+/g, ' ').trim();
295
+ console.log('Ghost chip onChange', v, !!v);
296
+ if (v) {
297
+ createAndStartEdit(v);
298
+ } else {
299
+ if (list.length > 0) {
300
+ const el = chipRefs.current[list.length - 1] as any;
301
+ el?.focus?.();
302
+ }
303
+ }
304
+ }}
305
+ onEditCommit={() => {
306
+ // Ghost chip doesn't commit - it creates a new chip via onChange
307
+ }}
308
+ onBlur={() => {
309
+ setIsFocused(false);
310
+ }}
311
+ onFocus={(e: React.FocusEvent) => {
312
+ setIsFocused(true);
313
+ e.stopPropagation();
314
+ }}
315
+ >
316
+ &nbsp;
317
+ </Chip>
318
+ )}
278
319
  </div>
279
320
  );
280
321
  };
@@ -1,142 +1,98 @@
1
- import { useEffect, useRef, useState } from 'react';
2
- import { CustomScrollInterface } from './custom-scroll';
3
- import { ReactProps } from '../utils';
4
- import { BlockScroll } from './block-scroll.effect';
5
- import { animate, AnimationPlaybackControls } from 'motion';
1
+ import { useEffect, useRef, ReactNode } from 'react';
2
+ import Lenis from 'lenis';
3
+
4
+ export type SmoothScrollProps = {
5
+ /**
6
+ * Duration of the scroll animation in seconds or as a CSS string (e.g., '1s', '500ms').
7
+ * Default: 1.2
8
+ */
9
+ transition?: number | string;
10
+ /**
11
+ * Easing function for the scroll animation.
12
+ * Default: easeOutQuint
13
+ */
14
+ easing?: (t: number) => number;
15
+ /**
16
+ * Scroll orientation.
17
+ * Default: 'vertical'
18
+ */
19
+ orientation?: 'vertical' | 'horizontal';
20
+ /**
21
+ * Enable smooth scrolling on touch devices.
22
+ * Default: false (native touch scrolling is usually preferred)
23
+ */
24
+ smoothTouch?: boolean;
25
+ /**
26
+ * Multiplier for touch scroll sensitivity.
27
+ * Default: 2
28
+ */
29
+ touchMultiplier?: number;
30
+ /**
31
+ * Children elements (optional, component works at document level)
32
+ */
33
+ children?: ReactNode;
34
+ };
6
35
 
7
36
  /**
8
- * WARNING: using this component is not recommended for now.
9
- * It may block or alter certain scroll events (wheel/touch/keyboard) depending on the context.
10
- * Rework it later (e.g., via Lenis or another solution) before using it in production.
37
+ * SmoothScroll component using Lenis for smooth scrolling.
38
+ * This component enables smooth scrolling at the document level.
11
39
  */
12
40
  export const SmoothScroll = ({
13
- transition,
41
+ transition = 1.2,
42
+ easing,
14
43
  orientation = 'vertical',
15
- throttleDuration = 25,
16
- }: {
17
- transition?: {
18
- ease:
19
- | 'linear'
20
- | 'easeIn'
21
- | 'easeOut'
22
- | 'easeInOut'
23
- | 'circIn'
24
- | 'circOut'
25
- | 'circInOut'
26
- | 'backIn'
27
- | 'backOut'
28
- | 'backInOut'
29
- | 'anticipate'
30
- | ((t: number) => number);
31
- duration?: number;
32
- };
33
- } & ReactProps<CustomScrollInterface>) => {
34
- // Target value (instant), driven by wheel/touch/keyboard or native scroll sync
35
- const [scrollY, setScrollY] = useState(0);
36
-
37
- const [el, setEl] = useState<HTMLHtmlElement>();
38
-
39
- const isScrolling = useRef(false);
40
- const scrollTimeoutRef = useRef<NodeJS.Timeout>();
41
- const lastAppliedYRef = useRef(0);
42
-
43
- useEffect(() => {
44
- setEl(document as unknown as HTMLHtmlElement);
45
- const y = document.documentElement.scrollTop;
46
- setScrollY(y);
47
- lastAppliedYRef.current = y;
48
- }, []);
44
+ smoothTouch = false,
45
+ touchMultiplier = 2,
46
+ children,
47
+ }: SmoothScrollProps) => {
48
+ const lenisRef = useRef<Lenis | null>(null);
49
+ const rafRef = useRef<number | null>(null);
49
50
 
50
- // Sync native scroll (e.g., scrollbar, programmatic) back to target after a small delay
51
51
  useEffect(() => {
52
- const onScroll = () => {
53
- if (isScrolling.current) return;
54
- setScrollY(document.documentElement.scrollTop);
55
- };
56
-
57
- el?.addEventListener('scroll', onScroll as unknown as EventListener);
58
- return () => {
59
- if (scrollTimeoutRef.current) clearTimeout(scrollTimeoutRef.current);
60
- el?.removeEventListener('scroll', onScroll as unknown as EventListener);
61
- };
62
- }, [el]);
63
-
64
- // Drive the spring when target changes
65
- const currentY = useRef<number | null>();
66
- const animationRef = useRef<AnimationPlaybackControls | null>(null);
67
- useEffect(() => {
68
- const y = scrollY;
69
-
70
- if (animationRef.current) {
71
- animationRef.current.stop();
72
- animationRef.current = null;
52
+ // Parse duration from string if needed (e.g., '1s' -> 1, '500ms' -> 0.5)
53
+ let duration: number;
54
+ if (typeof transition === 'string') {
55
+ if (transition.endsWith('ms')) {
56
+ duration = parseFloat(transition) / 1000;
57
+ } else if (transition.endsWith('s')) {
58
+ duration = parseFloat(transition);
59
+ } else {
60
+ duration = parseFloat(transition) || 1.2;
61
+ }
62
+ } else {
63
+ duration = transition;
73
64
  }
74
65
 
75
- if (!isScrolling.current) {
76
- currentY.current = y;
77
- return;
78
- }
79
- animationRef.current = animate(currentY.current ?? y, y, {
80
- duration: (transition?.duration ?? 500) / 1000,
81
- ease: transition?.ease ?? 'easeOut',
66
+ // Default easing: easeOutQuint
67
+ const defaultEasing = (t: number) => 1 - Math.pow(1 - t, 5);
68
+
69
+ // Initialize Lenis
70
+ lenisRef.current = new Lenis({
71
+ duration,
72
+ easing: easing ?? defaultEasing,
73
+ orientation,
74
+ smoothWheel: true,
75
+ touchMultiplier,
76
+ syncTouch: smoothTouch,
77
+ });
82
78
 
83
- onUpdate: (value) => {
84
- if (scrollTimeoutRef.current) {
85
- clearTimeout(scrollTimeoutRef.current);
86
- }
87
- currentY.current = value;
79
+ // Animation frame loop
80
+ const raf = (time: number) => {
81
+ lenisRef.current?.raf(time);
82
+ rafRef.current = requestAnimationFrame(raf);
83
+ };
88
84
 
89
- const html = document.documentElement;
90
- // Avoid micro-movements causing extra layout work
91
- const rounded = Math.round(value * 1000) / 1000;
92
- const last = lastAppliedYRef.current;
93
- if (Math.abs(rounded - last) < 0.1) return;
94
- lastAppliedYRef.current = rounded;
85
+ rafRef.current = requestAnimationFrame(raf);
95
86
 
96
- if (isScrolling.current) {
97
- html.scrollTo({ top: rounded });
98
- }
99
- },
100
- onComplete: () => {
101
- scrollTimeoutRef.current = setTimeout(() => {
102
- isScrolling.current = false;
103
- }, 300);
104
- animationRef.current = null;
105
- },
106
- });
87
+ // Cleanup
107
88
  return () => {
108
- // Safety: stop if effect re-runs quickly
109
- if (animationRef.current) {
110
- animationRef.current.stop();
111
- animationRef.current = null;
89
+ if (rafRef.current !== null) {
90
+ cancelAnimationFrame(rafRef.current);
112
91
  }
92
+ lenisRef.current?.destroy();
93
+ lenisRef.current = null;
113
94
  };
114
- }, [scrollY]);
115
-
116
- if (!el) return null;
117
-
118
- return (
119
- <BlockScroll
120
- touch={false}
121
- el={el as unknown as HTMLElement}
122
- onScroll={(scroll) => {
123
- if (
124
- 'deltaY' in scroll &&
125
- scroll.deltaY !== 0 &&
126
- el &&
127
- scrollY !== null
128
- ) {
129
- let y = scrollY + scroll.deltaY;
130
- const html = el.querySelector('html');
131
- if (html) {
132
- y = Math.min(y, html.scrollHeight - html.clientHeight);
133
- }
134
- y = Math.max(y, 0);
135
- setScrollY(y);
95
+ }, [transition, easing, orientation, smoothTouch, touchMultiplier]);
136
96
 
137
- isScrolling.current = true;
138
- }
139
- }}
140
- ></BlockScroll>
141
- );
97
+ return children ? <>{children}</> : null;
142
98
  };
@@ -2,42 +2,51 @@ import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { SmoothScroll } from '../../';
3
3
  import { JSX } from 'react/jsx-runtime';
4
4
 
5
- // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
6
5
  const meta = {
7
6
  title: 'effect/SmoothScroll',
8
7
  component: SmoothScroll,
9
- parameters: {
10
- // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
11
- },
12
- // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
8
+ parameters: {},
13
9
  tags: ['autodocs'],
14
- // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
15
- argTypes: {},
10
+ argTypes: {
11
+ transition: {
12
+ control: { type: 'text' },
13
+ description: 'Duration of the scroll animation (e.g., "1s", "500ms", or number in seconds)',
14
+ },
15
+ orientation: {
16
+ control: { type: 'select' },
17
+ options: ['vertical', 'horizontal'],
18
+ },
19
+ smoothTouch: {
20
+ control: { type: 'boolean' },
21
+ description: 'Enable smooth scrolling on touch devices',
22
+ },
23
+ touchMultiplier: {
24
+ control: { type: 'number' },
25
+ description: 'Multiplier for touch scroll sensitivity',
26
+ },
27
+ },
16
28
  } satisfies Meta<typeof SmoothScroll>;
17
29
 
18
30
  export default meta;
19
31
  type Story = StoryObj<typeof meta>;
20
32
 
21
- // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
22
-
23
33
  const createSmoothScrollStory = () => {
24
34
  const SmoothScrollStory: () => JSX.Element = () => (
25
- <div className={'h-96'}>
26
- <SmoothScroll transition={'1s'}>
27
- <div className={' h-52 bg-primary'} />
28
- <div className={' h-52 bg-secondary'} />
29
- <div className={' h-52 bg-tertiary'} />{' '}
30
- <div className={' h-52 bg-primary'} />
31
- <div className={' h-52 bg-secondary'} />
32
- <div className={' h-52 bg-tertiary'} />{' '}
33
- <div className={' h-52 bg-primary'} />
34
- <div className={' h-52 bg-secondary'} />
35
- <div className={' h-52 bg-tertiary'} />{' '}
36
- <div className={' h-52 bg-primary'} />
37
- <div className={' h-52 bg-secondary'} />
38
- <div className={' h-52 bg-tertiary'} />
39
- </SmoothScroll>
40
- </div>
35
+ <>
36
+ <SmoothScroll transition="1s" />
37
+ <div className="h-52 bg-primary" />
38
+ <div className="h-52 bg-secondary" />
39
+ <div className="h-52 bg-tertiary" />
40
+ <div className="h-52 bg-primary" />
41
+ <div className="h-52 bg-secondary" />
42
+ <div className="h-52 bg-tertiary" />
43
+ <div className="h-52 bg-primary" />
44
+ <div className="h-52 bg-secondary" />
45
+ <div className="h-52 bg-tertiary" />
46
+ <div className="h-52 bg-primary" />
47
+ <div className="h-52 bg-secondary" />
48
+ <div className="h-52 bg-tertiary" />
49
+ </>
41
50
  );
42
51
 
43
52
  return SmoothScrollStory;