@shohojdhara/atomix 0.4.0 → 0.4.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.
Files changed (150) hide show
  1. package/dist/atomix.css +0 -14
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +4 -4
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.d.ts +12 -19
  6. package/dist/charts.js +555 -359
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.d.ts +98 -28
  9. package/dist/core.js +1082 -733
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.d.ts +26 -21
  12. package/dist/forms.js +937 -350
  13. package/dist/forms.js.map +1 -1
  14. package/dist/heavy.d.ts +14 -21
  15. package/dist/heavy.js +409 -256
  16. package/dist/heavy.js.map +1 -1
  17. package/dist/index.d.ts +518 -284
  18. package/dist/index.esm.js +1993 -1237
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/index.js +1994 -1237
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.min.js +1 -1
  23. package/dist/index.min.js.map +1 -1
  24. package/package.json +2 -2
  25. package/scripts/atomix-cli.js +43 -1
  26. package/scripts/cli/__tests__/utils.test.js +6 -2
  27. package/scripts/cli/migration-tools.js +2 -2
  28. package/scripts/cli/theme-bridge.js +7 -9
  29. package/scripts/cli/utils.js +2 -1
  30. package/src/components/Accordion/Accordion.stories.tsx +40 -0
  31. package/src/components/Accordion/Accordion.tsx +174 -56
  32. package/src/components/Accordion/AccordionCompound.test.tsx +70 -0
  33. package/src/components/AtomixGlass/AtomixGlass.tsx +82 -54
  34. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +17 -18
  35. package/src/components/AtomixGlass/README.md +5 -5
  36. package/src/components/AtomixGlass/stories/Customization.stories.tsx +2 -2
  37. package/src/components/AtomixGlass/stories/Examples.stories.tsx +42 -42
  38. package/src/components/AtomixGlass/stories/Modes.stories.tsx +5 -5
  39. package/src/components/AtomixGlass/stories/Overview.stories.tsx +3 -3
  40. package/src/components/AtomixGlass/stories/Performance.stories.tsx +2 -2
  41. package/src/components/AtomixGlass/stories/Playground.stories.tsx +45 -45
  42. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +3 -3
  43. package/src/components/Badge/Badge.stories.tsx +1 -1
  44. package/src/components/Badge/Badge.tsx +1 -1
  45. package/src/components/Breadcrumb/Breadcrumb.tsx +185 -65
  46. package/src/components/Breadcrumb/BreadcrumbCompound.test.tsx +84 -0
  47. package/src/components/Breadcrumb/index.ts +2 -2
  48. package/src/components/Button/Button.stories.tsx +1 -1
  49. package/src/components/Button/README.md +2 -2
  50. package/src/components/Callout/Callout.stories.tsx +166 -1011
  51. package/src/components/Callout/Callout.test.tsx +3 -3
  52. package/src/components/Callout/Callout.tsx +196 -84
  53. package/src/components/Callout/CalloutCompound.test.tsx +72 -0
  54. package/src/components/Callout/README.md +2 -2
  55. package/src/components/Chart/Chart.stories.tsx +1 -1
  56. package/src/components/Chart/Chart.tsx +5 -5
  57. package/src/components/Chart/TreemapChart.tsx +37 -29
  58. package/src/components/DatePicker/readme.md +3 -3
  59. package/src/components/Dropdown/Dropdown.stories.tsx +1 -1
  60. package/src/components/Dropdown/Dropdown.tsx +133 -20
  61. package/src/components/Dropdown/DropdownCompound.test.tsx +64 -0
  62. package/src/components/EdgePanel/EdgePanel.stories.tsx +7 -7
  63. package/src/components/EdgePanel/EdgePanel.tsx +164 -112
  64. package/src/components/EdgePanel/EdgePanelCompound.test.tsx +53 -0
  65. package/src/components/Form/Checkbox.stories.tsx +1 -1
  66. package/src/components/Form/Checkbox.tsx +1 -1
  67. package/src/components/Form/Input.stories.tsx +1 -1
  68. package/src/components/Form/Input.tsx +1 -1
  69. package/src/components/Form/Radio.stories.tsx +1 -1
  70. package/src/components/Form/Radio.tsx +1 -1
  71. package/src/components/Form/Select.stories.tsx +24 -1
  72. package/src/components/Form/Select.test.tsx +99 -0
  73. package/src/components/Form/Select.tsx +145 -94
  74. package/src/components/Form/SelectOption.tsx +88 -0
  75. package/src/components/Form/Textarea.stories.tsx +1 -1
  76. package/src/components/Form/Textarea.tsx +1 -1
  77. package/src/components/Hero/Hero.stories.tsx +39 -2
  78. package/src/components/Hero/Hero.test.tsx +142 -0
  79. package/src/components/Hero/Hero.tsx +143 -4
  80. package/src/components/List/List.test.tsx +62 -0
  81. package/src/components/List/List.tsx +16 -5
  82. package/src/components/List/ListItem.tsx +20 -0
  83. package/src/components/Messages/Messages.stories.tsx +1 -1
  84. package/src/components/Messages/Messages.tsx +2 -2
  85. package/src/components/Modal/Modal.stories.tsx +66 -2
  86. package/src/components/Modal/Modal.tsx +115 -35
  87. package/src/components/Modal/ModalCompound.test.tsx +94 -0
  88. package/src/components/Navigation/Nav/Nav.stories.tsx +2 -2
  89. package/src/components/Navigation/Nav/Nav.tsx +1 -1
  90. package/src/components/Navigation/Navbar/Navbar.stories.tsx +3 -3
  91. package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
  92. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +2 -2
  93. package/src/components/Navigation/SideMenu/SideMenu.tsx +1 -1
  94. package/src/components/Pagination/Pagination.stories.tsx +1 -1
  95. package/src/components/Pagination/Pagination.tsx +1 -1
  96. package/src/components/Popover/Popover.stories.tsx +1 -1
  97. package/src/components/Popover/Popover.tsx +1 -1
  98. package/src/components/Progress/Progress.tsx +1 -1
  99. package/src/components/Rating/Rating.stories.tsx +1 -1
  100. package/src/components/Rating/Rating.test.tsx +73 -0
  101. package/src/components/Rating/Rating.tsx +25 -37
  102. package/src/components/Spinner/Spinner.tsx +1 -1
  103. package/src/components/Steps/Steps.stories.tsx +1 -1
  104. package/src/components/Steps/Steps.tsx +125 -22
  105. package/src/components/Steps/StepsCompound.test.tsx +81 -0
  106. package/src/components/Tabs/Tabs.stories.tsx +1 -1
  107. package/src/components/Tabs/Tabs.tsx +198 -45
  108. package/src/components/Tabs/TabsCompound.test.tsx +64 -0
  109. package/src/components/Todo/Todo.tsx +0 -1
  110. package/src/components/Toggle/Toggle.stories.tsx +1 -1
  111. package/src/components/Toggle/Toggle.tsx +1 -1
  112. package/src/components/Tooltip/Tooltip.stories.tsx +1 -1
  113. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +2 -2
  114. package/src/lib/composables/__tests__/useAtomixGlassPerf.test.tsx +88 -0
  115. package/src/lib/composables/__tests__/useChart.test.ts +50 -0
  116. package/src/lib/composables/__tests__/useChart.test.tsx +139 -0
  117. package/src/lib/composables/__tests__/useHeroBackgroundSlider.test.tsx +59 -0
  118. package/src/lib/composables/__tests__/useSliderAutoplay.test.tsx +68 -0
  119. package/src/lib/composables/atomix-glass/useGlassBackgroundDetection.ts +329 -0
  120. package/src/lib/composables/atomix-glass/useGlassCornerRadius.ts +82 -0
  121. package/src/lib/composables/atomix-glass/useGlassMouseTracking.ts +153 -0
  122. package/src/lib/composables/atomix-glass/useGlassOverLight.ts +198 -0
  123. package/src/lib/composables/atomix-glass/useGlassSize.ts +117 -0
  124. package/src/lib/composables/atomix-glass/useGlassState.ts +112 -0
  125. package/src/lib/composables/atomix-glass/useGlassTransforms.ts +160 -0
  126. package/src/lib/composables/glass-styles.ts +302 -0
  127. package/src/lib/composables/index.ts +0 -8
  128. package/src/lib/composables/useAtomixGlass.ts +331 -537
  129. package/src/lib/composables/useAtomixGlassStyles.ts +307 -0
  130. package/src/lib/composables/useBarChart.ts +1 -1
  131. package/src/lib/composables/useBreadcrumb.ts +6 -6
  132. package/src/lib/composables/useChart.ts +104 -21
  133. package/src/lib/composables/useHeroBackgroundSlider.ts +16 -7
  134. package/src/lib/composables/useSlider.ts +66 -34
  135. package/src/lib/theme/devtools/CLI.ts +2 -10
  136. package/src/lib/theme/utils/__tests__/themeUtils.test.ts +213 -0
  137. package/src/lib/types/components.ts +21 -23
  138. package/src/lib/utils/__tests__/componentUtils.test.ts +57 -2
  139. package/src/lib/utils/__tests__/dom.test.ts +100 -0
  140. package/src/lib/utils/__tests__/fontPreloader.test.ts +102 -0
  141. package/src/lib/utils/__tests__/themeNaming.test.ts +117 -0
  142. package/src/lib/utils/themeNaming.ts +1 -1
  143. package/src/styles/06-components/_components.accordion.scss +0 -2
  144. package/src/styles/06-components/_components.chart.scss +0 -1
  145. package/src/styles/06-components/_components.dropdown.scss +0 -1
  146. package/src/styles/06-components/_components.edge-panel.scss +0 -2
  147. package/src/styles/06-components/_components.photoviewer.scss +0 -1
  148. package/src/styles/06-components/_components.river.scss +0 -1
  149. package/src/styles/06-components/_components.slider.scss +0 -3
  150. package/src/styles/99-utilities/_utilities.glass-fixes.scss +0 -1
