@shohojdhara/atomix 0.2.1 → 0.2.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 (132) hide show
  1. package/README.md +1 -28
  2. package/dist/atomix.css +1810 -314
  3. package/dist/atomix.min.css +5 -5
  4. package/dist/index.d.ts +359 -3
  5. package/dist/index.esm.js +831 -124
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +834 -123
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/dist/themes/boomdevs.css +1808 -372
  12. package/dist/themes/boomdevs.min.css +60 -8
  13. package/dist/themes/esrar.css +1810 -314
  14. package/dist/themes/esrar.min.css +6 -6
  15. package/dist/themes/mashroom.css +1807 -308
  16. package/dist/themes/mashroom.min.css +8 -8
  17. package/dist/themes/shaj-default.css +1772 -273
  18. package/dist/themes/shaj-default.min.css +6 -6
  19. package/dist/themes/yabai.css +1804 -308
  20. package/dist/themes/yabai.min.css +8 -8
  21. package/package.json +1 -1
  22. package/src/components/Footer/Footer.stories.tsx +388 -0
  23. package/src/components/Footer/Footer.tsx +197 -0
  24. package/src/components/Footer/FooterLink.tsx +72 -0
  25. package/src/components/Footer/FooterSection.tsx +87 -0
  26. package/src/components/Footer/FooterSocialLink.tsx +117 -0
  27. package/src/components/Footer/README.md +261 -0
  28. package/src/components/Footer/index.ts +13 -0
  29. package/src/components/SectionIntro/SectionIntro.tsx +9 -11
  30. package/src/components/Slider/Slider.stories.tsx +634 -50
  31. package/src/components/Slider/Slider.tsx +5 -3
  32. package/src/components/index.ts +13 -0
  33. package/src/layouts/Grid/Grid.stories.tsx +226 -159
  34. package/src/lib/composables/useFooter.ts +85 -0
  35. package/src/lib/composables/useSlider.ts +191 -4
  36. package/src/lib/constants/components.ts +85 -0
  37. package/src/lib/types/components.ts +270 -0
  38. package/src/styles/01-settings/_index.scss +1 -0
  39. package/src/styles/01-settings/_settings.accordion.scss +20 -19
  40. package/src/styles/01-settings/_settings.animations.scss +5 -5
  41. package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
  42. package/src/styles/01-settings/_settings.avatar.scss +17 -18
  43. package/src/styles/01-settings/_settings.background.scss +9 -0
  44. package/src/styles/01-settings/_settings.badge.scss +1 -1
  45. package/src/styles/01-settings/_settings.breadcrumb.scss +8 -2
  46. package/src/styles/01-settings/_settings.card.scss +2 -2
  47. package/src/styles/01-settings/_settings.chart.scss +7 -7
  48. package/src/styles/01-settings/_settings.checkbox-group.scss +5 -2
  49. package/src/styles/01-settings/_settings.checkbox.scss +10 -4
  50. package/src/styles/01-settings/_settings.countdown.scss +6 -4
  51. package/src/styles/01-settings/_settings.dropdown.scss +9 -7
  52. package/src/styles/01-settings/_settings.edge-panel.scss +3 -2
  53. package/src/styles/01-settings/_settings.footer.scss +125 -0
  54. package/src/styles/01-settings/_settings.form-group.scss +3 -1
  55. package/src/styles/01-settings/_settings.form.scss +4 -2
  56. package/src/styles/01-settings/_settings.hero.scss +9 -7
  57. package/src/styles/01-settings/_settings.input.scss +9 -7
  58. package/src/styles/01-settings/_settings.list-group.scss +4 -2
  59. package/src/styles/01-settings/_settings.list.scss +4 -2
  60. package/src/styles/01-settings/_settings.menu.scss +10 -8
  61. package/src/styles/01-settings/_settings.messages.scss +19 -17
  62. package/src/styles/01-settings/_settings.modal.scss +6 -4
  63. package/src/styles/01-settings/_settings.nav.scss +6 -4
  64. package/src/styles/01-settings/_settings.navbar.scss +8 -5
  65. package/src/styles/01-settings/_settings.pagination.scss +5 -3
  66. package/src/styles/01-settings/_settings.popover.scss +6 -4
  67. package/src/styles/01-settings/_settings.rating.scss +5 -3
  68. package/src/styles/01-settings/_settings.river.scss +8 -6
  69. package/src/styles/01-settings/_settings.sectionintro.scss +8 -6
  70. package/src/styles/01-settings/_settings.select.scss +7 -5
  71. package/src/styles/01-settings/_settings.side-menu.scss +15 -13
  72. package/src/styles/01-settings/_settings.spacing.scss +4 -0
  73. package/src/styles/01-settings/_settings.steps.scss +7 -5
  74. package/src/styles/01-settings/_settings.tabs.scss +7 -5
  75. package/src/styles/01-settings/_settings.testimonials.scss +6 -4
  76. package/src/styles/01-settings/_settings.toggle.scss +3 -1
  77. package/src/styles/01-settings/_settings.tooltip.scss +5 -3
  78. package/src/styles/01-settings/_settings.upload.scss +22 -20
  79. package/src/styles/02-tools/_tools.background.scss +85 -0
  80. package/src/styles/02-tools/_tools.rem.scss +18 -5
  81. package/src/styles/02-tools/_tools.utility-api.scss +32 -26
  82. package/src/styles/03-generic/_generic.root.scss +14 -2
  83. package/src/styles/04-elements/_elements.body.scss +24 -0
  84. package/src/styles/06-components/_components.accordion.scss +8 -4
  85. package/src/styles/06-components/_components.avatar-group.scss +2 -1
  86. package/src/styles/06-components/_components.avatar.scss +2 -1
  87. package/src/styles/06-components/_components.badge.scss +2 -1
  88. package/src/styles/06-components/_components.breadcrumb.scss +2 -1
  89. package/src/styles/06-components/_components.button.scss +4 -3
  90. package/src/styles/06-components/_components.callout.scss +3 -2
  91. package/src/styles/06-components/_components.card.scss +4 -2
  92. package/src/styles/06-components/_components.chart.scss +2 -1
  93. package/src/styles/06-components/_components.checkbox.scss +2 -1
  94. package/src/styles/06-components/_components.color-mode-toggle.scss +3 -2
  95. package/src/styles/06-components/_components.countdown.scss +2 -1
  96. package/src/styles/06-components/_components.data-table.scss +7 -6
  97. package/src/styles/06-components/_components.datepicker.scss +2 -1
  98. package/src/styles/06-components/_components.dropdown.scss +4 -3
  99. package/src/styles/06-components/_components.edge-panel.scss +4 -3
  100. package/src/styles/06-components/_components.footer.scss +825 -0
  101. package/src/styles/06-components/_components.form-group.scss +1 -0
  102. package/src/styles/06-components/_components.hero.scss +3 -2
  103. package/src/styles/06-components/_components.image-gallery.scss +1 -0
  104. package/src/styles/06-components/_components.input.scss +2 -1
  105. package/src/styles/06-components/_components.list-group.scss +3 -2
  106. package/src/styles/06-components/_components.list.scss +2 -1
  107. package/src/styles/06-components/_components.menu.scss +5 -4
  108. package/src/styles/06-components/_components.messages.scss +8 -7
  109. package/src/styles/06-components/_components.modal.scss +3 -2
  110. package/src/styles/06-components/_components.nav.scss +6 -5
  111. package/src/styles/06-components/_components.navbar.scss +4 -3
  112. package/src/styles/06-components/_components.pagination.scss +2 -1
  113. package/src/styles/06-components/_components.photoviewer.scss +4 -3
  114. package/src/styles/06-components/_components.popover.scss +3 -2
  115. package/src/styles/06-components/_components.product-review.scss +3 -2
  116. package/src/styles/06-components/_components.progress.scss +3 -2
  117. package/src/styles/06-components/_components.river.scss +3 -2
  118. package/src/styles/06-components/_components.sectionintro.scss +2 -1
  119. package/src/styles/06-components/_components.select.scss +5 -4
  120. package/src/styles/06-components/_components.side-menu.scss +8 -7
  121. package/src/styles/06-components/_components.skeleton.scss +3 -2
  122. package/src/styles/06-components/_components.slider.scss +7 -6
  123. package/src/styles/06-components/_components.spinner.scss +1 -0
  124. package/src/styles/06-components/_components.steps.scss +3 -2
  125. package/src/styles/06-components/_components.tabs.scss +4 -3
  126. package/src/styles/06-components/_components.testimonials.scss +2 -1
  127. package/src/styles/06-components/_components.todo.scss +3 -2
  128. package/src/styles/06-components/_components.toggle.scss +5 -4
  129. package/src/styles/06-components/_components.tooltip.scss +3 -2
  130. package/src/styles/06-components/_components.upload.scss +4 -3
  131. package/src/styles/06-components/_components.video-player.scss +4 -3
  132. package/src/styles/06-components/_index.scss +1 -0
