-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoverflow-shadow.js
96 lines (86 loc) · 2.58 KB
/
overflow-shadow.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/**
* Copyright (c) 2023 tapiocode
* https://github.com/tapiocode
* MIT License
*/
(function() {
const SCRIPT_NAME = 'overflow-shadow';
const TAG_SELECTOR = `[${SCRIPT_NAME}]`;
const WRAPPER_NAME = `${SCRIPT_NAME}-content-wrapper`;
const getEdgeName = (edge) => `${SCRIPT_NAME}-${edge}`;
function wrapElems(wrapper, elem) {
const elems = elem.childNodes;
while (elems.length) {
wrapper.appendChild(elems[0]);
}
elem.appendChild(wrapper);
}
function getEdgeElem(edge) {
const elem = document.createElement('div');
elem.innerHTML = `<!-- ${SCRIPT_NAME} observable element for ${edge} -->`;
return elem;
}
function setupIntersectObserver(root) {
['top', 'bottom'].forEach((edge) => {
const edgeElem = getEdgeElem(edge);
root[edge === 'top' ? 'prepend' : 'append'](edgeElem);
const options = {
root,
rootMargin: '10px',
threshold: 1.0,
};
const callback = (entries) => {
entries.forEach((entry) => {
root.parentNode.classList[entry.isIntersecting ? 'remove' : 'add'](getEdgeName(edge));
});
};
const observer = new IntersectionObserver(callback, options);
observer.observe(edgeElem);
});
}
function initializeElems() {
const elems = document.querySelectorAll(TAG_SELECTOR);
elems.forEach((elem) => {
const wrapper = document.createElement('div');
wrapper.setAttribute(WRAPPER_NAME, '');
wrapElems(wrapper, elem);
setupIntersectObserver(wrapper);
});
}
function injectCss() {
const css = document.createElement('style');
const styles = `
${TAG_SELECTOR} {
position: relative;
height: 100%;
}
${TAG_SELECTOR}:before,
${TAG_SELECTOR}:after {
background: linear-gradient(180deg, rgba(29,29,31,0.5) 0%, rgba(29,29,31,0.15) 35%, rgba(29,29,31,0) 100%);
opacity: 0;
transition: opacity .2s ease-in-out;
content: '';
display: block;
height: 1.4rem;
position: absolute;
width: 100%;
}
${TAG_SELECTOR}:after {
background: linear-gradient(0deg, rgba(29,29,31,0.5) 0%, rgba(29,29,31,0.15) 35%, rgba(29,29,31,0) 100%);
bottom: 0;
}
${TAG_SELECTOR}.${getEdgeName('top')}:before,
${TAG_SELECTOR}.${getEdgeName('bottom')}:after {
opacity: 1;
}
[${WRAPPER_NAME}] {
overflow-y: auto;
height: 100%;
}
`;
css.appendChild(document.createTextNode(styles));
document.head.appendChild(css);
}
initializeElems();
injectCss();
})();