@@ -121,7 +121,7 @@ export const Toggle: React.FC<ToggleProps> = ({
121
121
  blurAmount: 1,
122
122
  saturation: 160,
123
123
  aberrationIntensity: 0.5,
124
- cornerRadius: 8,
124
+ borderRadius: 8,
125
125
  mode: 'shader' as const,
126
126
  };
127
127
 
@@ -349,7 +349,7 @@ export const GlassTooltipCustom: Story = {
349
349
  blurAmount: 2,
350
350
  saturation: 200,
351
351
  aberrationIntensity: 1,
352
- cornerRadius: 12,
352
+ borderRadius: 12,
353
353
  mode: 'polar',
354
354
  } as GlassProps,
355
355
  } as any,
@@ -813,7 +813,7 @@ export const GlassCustom: Story = {
813
813
  saturation: 180,
814
814
  aberrationIntensity: 2.5,
815
815
  elasticity: 0.4,
816
- cornerRadius: 20,
816
+ borderRadius: 20,
817
817
  mode: 'prominent',
818
818
  overLight: false,
819
819
  },
@@ -1071,7 +1071,7 @@ export const GlassWithInteractiveContent: Story = {
1071
1071
  saturation: 170,
1072
1072
  aberrationIntensity: 2,
1073
1073
  elasticity: 0.3,
1074
- cornerRadius: 15,
1074
+ borderRadius: 15,
1075
1075
  mode: 'standard',
1076
1076
  },