@@ -0,0 +1,85 @@
1
+ import { FooterLayout, ThemeColor, Size, SocialLink } from '../types/components';
2
+ import { FOOTER } from '../constants/components';
3
+
4
+ export interface UseFooterOptions {
5
+ layout?: FooterLayout;
6
+ variant?: ThemeColor;
7
+ size?: Size;
8
+ sticky?: boolean;
9
+ showNewsletter?: boolean;
10
+ showBackToTop?: boolean;
11
+ socialLinks?: SocialLink[];
12
+ onNewsletterSubmit?: (email: string) => void | Promise<void>;
13
+ onBackToTop?: () => void;
14
+ className?: string;
15
+ }
16
+
17
+
18
+
19
+ export function useFooter(options: UseFooterOptions = {}) {
20
+ const {
21
+ layout = FOOTER.DEFAULTS.LAYOUT,
22
+ variant = FOOTER.DEFAULTS.VARIANT,
23
+ size = FOOTER.DEFAULTS.SIZE,
24
+ sticky = FOOTER.DEFAULTS.STICKY,
25
+ showNewsletter = FOOTER.DEFAULTS.SHOW_NEWSLETTER,
26
+ showBackToTop = FOOTER.DEFAULTS.SHOW_BACK_TO_TOP,
27
+ socialLinks = [],
28
+ onNewsletterSubmit,
29
+ onBackToTop,
30
+ className = '',
31
+ } = options;
32
+
33
+ // Generate footer classes
34
+ const footerClass = (() => {
35
+ const classes = [
36
+ FOOTER.CLASSES.BASE,
37
+ FOOTER.CLASSES[layout.toUpperCase() as keyof typeof FOOTER.CLASSES] || FOOTER.CLASSES.COLUMNS,
38
+ `c-footer--${variant}`,
39
+ FOOTER.CLASSES[size.toUpperCase() as keyof typeof FOOTER.CLASSES] || FOOTER.CLASSES.MD,
40
+ sticky && FOOTER.CLASSES.STICKY,
41
+ className,
42
+ ];
43
+ return classes.filter(Boolean).join(' ');
44
+ })();
45
+
46
+ const containerClass = FOOTER.CLASSES.CONTAINER;
47
+ const brandClass = FOOTER.CLASSES.BRAND;
48
+ const sectionsClass = (() => {
49
+ const classes = [
50
+ FOOTER.CLASSES.SECTIONS,
51
+ layout === 'columns' && 'c-footer__sections--columns',
52
+ layout === 'centered' && 'c-footer__sections--centered',
53
+ layout === 'stacked' && 'c-footer__sections--stacked',
54
+ ];
55
+ return classes.filter(Boolean).join(' ');
56
+ })();
57
+ const bottomClass = FOOTER.CLASSES.BOTTOM;
58
+
59
+ // Handle newsletter submission
60
+ const handleNewsletterSubmit = (email: string) => {
61
+ if (onNewsletterSubmit) {
62
+ onNewsletterSubmit(email);
63
+ }
64
+ };
65
+
66
+ // Handle back to top
67
+ const handleBackToTop = () => {
68
+ if (onBackToTop) {
69
+ onBackToTop();
70
+ } else {
71
+ window.scrollTo({ top: 0, behavior: 'smooth' });
72
+ }
73
+ };
74
+
75
+ return {
76
+ footerClass,
77
+ containerClass,
78
+ brandClass,
79
+ sectionsClass,
80
+ bottomClass,
81
+ handleNewsletterSubmit,
82
+ handleBackToTop,
83
+ socialLinks,
84
+ };
85
+ }
@@ -35,12 +35,15 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
35
35
  speed = 300,
