derafu-js 0.1.1 → 0.1.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.
- package/package.json +1 -1
- package/src/tabs.js +61 -21
package/package.json
CHANGED
package/src/tabs.js
CHANGED
|
@@ -54,6 +54,9 @@ Tabs.init = function () {
|
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Inject animation styles for deeplink highlighting.
|
|
58
|
+
Tabs._injectStyles();
|
|
59
|
+
|
|
57
60
|
// Add magic links, modal button actions, and form elements within tabs.
|
|
58
61
|
for (const tabPane of document.querySelectorAll('div.tab-pane')) {
|
|
59
62
|
if (tabPane.id) {
|
|
@@ -78,6 +81,58 @@ Tabs.init = function () {
|
|
|
78
81
|
}, true);*/
|
|
79
82
|
};
|
|
80
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Injects the CSS keyframe animation for deeplink highlighting once into the
|
|
86
|
+
* document head. Uses Bootstrap CSS variables so colors adapt to any theme.
|
|
87
|
+
*
|
|
88
|
+
* @returns {void}
|
|
89
|
+
*/
|
|
90
|
+
Tabs._injectStyles = function () {
|
|
91
|
+
'use strict';
|
|
92
|
+
if (document.getElementById('derafu-tabs-styles')) return;
|
|
93
|
+
const style = document.createElement('style');
|
|
94
|
+
style.id = 'derafu-tabs-styles';
|
|
95
|
+
style.textContent =
|
|
96
|
+
'@keyframes deeplink-pulse {' +
|
|
97
|
+
'0% { box-shadow: 0 0 0 4px rgba(var(--bs-primary-rgb), 0.5); }' +
|
|
98
|
+
'100% { box-shadow: 0 0 0 0 rgba(var(--bs-primary-rgb), 0); }' +
|
|
99
|
+
'}' +
|
|
100
|
+
'.deeplink-highlight {' +
|
|
101
|
+
'animation: deeplink-pulse 2s ease-out forwards;' +
|
|
102
|
+
'}';
|
|
103
|
+
document.head.appendChild(style);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Highlights an element using a pulse animation. For cards the element itself
|
|
108
|
+
* is targeted; for form elements the nearest Bootstrap container is used
|
|
109
|
+
* (.input-group > .form-floating > parentElement) so that prepend/append
|
|
110
|
+
* addons and floating labels are included in the visual feedback.
|
|
111
|
+
* The highlight class is removed automatically when the animation ends.
|
|
112
|
+
*
|
|
113
|
+
* @param {HTMLElement} element - The element to highlight.
|
|
114
|
+
* @param {boolean} isCard - Whether the element is a card.
|
|
115
|
+
* @returns {void}
|
|
116
|
+
*/
|
|
117
|
+
Tabs._highlightElement = function (element, isCard) {
|
|
118
|
+
'use strict';
|
|
119
|
+
const target = isCard
|
|
120
|
+
? element
|
|
121
|
+
: element.closest('.input-group') ||
|
|
122
|
+
element.closest('.form-floating') ||
|
|
123
|
+
element.parentElement;
|
|
124
|
+
if (!target) return;
|
|
125
|
+
if (isCard) target.classList.add('border-primary');
|
|
126
|
+
target.classList.add('deeplink-highlight');
|
|
127
|
+
target.addEventListener(
|
|
128
|
+
'animationend',
|
|
129
|
+
function () {
|
|
130
|
+
target.classList.remove('deeplink-highlight', 'border-primary');
|
|
131
|
+
},
|
|
132
|
+
{ once: true },
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
81
136
|
/**
|
|
82
137
|
* Handles opening tabs and focusing on specific elements based on URL.
|
|
83
138
|
* @returns {void}
|
|
@@ -115,7 +170,7 @@ Tabs.handleTabDeeplink = function (tabElement, elementId) {
|
|
|
115
170
|
`${tabElement_id}_${elementId}-card`,
|
|
116
171
|
);
|
|
117
172
|
if (cardElement) {
|
|
118
|
-
|
|
173
|
+
Tabs._highlightElement(cardElement, true);
|
|
119
174
|
typeof UI !== 'undefined'
|
|
120
175
|
? UI.scroll(cardElement)
|
|
121
176
|
: cardElement.scrollIntoView({ behavior: 'smooth' });
|
|
@@ -133,21 +188,9 @@ Tabs.handleTabDeeplink = function (tabElement, elementId) {
|
|
|
133
188
|
}
|
|
134
189
|
modalInstance.show();
|
|
135
190
|
}
|
|
136
|
-
// If it's a
|
|
137
|
-
else if (
|
|
138
|
-
element.tagName.toLowerCase() === 'select' &&
|
|
139
|
-
element.dataset.select2Id
|
|
140
|
-
) {
|
|
141
|
-
element.parentElement
|
|
142
|
-
.querySelector('span.select2-selection')
|
|
143
|
-
.classList.add('deeplink', 'border', 'border-danger');
|
|
144
|
-
typeof UI !== 'undefined'
|
|
145
|
-
? UI.scroll(element)
|
|
146
|
-
: element.scrollIntoView({ behavior: 'smooth' });
|
|
147
|
-
}
|
|
148
|
-
// If it's not a modal or select2, apply border and scroll.
|
|
191
|
+
// If it's a form element, highlight its container and scroll.
|
|
149
192
|
else {
|
|
150
|
-
|
|
193
|
+
Tabs._highlightElement(element, false);
|
|
151
194
|
typeof UI !== 'undefined'
|
|
152
195
|
? UI.scroll(element)
|
|
153
196
|
: element.scrollIntoView({ behavior: 'smooth' });
|
|
@@ -258,12 +301,9 @@ Tabs.deeplink = function (deeplink) {
|
|
|
258
301
|
history.replaceState(null, null, url);
|
|
259
302
|
})();
|
|
260
303
|
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
'.deeplink.border.border-danger',
|
|
265
|
-
)) {
|
|
266
|
-
element.classList.remove('deeplink', 'border', 'border-danger');
|
|
304
|
+
// Cancel any in-progress highlight so only one marked element exists at a time.
|
|
305
|
+
for (const element of document.querySelectorAll('.deeplink-highlight')) {
|
|
306
|
+
element.classList.remove('deeplink-highlight', 'border-primary');
|
|
267
307
|
}
|
|
268
308
|
|
|
269
309
|
// Handle opening tabs based on URL.
|