1077
1077
  glassOpacity: 0.6,
@@ -0,0 +1,88 @@
1
+ import React, { useRef } from 'react';
2
+ import { render, act } from '@testing-library/react';
3
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
4
+ import { useAtomixGlass } from '../useAtomixGlass';
5
+
6
+ describe('useAtomixGlass Performance', () => {
7
+ let renderCount = 0;
8
+ let glassRefOut: React.RefObject<HTMLDivElement> | null = null;
9
+
10
+ const TestComponent = () => {
11
+ renderCount++;
12
+ const glassRef = useRef<HTMLDivElement>(null);
13
+ const contentRef = useRef<HTMLDivElement>(null);
14
+ glassRefOut = glassRef;
15
+
16
+ useAtomixGlass({
17
+ glassRef,
18
+ contentRef,
19
+ elasticity: 0.1, // Ensure elasticity so transform changes
20
+ });
21
+
22
+ return (
23
+ <div ref={glassRef} style={{ width: 200, height: 100 }}>
24
+ <div ref={contentRef}>Content</div>
25
+ </div>
26
+ );
27
+ };
28
+
29
+ beforeEach(() => {
30
+ renderCount = 0;
31
+ glassRefOut = null;
32
+ // Mock getBoundingClientRect
33
+ Element.prototype.getBoundingClientRect = vi.fn(() => ({
34
+ width: 200,
35
+ height: 100,
36
+ top: 0,
37
+ left: 0,
38
+ bottom: 100,
39
+ right: 200,
40
+ x: 0,
41
+ y: 0,
42
+ toJSON: () => {},
43
+ }));
44
+ vi.useFakeTimers();
45
+ });
46
+
47
+ afterEach(() => {
48
+ vi.useRealTimers();
49
+ vi.restoreAllMocks();
50
+ });
51
+
52
+ it('does not re-render on mouse move but updates styles', async () => {
53
+ render(<TestComponent />);
54
+
55
+ // Run initial effects
56
+ await act(async () => {
57
+ vi.runAllTimers();
58
+ });
59
+
60
+ const countAfterSetup = renderCount;
61
+ const initialTransform = glassRefOut?.current?.style.transform;
62
+ console.log(`Initial transform: ${initialTransform}`);
63
+
64
+ // Simulate mouse move
65
+ const moveEvent = new MouseEvent('mousemove', {
66
+ clientX: 50,
67
+ clientY: 50,
68
+ bubbles: true,
69
+ });
70
+
71
+ await act(async () => {
72
+ document.dispatchEvent(moveEvent);
73
+ vi.runAllTimers();
74
+ });
75
+
76
+ console.log(`Render count: ${renderCount}`);
77
+
78
+ // Expect NO re-render
79
+ expect(renderCount).toBe(countAfterSetup);
80
+
81
+ // Expect style update
82
+ const finalTransform = glassRefOut?.current?.style.transform;
83
+ console.log(`Final transform: ${finalTransform}`);
84
+
85
+ expect(finalTransform).not.toBe(initialTransform);
86
+ expect(finalTransform).toContain('translate');
87
+ });
88
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { getDatasetBounds } from '../useChart';
3
+ import { ChartDataPoint } from '../../types/components';
4
+
5
+ describe('useChart', () => {
6
+ describe('getDatasetBounds', () => {
7
+ it('should correctly calculate min and max for valid numeric data', () => {
8
+ const data: ChartDataPoint[] = [
9
+ { label: 'A', value: 10 },
10
+ { label: 'B', value: 5 },
11
+ { label: 'C', value: 20 },
12
+ ];
13
+ const result = getDatasetBounds(data);
14
+ expect(result).toEqual({ min: 5, max: 20, hasValid: true });
15
+ });
16
+
17
+ it('should handle empty data', () => {
18
+ const data: ChartDataPoint[] = [];
19
+ const result = getDatasetBounds(data);
20
+ expect(result).toEqual({ min: Infinity, max: -Infinity, hasValid: false });
21
+ });
22
+
23
+ it('should handle undefined data', () => {
24
+ const result = getDatasetBounds(undefined);
25
+ expect(result).toEqual({ min: Infinity, max: -Infinity, hasValid: false });
26
+ });
27
+
28
+ it('should ignore invalid values', () => {
29
+ const data: any[] = [
30
+ { label: 'A', value: 10 },
31
+ { label: 'B', value: 'invalid' },
32
+ { label: 'C', value: null },
33
+ { label: 'D', value: 30 },
34
+ ];
35
+ const result = getDatasetBounds(data as ChartDataPoint[]);
36
+ expect(result).toEqual({ min: 10, max: 30, hasValid: true });
37
+ });
38
+
39
+ it('should handle large datasets without stack overflow', () => {
40
+ const size = 150000;
41
+ const data: ChartDataPoint[] = Array.from({ length: size }, (_, i) => ({
42
+ label: `Point ${i}`,
43
+ value: i
44
+ }));
45
+
46
+ const result = getDatasetBounds(data);
47
+ expect(result).toEqual({ min: 0, max: size - 1, hasValid: true });
48
+ });
49
+ });
50
+ });
@@ -0,0 +1,139 @@
1
+ import { renderHook, act } from '@testing-library/react';
2
+ import { useChartData } from '../useChart';
3
+ import { ChartDataset } from '../../types/components';
4
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
5
+
6
+ describe('useChartData - Real-time Optimization', () => {
7
+ beforeEach(() => {
8
+ vi.useFakeTimers();
9
+ });
10
+
11
+ afterEach(() => {
12
+ vi.useRealTimers();
13
+ });
14
+
15
+ it('should not update processedData if data has not changed', () => {
16
+ const datasets: ChartDataset[] = [
17
+ {
18
+ label: 'Dataset 1',
19
+ data: [
20
+ { label: '1', value: 10 },
21
+ { label: '2', value: 20 },
22
+ ],
23
+ },
24
+ ];
25
+
26
+ const { result } = renderHook(() =>
27
+ useChartData(datasets, {
28
+ enableRealTime: true,
29
+ realTimeInterval: 1000,
30
+ enableDecimation: false,
31
+ })
32
+ );
33
+
34
+ const initialData = result.current.processedData;
35
+
36
+ // Advance time
37
+ act(() => {
38
+ vi.advanceTimersByTime(1100);
39
+ });
40
+
41
+ expect(result.current.processedData).toBe(initialData);
42
+ });
43
+
44
+ it('should update processedData if data length changes (mutation)', () => {
45
+ const datasets: ChartDataset[] = [
46
+ {
47
+ label: 'Dataset 1',
48
+ data: [
49
+ { label: '1', value: 10 },
50
+ { label: '2', value: 20 },
51
+ ],
52
+ },
53
+ ];
54
+
55
+ const { result } = renderHook(() =>
56
+ useChartData(datasets, {
57
+ enableRealTime: true,
58
+ realTimeInterval: 1000,
59
+ enableDecimation: false,
60
+ })
61
+ );
62
+
63
+ const initialData = result.current.processedData;
64
+
65
+ datasets[0].data.push({ label: '3', value: 30 });
66
+
67
+ act(() => {
68
+ vi.advanceTimersByTime(1100);
69
+ });
70
+
71
+ expect(result.current.processedData).not.toBe(initialData);
72
+ expect(result.current.processedData[0].data.length).toBe(3);
73
+ });
74
+
75
+ it('should update processedData if data value changes (mutation)', () => {
76
+ const datasets: ChartDataset[] = [
77
+ {
78
+ label: 'Dataset 1',
79
+ data: [
80
+ { label: '1', value: 10 },
81
+ { label: '2', value: 20 },
82
+ ],
83
+ },
84
+ ];
85
+
86
+ const { result } = renderHook(() =>
87
+ useChartData(datasets, {
88
+ enableRealTime: true,
89
+ realTimeInterval: 1000,
90
+ enableDecimation: false,
91
+ })
92
+ );
93
+
94
+ const initialData = result.current.processedData;
95
+
96
+ datasets[0].data[1].value = 25;
97
+
98
+ act(() => {
99
+ vi.advanceTimersByTime(1100);
100
+ });
101
+
102
+ expect(result.current.processedData).not.toBe(initialData);
103
+ expect(result.current.processedData[0].data[1].value).toBe(25);
104
+ });
105
+
106
+ it('should update processedData if historical data changes (mutation)', () => {
107
+ const datasets: ChartDataset[] = [
108
+ {
109
+ label: 'Dataset 1',
110
+ data: [
111
+ { label: '1', value: 10 },
112
+ { label: '2', value: 20 },
113
+ { label: '3', value: 30 },
114
+ ],
115
+ },
116
+ ];
117
+
118
+ const { result } = renderHook(() =>
119
+ useChartData(datasets, {
120
+ enableRealTime: true,
121
+ realTimeInterval: 1000,
122
+ enableDecimation: false,
123
+ })
124
+ );
125
+
126
+ const initialData = result.current.processedData;
127
+
128
+ // Mutate historical data (index 0)
129
+ datasets[0].data[0].value = 15;
130
+
131
+ act(() => {
132
+ vi.advanceTimersByTime(1100);
133
+ });
134
+
135
+ // Should update
136
+ expect(result.current.processedData).not.toBe(initialData);
137
+ expect(result.current.processedData[0].data[0].value).toBe(15);
138
+ });
139
+ });
@@ -0,0 +1,59 @@
1
+ import { renderHook, act } from '@testing-library/react';
2
+ import { useHeroBackgroundSlider } from '../useHeroBackgroundSlider';
3
+ import { HeroBackgroundSliderConfig } from '../../types/components';
4
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
5
+
6
+ describe('useHeroBackgroundSlider Performance', () => {
7
+ beforeEach(() => {
8
+ vi.useFakeTimers();
9
+ });
10
+
11
+ afterEach(() => {
12
+ vi.useRealTimers();
13
+ vi.restoreAllMocks();
14
+ });
15
+
16
+ it('should not reset interval frequently during autoplay', () => {
17
+ const config: HeroBackgroundSliderConfig = {
18
+ slides: [
19
+ { type: 'image', src: 'slide1.jpg' },
20
+ { type: 'image', src: 'slide2.jpg' },
21
+ { type: 'image', src: 'slide3.jpg' },
22
+ ],
23
+ autoplay: {
24
+ delay: 3000,
25
+ },
26
+ transitionDuration: 1000,
27
+ };
28
+
29
+ const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
30
+
31
+ const { result } = renderHook(() => useHeroBackgroundSlider(config));
32
+
33
+ // Reset call count after initial render
34
+ clearIntervalSpy.mockClear();
35
+
36
+ // 1st Transition
37
+ act(() => {
38
+ vi.advanceTimersByTime(3000);
39
+ });
40
+
41
+ act(() => {
42
+ vi.advanceTimersByTime(1000);
43
+ });
44
+
45
+ // 2nd Transition
46
+ act(() => {
47
+ vi.advanceTimersByTime(3000);
48
+ });
49
+
50
+ act(() => {
51
+ vi.advanceTimersByTime(1000);
52
+ });
53
+
54
+ console.log(`clearInterval calls: ${clearIntervalSpy.mock.calls.length}`);
55
+
56
+ // With optimization, the interval should persist and not be cleared during transitions
57
+ expect(clearIntervalSpy).toHaveBeenCalledTimes(0);
58
+ });
59
+ });
@@ -0,0 +1,68 @@
1
+ import { renderHook, act } from '@testing-library/react';
2
+ import { useSlider } from '../useSlider';
3
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
4
+ import { SliderSlide } from '../../types/components';
5
+
6
+ describe('useSlider Autoplay Optimization', () => {
7
+ const slides: SliderSlide[] = [
8
+ { id: '1', content: 'Slide 1' },
9
+ { id: '2', content: 'Slide 2' },
10
+ { id: '3', content: 'Slide 3' },
11
+ ];
12
+
13
+ beforeEach(() => {
14
+ vi.useFakeTimers();
15
+ });
16
+
17
+ afterEach(() => {
18
+ vi.useRealTimers();
19
+ vi.restoreAllMocks();
20
+ });
21
+
22
+ it('should not reset interval when transitioning state changes', () => {
23
+ const setIntervalSpy = vi.spyOn(global, 'setInterval');
24
+ const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
25
+
26
+ const autoplayConfig = { delay: 1000 };
27
+
28
+ const { result } = renderHook(() =>
29
+ useSlider({
30
+ slides,
31
+ autoplay: autoplayConfig,
32
+ speed: 300,
33
+ slidesToShow: 1,
34
+ })
35
+ );
36
+
37
+ // Initial render should set interval.
38
+ // Note: It might be called more than once due to initial state updates (like internalIndex setting)
39
+ // causing re-renders if dependencies are unstable, though refs should be stable.
40
+ // However, strictly, we want to verify it doesn't reset DURING autoplay cycle.
41
+
42
+ // Let's clear mocks after initial render is done.
43
+ setIntervalSpy.mockClear();
44
+ clearIntervalSpy.mockClear();
45
+
46
+ // Fast-forward to trigger autoplay
47
+ act(() => {
48
+ vi.advanceTimersByTime(1000);
49
+ });
50
+
51
+ // Check if transition started
52
+ expect(result.current.transitioning).toBe(true);
53
+
54
+ // At this point, in the buggy version, transitioning becoming true triggers the effect cleanup and re-setup.
55
+ // So we expect setInterval/clearInterval to have been called.
56
+
57
+ // Let's see what happens after transition ends
58
+ act(() => {
59
+ vi.advanceTimersByTime(300); // speed is 300
60
+ });
61
+
62
+ expect(result.current.transitioning).toBe(false);
63
+
64
+ // In the optimized version, these should be 0 because the interval persists.
65
+ expect(setIntervalSpy).toHaveBeenCalledTimes(0);
66
+ expect(clearIntervalSpy).toHaveBeenCalledTimes(0);
67
+ });
68
+ });