@madj2k/fe-frontend-kit 2.0.30 → 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 +1 -0
- package/index.scss +1 -0
- package/package.json +1 -1
- package/readme.md +46 -0
- package/sass/bootstrap-5.3/10_mixins/_page.scss +11 -6
- package/sass/bootstrap-5.3/10_mixins/_section.scss +18 -0
- package/tools/element-in-viewport/element-in-viewport-2.0.js +117 -0
- package/tools/element-in-viewport/element-in-viewport-2.0.scss +0 -0
- package/tools/element-in-viewport/index.js +2 -0
- package/tools/element-in-viewport/index.scss +1 -0
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
package/package.json
CHANGED
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
|
|
@@ -90,11 +90,13 @@
|
|
|
90
90
|
$wrap-class: '.fullwidth',
|
|
91
91
|
$default-padding: 16px,
|
|
92
92
|
$padding-class: $page-wrap-class,
|
|
93
|
-
$version: 1,
|
|
94
93
|
) {
|
|
95
94
|
|
|
96
95
|
/** addition class which simply contains the normal padding */
|
|
97
96
|
#{$padding-class}-padding {
|
|
97
|
+
@include page-padding-only($default-padding);
|
|
98
|
+
}
|
|
99
|
+
#{$padding-class}-padding-full {
|
|
98
100
|
@include page-padding-only($default-padding, 'full');
|
|
99
101
|
}
|
|
100
102
|
|
|
@@ -103,12 +105,18 @@
|
|
|
103
105
|
@include media-breakpoint-up($breakpoint) {
|
|
104
106
|
/** addition class which simply contains the normal padding */
|
|
105
107
|
#{$padding-class}-padding {
|
|
108
|
+
@include page-padding-only($padding-x);
|
|
109
|
+
}
|
|
110
|
+
#{$padding-class}-padding-full {
|
|
106
111
|
@include page-padding-only($padding-x, 'full');
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
body {
|
|
110
115
|
/** addition class which simply contains the normal padding */
|
|
111
116
|
#{$padding-class}-#{$breakpoint}-padding {
|
|
117
|
+
@include page-padding-only($padding-x);
|
|
118
|
+
}
|
|
119
|
+
#{$padding-class}-#{$breakpoint}-padding-full {
|
|
112
120
|
@include page-padding-only($padding-x, 'full');
|
|
113
121
|
}
|
|
114
122
|
}
|
|
@@ -206,11 +214,8 @@
|
|
|
206
214
|
/** ensure dominance with body-prefix */
|
|
207
215
|
body #{$page-wrap-class} {
|
|
208
216
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
padding-left: $padding-x - math.div($grid-gutter-width, 2);
|
|
212
|
-
padding-right: $padding-x - math.div($grid-gutter-width, 2);
|
|
213
|
-
}
|
|
217
|
+
padding-left: $padding-x - math.div($grid-gutter-width, 2);
|
|
218
|
+
padding-right: $padding-x - math.div($grid-gutter-width, 2);
|
|
214
219
|
|
|
215
220
|
/** addition class which simply contains the normal padding */
|
|
216
221
|
#{$padding-class}-#{$breakpoint}-padding {
|
|
@@ -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
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@forward './element-in-viewport-2.0';
|