@madj2k/fe-frontend-kit 2.0.31 → 2.0.32

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/index.js CHANGED
@@ -6,6 +6,7 @@ export { Madj2kResizeEnd } from './tools/resize-end';
6
6
  export { Madj2kScrolling } from './tools/scrolling';
7
7
  export { Madj2kSimpleFadeSlider } from './tools/simple-fade-slider';
8
8
  export { Madj2kToggledOverlay } from './tools/toggled-overlay';
9
+ export { Madj2kElementInViewport } from './tools/element-in-viewport';
9
10
 
10
11
  // Menus
11
12
  export { Madj2kFlyoutMenu } from './menus/flyout-menu';
package/index.scss CHANGED
@@ -12,3 +12,4 @@
12
12
  @forward 'tools/scrolling/index';
13
13
  @forward 'tools/simple-fade-slider/index';
14
14
  @forward 'tools/toggled-overlay/index';
15
+ @forward 'tools/element-in-viewport/index';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madj2k/fe-frontend-kit",
3
- "version": "2.0.31",
3
+ "version": "2.0.32",
4
4
  "description": "Shared frontend utilities, menus and mixins for projects",
5
5
  "main": "index.js",
6
6
  "style": "index.scss",
package/readme.md CHANGED
@@ -366,6 +366,52 @@ Usage with Appear-On-Scroll (HTML):
366
366
  </div>