36
36
  allowTouchMove = true,
37
37
  threshold = 50,
38
+ autoplay,
38
39
  onSlideChange,
39
40
  } = options;
40
41
 
41
42
  const containerRef = useRef<HTMLDivElement | null>(null);
42
43
  const wrapperRef = useRef<HTMLDivElement | null>(null);
43
44
  const repositioningRef = useRef(false);
45
+ const autoplayRef = useRef<NodeJS.Timeout | null>(null);
46
+ const [autoplayRunning, setAutoplayRunning] = useState(false);
44
47
 
45
48
  const [realIndex, setRealIndex] = useState(initialSlide);
46
49
  const [internalIndex, setInternalIndex] = useState(0);
@@ -73,6 +76,160 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
73
76
  return -(internalIndex * slideWidth) + dragOffset;
74
77
  }, [slideWidth, internalIndex, dragOffset]);
75
78
 
79
+ // Autoplay effect
80
+ useEffect(() => {
81
+ if (!autoplay) {
82
+ if (autoplayRef.current) {
83
+ clearInterval(autoplayRef.current);
84
+ autoplayRef.current = null;
85
+ }
86
+ setAutoplayRunning(false);
87
+ return;
88
+ }
89
+
90
+ const autoplayParams = typeof autoplay === 'boolean' ? { delay: 3000 } : autoplay;
91
+ const { delay = 3000, pauseOnMouseEnter = false, disableOnInteraction = false, reverseDirection = false } = autoplayParams;
92
+
93
+ // Clear any existing interval
94
+ if (autoplayRef.current) {
95
+ clearInterval(autoplayRef.current);
96
+ }
97
+
98
+ // Create new interval
99
+ autoplayRef.current = setInterval(() => {
100
+ // We need to use a functional update to get the latest values
101
+ setRealIndex(prevRealIndex => {
102
+ if (isTransitioning) return prevRealIndex;
103
+
104
+ // Stop autoplay on interaction if disableOnInteraction is true
105
+ if (disableOnInteraction && autoplayRef.current) {
106
+ clearInterval(autoplayRef.current);
107
+ autoplayRef.current = null;
108
+ setAutoplayRunning(false);
109
+ }
110
+
111
+ let nextIndex;
112
+ if (loop) {
113
+ nextIndex = (prevRealIndex + 1) % slides.length;
114
+ } else {
115
+ nextIndex = Math.min(prevRealIndex + 1, slides.length - slidesToShow);
116
+ }
117
+
118
+ // Trigger the slide change
119
+ if (reverseDirection) {
120
+ // For reverse direction, we would go to previous slide
121
+ const prevIndex = loop ? (prevRealIndex === 0 ? slides.length - 1 : prevRealIndex - 1) : Math.max(prevRealIndex - 1, 0);
122
+ setInternalIndex(loop ? slides.length + prevIndex : prevIndex);
123
+ setIsTransitioning(true);
124
+ setDragOffset(0);
125
+
126
+ setTimeout(() => {
127
+ setIsTransitioning(false);
128
+ onSlideChange?.(prevIndex);
129
+ }, speed);
130
+
131
+ return prevIndex;
132
+ } else {
133
+ // Normal direction
134
+ setInternalIndex(loop ? slides.length + nextIndex : nextIndex);
135
+ setIsTransitioning(true);
136
+ setDragOffset(0);
137
+
138
+ setTimeout(() => {
139
+ setIsTransitioning(false);
140
+ onSlideChange?.(nextIndex);
141
+
142
+ // Reposition after transition ends for looped sliders
143
+ if (loop && nextIndex >= slides.length * 2) {
144
+ repositioningRef.current = true;
145
+ setInternalIndex(slides.length + nextIndex);
146
+ setTimeout(() => {
147
+ repositioningRef.current = false;
148
+ }, 0);
149
+ }
150
+ }, speed);
151
+
152
+ return nextIndex;
153
+ }
154
+ });
155
+ }, delay);
156
+
157
+ setAutoplayRunning(true);
158
+
159
+ // Handle pause on mouse enter/leave if enabled
160
+ let containerElement: HTMLDivElement | null = null;
161
+ const handleMouseEnter = () => {
162
+ if (autoplayRef.current) {
163
+ clearInterval(autoplayRef.current);
164
+ autoplayRef.current = null;
165
+ setAutoplayRunning(false);
166
+ }
167
+ };
168
+
169
+ const handleMouseLeave = () => {
170
+ // Restart autoplay
171
+ if (autoplayRef.current) {
172
+ clearInterval(autoplayRef.current);
173
+ }
174
+
175
+ autoplayRef.current = setInterval(() => {
176
+ setRealIndex(prevRealIndex => {
177
+ if (isTransitioning) return prevRealIndex;
178
+
179
+ let nextIndex;
180
+ if (loop) {
181
+ nextIndex = (prevRealIndex + 1) % slides.length;
182
+ } else {
183
+ nextIndex = Math.min(prevRealIndex + 1, slides.length - slidesToShow);
184
+ }
185
+
186
+ setInternalIndex(loop ? slides.length + nextIndex : nextIndex);
187
+ setIsTransitioning(true);
188
+ setDragOffset(0);
189
+
190
+ setTimeout(() => {
191
+ setIsTransitioning(false);
192
+ onSlideChange?.(nextIndex);
193
+
194
+ if (loop) {
195
+ // Reposition after transition ends
196
+ if (nextIndex >= slides.length * 2) {
197
+ repositioningRef.current = true;
198
+ setInternalIndex(slides.length + nextIndex);
199
+ setTimeout(() => {
200
+ repositioningRef.current = false;
201
+ }, 0);
202
+ }
203
+ }
204
+ }, speed);
205
+
206
+ return nextIndex;
207
+ });
208
+ }, delay);
209
+
210
+ setAutoplayRunning(true);
211
+ };
212
+
213
+ if (pauseOnMouseEnter && containerRef.current) {
214
+ containerElement = containerRef.current;
215
+ containerElement.addEventListener('mouseenter', handleMouseEnter);
216
+ containerElement.addEventListener('mouseleave', handleMouseLeave);
217
+ }
218
+
219
+ // Cleanup
220
+ return () => {
221
+ if (autoplayRef.current) {
222
+ clearInterval(autoplayRef.current);
223
+ autoplayRef.current = null;
224
+ }
225
+ if (containerElement) {
226
+ containerElement.removeEventListener('mouseenter', handleMouseEnter);
227
+ containerElement.removeEventListener('mouseleave', handleMouseLeave);
228
+ }
229
+ setAutoplayRunning(false);
230
+ };
231
+ }, [autoplay, slides.length, loop, slidesToShow, isTransitioning, speed, onSlideChange, repositioningRef]);
232
+
76
233
  // Initialize