367
367
  ```
368
368
 
369
+ # JS: Element In Viewport
370
+ A lightweight helper class that adds a configurable class to any DOM element once it becomes visible in the viewport.
371
+ Perfect for triggering CSS-based animations (e.g., quote reveals, fade-ins, transitions) when an element enters view.
372
+ * Works with IntersectionObserver API
373
+ * Purely DOM-based (no keyframes required)
374
+ * Fully configurable (threshold, delay, class)
375
+ * Ideal for CMS-driven content (dynamic DOM)
376
+ * Designed for performance and flexibility
377
+
378
+ Init:
379
+ ```
380
+ document.querySelectorAll('.js-inview').forEach((el) => {
381
+ new Madj2kElementInViewport(el, {
382
+ visibleClass: 'is-in-viewport',
383
+ threshold: 0.5,
384
+ debug: false
385
+ });
386
+ });
387
+ ```
388
+
389
+ HTML-Example
390
+ ```
391
+ <section class="my-element js-inview">
392
+ <div class="my-element-content">Lorem ipsum dolor sit amet.</div>
393
+ </section>
394
+ ```
395
+
396
+ SCSS-Example
397
+ ```
398
+ .my-element {
399
+ .my-element-content {
400
+ opacity: 0;
401
+ transform: translateY(20%);
402
+ transition: opacity 0.6s ease, transform 0.6s ease;
403
+ }
404
+
405
+ &.is-in-viewport {
406
+ .my-element-content {
407
+ opacity: 1;
408
+ transform: translateY(0);
409
+ }
410
+ }
411
+ }
412
+ ```
413
+
414
+
369
415
  # JS: Toggled Overlay
370
416
  This class toggles the visibility of any target element referenced by the `aria-controls`
371
417
  attribute of a trigger element (button, link, etc.). It manages ARIA attributes for accessibility
@@ -43,6 +43,15 @@
43
43
  /// [...]
44
44
  /// </div>
45
45
  ///
46
+ /// @example html
47
+ /// <div class="csp-section">
48
+ /// [...]
49
+ /// </div>
50
+ /// <!-- With vertical padding instead of margin -->
51
+ /// <div class="csp-section csp-section-padding">
52
+ /// [...]
53
+ /// </div>
54
+ ///
46
55
  /// @example scss
47
56
  /// .layout-default {
48
57
  /// @include section-spacing();
@@ -56,6 +65,7 @@
56
65
  $block-class: 'csp-block',
57
66
  $not-last-class: 'csp-not-last',
58
67
  $utility-append-class: 'sp',
68
+ $padding-append-class: 'padding',
59
69
  $csp-blocks: (
60
70
  'text',
61
71
  'text-image',
@@ -101,9 +111,17 @@
101
111
  }
102
112
 
103
113
  .#{$section-class}.#{$not-last-class}:not(:has(+ .#{$section-class})),
114
+ .#{$section-class}.#{$section-class}-#{$padding-append-class},
115
+ .#{$section-class}:has(+ .#{$section-class}-#{$padding-append-class}),
104
116
  .#{$section-class}-#{$utility-append-class}.#{$not-last-class}:not(:has(+ .#{$section-class})) {
105
117
  margin-bottom: 0;
106
118
  }
119
+
120
+ .#{$section-class}-#{$padding-append-class},
121
+ .#{$section-class}-#{$padding-append-class}-#{$utility-append-class} {
122
+ padding-top: rem-calc($spacer-section);
123
+ padding-bottom: rem-calc($spacer-section);
124
+ }
107
125
  }
108
126
 
109
127
  // block-spacing
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Madj2kElementInViewport
3
+ *
4
+ * Adds a CSS class to any DOM element once it becomes fully (or partially) visible
5
+ * in the viewport using the IntersectionObserver API.
6
+ *
7
+ * - Purely CSS-triggered transitions via class
8
+ * - Reusable for any type of element (quotes, sections, etc.)
9
+ * - Fully configurable: class name, threshold, delay
10
+ * - Designed for CMS contexts with dynamically loaded content
11
+ *
12
+ * @author Steffen Kroggel <developer@steffenkroggel.de>
13
+ * @copyright 2025 Steffen Kroggel
14
+ * @version 1.0.0
15
+ * @license GNU General Public License v3.0
16
+ * @see https://www.gnu.org/licenses/gpl-3.0.en.html
17
+ *
18
+ * @example
19
+ * // Single element with defaults
20
+ * const el = document.querySelector('.js-animate-in');
21
+ * new Madj2kElementInViewport(el);
22
+ *
23
+ * @example
24
+ * // Single element with custom config
25
+ * new Madj2kElementInViewport(el, {
26
+ * visibleClass: 'is-visible',
27
+ * threshold: 0.75,
28
+ * delay: 200,
29
+ * debug: true
30
+ * });
31
+ *
32
+ * @example
33
+ * // Multiple elements
34
+ * document.querySelectorAll('.js-element-in-viewport').forEach((el) => {
35
+ * new Madj2kElementInViewport(el, {
36
+ * visibleClass: 'is-in-viewport',
37
+ * threshold: 1
38
+ * });
39
+ * });
40
+ */
41
+
42
+ class Madj2kElementInViewport {
43
+ config = {
44
+ visibleClass: 'is-in-viewport',
45
+ threshold: 0.5,
46
+ delay: 0,
47
+ debug: false
48
+ };
49
+
50
+ /**
51
+ * @param {HTMLElement} element - DOM element to observe
52
+ * @param {Object} config - configuration options
53
+ * @param {string} [config.visibleClass='in-viewport'] - class to apply when element is in view
54
+ * @param {number} [config.threshold=1.0] - how much of the element must be visible (0–1)
55
+ * @param {number} [config.delay=0] - optional delay before applying class (in ms)
56
+ * @param {boolean} [config.debug=false] - enable debug logs
57
+ */
58
+ constructor(element, config = {}) {
59
+ if (!(element instanceof HTMLElement)) {
60
+ console.warn('[Madj2kElementInViewport] No valid element provided.');
61
+ return;
62
+ }
63
+
64
+ this.element = element;
65
+ this.config = { ...this.config, ...config };
66
+
67
+ this._log('Initialized with config:', this.config);
68
+ this._observe();
69
+ }
70
+
71
+ /**
72
+ * Initializes the IntersectionObserver
73
+ * @private
74
+ */
75
+ _observe() {
76
+ const observer = new IntersectionObserver(
77
+ ([entry], observerInstance) => {
78
+ if (entry.isIntersecting && entry.intersectionRatio >= this.config.threshold) {
79
+ this._log('Element in viewport:', this.element);
80
+
81
+ if (this.config.delay > 0) {
82
+ setTimeout(() => this._activate(observerInstance), this.config.delay);
83
+ } else {
84
+ this._activate(observerInstance);
85
+ }
86
+ }
87
+ },
88
+ {
89
+ threshold: this.config.threshold
90
+ }
91
+ );
92
+
93
+ observer.observe(this.element);
94
+ }
95
+
96
+ /**
97
+ * Applies the visible class and stops observing
98
+ * @param {IntersectionObserver} observer
99
+ * @private
100
+ */
101
+ _activate(observer) {
102
+ this.element.classList.add(this.config.visibleClass);
103
+ observer.unobserve(this.element);
104
+ this._log(`Class "${this.config.visibleClass}" added.`);
105
+ }
106
+
107
+ /**
108
+ * Logs debug messages
109
+ * @param {...any} args
110
+ * @private
111
+ */
112
+ _log(...args) {
113
+ if (this.config.debug) {
114
+ console.log('[Madj2kElementInViewport]', ...args);
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,2 @@
1
+ import Madj2kElementInViewport from './element-in-viewport-2.0';
2
+ export { Madj2kElementInViewport };
@@ -0,0 +1 @@
1
+ @forward './element-in-viewport-2.0';