77
234
  useEffect(() => {
78
235
  if (loop) {
@@ -100,6 +257,13 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
100
257
  const slideNext = useCallback(() => {
101
258
  if (isTransitioning) return;
102
259
 
260
+ // Stop autoplay on interaction if disableOnInteraction is true
261
+ if (autoplay && typeof autoplay === 'object' && autoplay.disableOnInteraction && autoplayRef.current) {
262
+ clearInterval(autoplayRef.current);
263
+ autoplayRef.current = null;
264
+ setAutoplayRunning(false);
265
+ }
266
+
103
267
  if (loop) {
104
268
  const nextRealIndex = (realIndex + 1) % slides.length;
105
269
  const nextInternalIndex = internalIndex + 1;
@@ -145,11 +309,19 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
145
309
  onSlideChange,
146
310
  allSlides.length,
147
311
  loopedSlides,
312
+ autoplay
148
313
  ]);
149
314
 
150
315
  const slidePrev = useCallback(() => {
151
316
  if (isTransitioning) return;
152
317
 
318
+ // Stop autoplay on interaction if disableOnInteraction is true
319
+ if (autoplay && typeof autoplay === 'object' && autoplay.disableOnInteraction && autoplayRef.current) {
320
+ clearInterval(autoplayRef.current);
321
+ autoplayRef.current = null;
322
+ setAutoplayRunning(false);
323
+ }
324
+
153
325
  if (loop) {
154
326
  const prevRealIndex = realIndex === 0 ? slides.length - 1 : realIndex - 1;
155
327
  const prevInternalIndex = internalIndex - 1;
@@ -194,12 +366,20 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
194
366
  onSlideChange,
195
367
  allSlides.length,
196
368
  loopedSlides,
369
+ autoplay
197
370
  ]);
198
371
 
199
372
  const goToSlide = useCallback(
200
373
  (index: number) => {
201
374
  if (isTransitioning || index === realIndex) return;
202
375
 
376
+ // Stop autoplay on interaction if disableOnInteraction is true
377
+ if (autoplay && typeof autoplay === 'object' && autoplay.disableOnInteraction && autoplayRef.current) {
378
+ clearInterval(autoplayRef.current);
379
+ autoplayRef.current = null;
380
+ setAutoplayRunning(false);
381
+ }
382
+
203
383
  setIsTransitioning(true);
204
384
  setDragOffset(0);
205
385
 
@@ -211,13 +391,20 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
211
391
  onSlideChange?.(index);
212
392
  }, speed);
213
393
  },
214
- [realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides]
394
+ [realIndex, isTransitioning, speed, onSlideChange, loop, loopedSlides, autoplay]
215
395
  );
216
396
 
217
397
  const handleTouchStart = useCallback(
218
398
  (e: React.TouchEvent | React.MouseEvent) => {
219
399
  if (!allowTouchMove) return;
220
400
 
401
+ // Stop autoplay on interaction if disableOnInteraction is true
402
+ if (autoplay && typeof autoplay === 'object' && autoplay.disableOnInteraction && autoplayRef.current) {
403
+ clearInterval(autoplayRef.current);
404
+ autoplayRef.current = null;
405
+ setAutoplayRunning(false);
406
+ }
407
+
221
408
  const client =
222
409
  direction === 'horizontal'
223
410
  ? 'touches' in e
@@ -230,7 +417,7 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
230
417
  setTouching(true);
231
418
  setDragOffset(0);
232
419
  },
233
- [allowTouchMove, direction]
420
+ [allowTouchMove, direction, autoplay]
234
421
  );
235
422
 
236
423
  const handleTouchMove = useCallback(
@@ -293,7 +480,7 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
293
480
  isBeginning: !loop && realIndex === 0,
294
481
  isEnd: !loop && realIndex >= slides.length - slidesToShow,
295
482
  progress: slides.length > 0 ? realIndex / (slides.length - 1) : 0,
296
- autoplayRunning: false,
483
+ autoplayRunning,
297
484
  transitioning: isTransitioning,
298
485
  touching,
299
486
  translate: translateValue,
@@ -336,4 +523,4 @@ export function useSlider(options: UseSliderOptions): UseSliderReturn {
336
523
  loopedSlides,
337
524
  repositioningRef,
338
525
  };
339
- }
526
+ }
@@ -1431,3 +1431,88 @@ export const BLOCK = {
1431
1431
  DEFAULT: 'md' as const,
1432
1432
  },
1433
1433
  };
1434
+
1435
+ /**
1436
+ * Footer-specific constants
1437
+ */
1438
+ export const FOOTER = {
1439
+ SELECTORS: {
1440
+ FOOTER: '.c-footer',
1441
+ CONTAINER: '.c-footer__container',
1442
+ SECTIONS: '.c-footer__sections',
1443
+ BRAND: '.c-footer__brand',
1444
+ BRAND_LOGO: '.c-footer__brand-logo',
1445
+ BRAND_NAME: '.c-footer__brand-name',
1446
+ BRAND_DESCRIPTION: '.c-footer__brand-description',
1447
+ SECTION: '.c-footer__section',
1448
+ SECTION_HEADER: '.c-footer__section-header',
1449
+ SECTION_TITLE: '.c-footer__section-title',
1450
+ SECTION_CONTENT: '.c-footer__section-content',
1451
+ SECTION_TOGGLE: '.c-footer__section-toggle',
1452
+ LINK: '.c-footer__link',
1453
+ SOCIAL: '.c-footer__social',
1454
+ SOCIAL_LINK: '.c-footer__social-link',
1455
+ NEWSLETTER: '.c-footer__newsletter',
1456
+ NEWSLETTER_FORM: '.c-footer__newsletter-form',
1457
+ NEWSLETTER_INPUT: '.c-footer__newsletter-input',
1458
+ NEWSLETTER_BUTTON: '.c-footer__newsletter-button',
1459
+ BOTTOM: '.c-footer__bottom',
1460
+ COPYRIGHT: '.c-footer__copyright',
1461
+ BACK_TO_TOP: '.c-footer__back-to-top',
1462
+ DIVIDER: '.c-footer__divider',
1463
+ },
1464
+ CLASSES: {
1465
+ BASE: 'c-footer',
1466
+ CONTAINER: 'c-footer__container',
1467
+ SECTIONS: 'c-footer__sections',
1468
+ BRAND: 'c-footer__brand',
1469
+ BRAND_LOGO: 'c-footer__brand-logo',
1470
+ BRAND_NAME: 'c-footer__brand-name',
1471
+ BRAND_DESCRIPTION: 'c-footer__brand-description',
1472
+ SECTION: 'c-footer__section',
1473
+ SECTION_HEADER: 'c-footer__section-header',
1474
+ SECTION_TITLE: 'c-footer__section-title',
1475
+ SECTION_CONTENT: 'c-footer__section-content',
1476
+ SECTION_TOGGLE: 'c-footer__section-toggle',
1477
+ SECTION_COLLAPSIBLE: 'c-footer__section--collapsible',
1478
+ SECTION_COLLAPSED: 'c-footer__section--collapsed',
1479
+ LINK: 'c-footer__link',
1480
+ LINK_ACTIVE: 'c-footer__link--active',
1481
+ LINK_DISABLED: 'c-footer__link--disabled',
1482
+ SOCIAL: 'c-footer__social',
1483
+ SOCIAL_LINK: 'c-footer__social-link',
1484
+ NEWSLETTER: 'c-footer__newsletter',
1485
+ NEWSLETTER_FORM: 'c-footer__newsletter-form',
1486
+ NEWSLETTER_INPUT: 'c-footer__newsletter-input',
1487
+ NEWSLETTER_BUTTON: 'c-footer__newsletter-button',
1488
+ BOTTOM: 'c-footer__bottom',
1489
+ COPYRIGHT: 'c-footer__copyright',
1490
+ BACK_TO_TOP: 'c-footer__back-to-top',
1491
+ DIVIDER: 'c-footer__divider',
1492
+ // Layout variants
1493
+ COLUMNS: 'c-footer--columns',
1494
+ CENTERED: 'c-footer--centered',
1495
+ MINIMAL: 'c-footer--minimal',
1496
+ STACKED: 'c-footer--stacked',
1497
+ // Size variants
1498
+ SM: 'c-footer--sm',
1499
+ MD: 'c-footer--md',
1500
+ LG: 'c-footer--lg',
1501
+ // State modifiers
1502
+ STICKY: 'c-footer--sticky',
1503
+ },
1504
+ DEFAULTS: {
1505
+ LAYOUT: 'columns',
1506
+ VARIANT: 'primary',
1507
+ SIZE: 'md',
1508
+ SHOW_NEWSLETTER: false,
1509
+ SHOW_BACK_TO_TOP: false,
1510
+ SHOW_DIVIDER: true,
1511
+ STICKY: false,
1512
+ NEWSLETTER_TITLE: 'Stay Updated',
1513
+ NEWSLETTER_DESCRIPTION: 'Subscribe to our newsletter for the latest updates.',
1514
+ NEWSLETTER_PLACEHOLDER: 'Enter your email',
1515
+ NEWSLETTER_BUTTON_TEXT: 'Subscribe',
1516
+ BACK_TO_TOP_TEXT: 'Back to Top',
1517
+ },
1518
+ };