atharv-mandlavdiya 1.0.13 → 1.0.16
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/README.md +13 -0
- package/atharvmandlavdiya.js +162 -0
- package/package.json +2 -1
- package/prefabs/progress/progress.css +8 -1
- package/prefabs/progress/progress.js +41 -55
- package/test/progress-card.test.js +213 -0
package/README.md
CHANGED
|
@@ -18,4 +18,17 @@ import { atharvm } from "atharv-mandlavdiya";
|
|
|
18
18
|
atharvm();
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
The package also provides a self-contained progress card custom element. Import
|
|
22
|
+
the package once; registration and CSS injection happen automatically:
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<script type="module">
|
|
26
|
+
import "atharv-mandlavdiya";
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<progress-card data-scroll-length="300">
|
|
30
|
+
<div></div>
|
|
31
|
+
</progress-card>
|
|
32
|
+
```
|
|
33
|
+
|
|
21
34
|
MIT © [Atharv Mandlavdiya](https://github.com/AtharvM02222)
|
package/atharvmandlavdiya.js
CHANGED
|
@@ -10,6 +10,168 @@ export function atharvm() {
|
|
|
10
10
|
console.log(atharv_mandlavdiya);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
const progressCardStyles = `
|
|
14
|
+
@property --progress {
|
|
15
|
+
syntax: "<number>";
|
|
16
|
+
inherits: true;
|
|
17
|
+
initial-value: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.progress-wrapper {
|
|
21
|
+
position: relative;
|
|
22
|
+
width: 100%;
|
|
23
|
+
max-width: 100%;
|
|
24
|
+
min-height: 300vh;
|
|
25
|
+
padding: 0 4vw;
|
|
26
|
+
box-sizing: border-box;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
progress-card {
|
|
31
|
+
display: block;
|
|
32
|
+
position: sticky;
|
|
33
|
+
width: 100%;
|
|
34
|
+
max-width: 100%;
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
top: calc(var(--vh, 1vh) * 15);
|
|
37
|
+
height: calc(var(--vh, 1vh) * 70);
|
|
38
|
+
margin-bottom: calc(var(--vh, 1vh) * 15);
|
|
39
|
+
scale: calc(0.5 + var(--progress) * 0.5);
|
|
40
|
+
clip-path: rect(
|
|
41
|
+
calc(20% - var(--progress) * 18%)
|
|
42
|
+
calc(70% + var(--progress) * 26%)
|
|
43
|
+
calc(80% + var(--progress) * 18%)
|
|
44
|
+
calc(30% - var(--progress) * 26%)
|
|
45
|
+
round calc(2.441rem - var(--progress) * 1.941rem)
|
|
46
|
+
);
|
|
47
|
+
transform: translateZ(0);
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
progress-card img,
|
|
52
|
+
progress-card video,
|
|
53
|
+
progress-card > div {
|
|
54
|
+
display: block;
|
|
55
|
+
width: 100%;
|
|
56
|
+
max-width: 100%;
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
height: 100%;
|
|
59
|
+
object-fit: cover;
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
function injectProgressCardStyles(root) {
|
|
64
|
+
if (!root.document || root.document.getElementById('atharv-progress-card-styles')) return;
|
|
65
|
+
|
|
66
|
+
const style = root.document.createElement('style');
|
|
67
|
+
style.id = 'atharv-progress-card-styles';
|
|
68
|
+
style.textContent = progressCardStyles;
|
|
69
|
+
(root.document.head || root.document.documentElement).appendChild(style);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isScrollable(element, root) {
|
|
73
|
+
const style = root.getComputedStyle(element);
|
|
74
|
+
const overflow = `${style.overflow} ${style.overflowY}`;
|
|
75
|
+
return /(auto|scroll|overlay)/.test(overflow) &&
|
|
76
|
+
(element.scrollHeight > element.clientHeight || /(auto|scroll|overlay)/.test(overflow));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function findScrollContainer(element, root) {
|
|
80
|
+
let parent = element.parentElement;
|
|
81
|
+
while (parent) {
|
|
82
|
+
if (isScrollable(parent, root)) return parent;
|
|
83
|
+
parent = parent.parentElement;
|
|
84
|
+
}
|
|
85
|
+
return root;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getScrollPosition(container, root) {
|
|
89
|
+
return container === root ? (root.pageYOffset || root.scrollY || 0) : container.scrollTop;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getViewportHeight(container, root) {
|
|
93
|
+
return container === root ? root.innerHeight : container.clientHeight;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getWrapperPosition(wrapper, container, root) {
|
|
97
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
98
|
+
if (container === root) return wrapperRect.top + getScrollPosition(container, root);
|
|
99
|
+
|
|
100
|
+
const containerRect = container.getBoundingClientRect();
|
|
101
|
+
return wrapperRect.top - containerRect.top + getScrollPosition(container, root);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function clamp(value, min, max) {
|
|
105
|
+
return Math.min(max, Math.max(min, value));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function defineProgressCard(root) {
|
|
109
|
+
if (!root.document || !root.customElements || root.customElements.get('progress-card')) return;
|
|
110
|
+
|
|
111
|
+
root.customElements.define('progress-card', class extends root.HTMLElement {
|
|
112
|
+
constructor() {
|
|
113
|
+
super();
|
|
114
|
+
this._wrapper = null;
|
|
115
|
+
this._scrollContainer = null;
|
|
116
|
+
this._onScroll = () => this._updateProgress();
|
|
117
|
+
this._onResize = () => this._updateProgress();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
connectedCallback() {
|
|
121
|
+
if (!this._wrapper) {
|
|
122
|
+
const scrollLength = Number.parseFloat(this.dataset.scrollLength) || 300;
|
|
123
|
+
const wrapper = root.document.createElement('div');
|
|
124
|
+
wrapper.className = 'progress-wrapper';
|
|
125
|
+
wrapper.style.minHeight = `${scrollLength}vh`;
|
|
126
|
+
this.parentNode.insertBefore(wrapper, this);
|
|
127
|
+
wrapper.appendChild(this);
|
|
128
|
+
this._wrapper = wrapper;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
this._scrollContainer = findScrollContainer(this, root);
|
|
132
|
+
this._scrollContainer.addEventListener('scroll', this._onScroll, { passive: true });
|
|
133
|
+
root.addEventListener('resize', this._onResize, { passive: true });
|
|
134
|
+
this._updateProgress();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
disconnectedCallback() {
|
|
138
|
+
if (this._scrollContainer) {
|
|
139
|
+
this._scrollContainer.removeEventListener('scroll', this._onScroll);
|
|
140
|
+
this._scrollContainer = null;
|
|
141
|
+
}
|
|
142
|
+
root.removeEventListener('resize', this._onResize);
|
|
143
|
+
if (this._wrapper && this._wrapper.parentNode && !this._wrapper.contains(this)) {
|
|
144
|
+
this._wrapper.parentNode.removeChild(this._wrapper);
|
|
145
|
+
}
|
|
146
|
+
this._wrapper = null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
_updateProgress() {
|
|
150
|
+
if (!this._wrapper || !this._scrollContainer) return;
|
|
151
|
+
const viewportHeight = getViewportHeight(this._scrollContainer, root);
|
|
152
|
+
const wrapperStart = getWrapperPosition(this._wrapper, this._scrollContainer, root);
|
|
153
|
+
const wrapperHeight = this._wrapper.offsetHeight ||
|
|
154
|
+
this._wrapper.getBoundingClientRect().height;
|
|
155
|
+
const wrapperEnd = wrapperStart + wrapperHeight - viewportHeight;
|
|
156
|
+
const scrollPosition = getScrollPosition(this._scrollContainer, root);
|
|
157
|
+
const progress = wrapperEnd <= wrapperStart
|
|
158
|
+
? (scrollPosition >= wrapperEnd ? 1 : 0)
|
|
159
|
+
: clamp((scrollPosition - wrapperStart) / (wrapperEnd - wrapperStart), 0, 1);
|
|
160
|
+
|
|
161
|
+
this.style.setProperty('--progress', String(progress));
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
injectProgressCardStyles(globalThis);
|
|
167
|
+
defineProgressCard(globalThis);
|
|
168
|
+
|
|
169
|
+
// Kept as a compatibility no-op for consumers upgrading from the old API.
|
|
170
|
+
export function progressCard() {
|
|
171
|
+
injectProgressCardStyles(globalThis);
|
|
172
|
+
defineProgressCard(globalThis);
|
|
173
|
+
}
|
|
174
|
+
|
|
13
175
|
const _svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 650 200" width="650" height="200">
|
|
14
176
|
<defs>
|
|
15
177
|
<linearGradient id="pathGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atharv-mandlavdiya",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"description": "Made With Love By Atharv Mandlavdiya",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "atharvmandlavdiya.js",
|
|
7
7
|
"exports": "./atharvmandlavdiya.js",
|
|
8
8
|
"scripts": {
|
|
9
|
+
"test": "node --test",
|
|
9
10
|
"postinstall": "node postinstall.js"
|
|
10
11
|
},
|
|
11
12
|
"keywords": [
|
|
@@ -7,14 +7,19 @@
|
|
|
7
7
|
.progress-wrapper {
|
|
8
8
|
position: relative;
|
|
9
9
|
width: 100%;
|
|
10
|
-
|
|
10
|
+
max-width: 100%;
|
|
11
|
+
min-height: 300vh;
|
|
11
12
|
padding: 0 4vw;
|
|
12
13
|
box-sizing: border-box;
|
|
14
|
+
overflow: hidden;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
progress-card {
|
|
16
18
|
display: block;
|
|
17
19
|
position: sticky;
|
|
20
|
+
width: 100%;
|
|
21
|
+
max-width: 100%;
|
|
22
|
+
box-sizing: border-box;
|
|
18
23
|
top: calc(var(--vh, 1vh) * 15);
|
|
19
24
|
height: calc(var(--vh, 1vh) * 70);
|
|
20
25
|
margin-bottom: calc(var(--vh, 1vh) * 15);
|
|
@@ -35,6 +40,8 @@ progress-card video,
|
|
|
35
40
|
progress-card > div {
|
|
36
41
|
display: block;
|
|
37
42
|
width: 100%;
|
|
43
|
+
max-width: 100%;
|
|
44
|
+
box-sizing: border-box;
|
|
38
45
|
height: 100%;
|
|
39
46
|
object-fit: cover;
|
|
40
47
|
}
|
|
@@ -1,65 +1,51 @@
|
|
|
1
1
|
(function (root) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (_instance) return _instance;
|
|
15
|
-
var ST = root.StringTune;
|
|
16
|
-
if (!ST) return null;
|
|
17
|
-
var Ctor = (ST.StringTune && typeof ST.StringTune.getInstance === 'function')
|
|
18
|
-
? ST.StringTune
|
|
19
|
-
: (typeof ST.getInstance === 'function' ? ST : null);
|
|
20
|
-
if (!Ctor) return null;
|
|
21
|
-
_instance = Ctor.getInstance();
|
|
22
|
-
return _instance;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function wrapElement(el) {
|
|
26
|
-
if (el.hasAttribute('data-progress-init')) return;
|
|
27
|
-
var scrollLen = parseInt(el.dataset.scrollLength, 10) || 1024;
|
|
28
|
-
var id = uid();
|
|
29
|
-
|
|
30
|
-
var wrapper = document.createElement('div');
|
|
31
|
-
wrapper.className = 'progress-wrapper';
|
|
32
|
-
wrapper.setAttribute('string', 'progress');
|
|
33
|
-
wrapper.setAttribute('string-id', id);
|
|
34
|
-
wrapper.setAttribute('string-enter-vp', 'top');
|
|
35
|
-
wrapper.setAttribute('string-exit-vp', 'bottom');
|
|
36
|
-
wrapper.style.minHeight = scrollLen + 'vh';
|
|
37
|
-
|
|
38
|
-
el.parentNode.insertBefore(wrapper, el);
|
|
39
|
-
wrapper.appendChild(el);
|
|
40
|
-
el.setAttribute('data-progress-init', id);
|
|
4
|
+
if (!root.document || !root.customElements || root.customElements.get('progress-card')) return;
|
|
5
|
+
|
|
6
|
+
function scrollParent(element) {
|
|
7
|
+
var parent = element.parentElement;
|
|
8
|
+
while (parent) {
|
|
9
|
+
var style = root.getComputedStyle(parent);
|
|
10
|
+
if (/(auto|scroll|overlay)/.test(style.overflow + ' ' + style.overflowY)) return parent;
|
|
11
|
+
parent = parent.parentElement;
|
|
12
|
+
}
|
|
13
|
+
return root;
|
|
41
14
|
}
|
|
42
15
|
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
var st = getStringTune();
|
|
46
|
-
if (!st) return;
|
|
47
|
-
var ST = root.StringTune;
|
|
48
|
-
if (ST.StringLazy) st.use(ST.StringLazy);
|
|
49
|
-
if (!ST.StringProgress) return;
|
|
50
|
-
st.use(ST.StringProgress);
|
|
51
|
-
st.start(0);
|
|
52
|
-
_started = true;
|
|
53
|
-
root.StringTuneContext = st;
|
|
16
|
+
function scrollPosition(container) {
|
|
17
|
+
return container === root ? (root.pageYOffset || root.scrollY || 0) : container.scrollTop;
|
|
54
18
|
}
|
|
55
19
|
|
|
56
|
-
|
|
57
|
-
root
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
20
|
+
function update(card, wrapper, container) {
|
|
21
|
+
var viewport = container === root ? root.innerHeight : container.clientHeight;
|
|
22
|
+
var wrapperRect = wrapper.getBoundingClientRect();
|
|
23
|
+
var start = container === root
|
|
24
|
+
? wrapperRect.top + scrollPosition(container)
|
|
25
|
+
: wrapperRect.top - container.getBoundingClientRect().top + scrollPosition(container);
|
|
26
|
+
var end = start + (wrapper.offsetHeight || wrapperRect.height) - viewport;
|
|
27
|
+
var range = end - start;
|
|
28
|
+
var progress = range > 0 ? (scrollPosition(container) - start) / range : 0;
|
|
29
|
+
card.style.setProperty('--progress', String(Math.min(1, Math.max(0, progress))));
|
|
63
30
|
}
|
|
64
31
|
|
|
32
|
+
root.customElements.define('progress-card', class extends root.HTMLElement {
|
|
33
|
+
connectedCallback() {
|
|
34
|
+
this._wrapper = root.document.createElement('div');
|
|
35
|
+
this._wrapper.className = 'progress-wrapper';
|
|
36
|
+
this._wrapper.style.minHeight = (parseFloat(this.dataset.scrollLength) || 300) + 'vh';
|
|
37
|
+
this.parentNode.insertBefore(this._wrapper, this);
|
|
38
|
+
this._wrapper.appendChild(this);
|
|
39
|
+
this._container = scrollParent(this);
|
|
40
|
+
this._update = () => update(this, this._wrapper, this._container);
|
|
41
|
+
this._container.addEventListener('scroll', this._update, { passive: true });
|
|
42
|
+
root.addEventListener('resize', this._update, { passive: true });
|
|
43
|
+
this._update();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
disconnectedCallback() {
|
|
47
|
+
if (this._container) this._container.removeEventListener('scroll', this._update);
|
|
48
|
+
root.removeEventListener('resize', this._update);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
65
51
|
}(typeof globalThis !== 'undefined' ? globalThis : window));
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import test, { afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
|
|
4
|
+
class FakeStyle {
|
|
5
|
+
setProperty(name, value) {
|
|
6
|
+
this[name] = value;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getPropertyValue(name) {
|
|
10
|
+
return this[name] || '';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class FakeElement {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.children = [];
|
|
17
|
+
this.attributes = new Map();
|
|
18
|
+
this.style = new FakeStyle();
|
|
19
|
+
this.listeners = new Map();
|
|
20
|
+
this.parentElement = null;
|
|
21
|
+
this._rect = { top: 0, height: 0 };
|
|
22
|
+
this._height = 0;
|
|
23
|
+
this.clientHeight = 0;
|
|
24
|
+
this.scrollHeight = 0;
|
|
25
|
+
this.scrollTop = 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get parentNode() {
|
|
29
|
+
return this.parentElement;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get dataset() {
|
|
33
|
+
return Object.fromEntries([...this.attributes]
|
|
34
|
+
.filter(([name]) => name.startsWith('data-'))
|
|
35
|
+
.map(([name, value]) => [
|
|
36
|
+
name.slice(5).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()),
|
|
37
|
+
value
|
|
38
|
+
]));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get offsetHeight() {
|
|
42
|
+
return this._height;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set className(value) {
|
|
46
|
+
this.attributes.set('class', value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get className() {
|
|
50
|
+
return this.attributes.get('class') || '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setAttribute(name, value) {
|
|
54
|
+
this.attributes.set(name, String(value));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
hasAttribute(name) {
|
|
58
|
+
return this.attributes.has(name);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
appendChild(child) {
|
|
62
|
+
child.parentElement = this;
|
|
63
|
+
this.children.push(child);
|
|
64
|
+
return child;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
insertBefore(child, reference) {
|
|
68
|
+
child.parentElement = this;
|
|
69
|
+
const index = this.children.indexOf(reference);
|
|
70
|
+
this.children.splice(index < 0 ? this.children.length : index, 0, child);
|
|
71
|
+
return child;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
removeChild(child) {
|
|
75
|
+
this.children.splice(this.children.indexOf(child), 1);
|
|
76
|
+
child.parentElement = null;
|
|
77
|
+
return child;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
contains(child) {
|
|
81
|
+
return this.children.includes(child) || this.children.some((item) => item.contains(child));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getBoundingClientRect() {
|
|
85
|
+
return this._rect;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
addEventListener(type, listener) {
|
|
89
|
+
if (!this.listeners.has(type)) this.listeners.set(type, new Set());
|
|
90
|
+
this.listeners.get(type).add(listener);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
removeEventListener(type, listener) {
|
|
94
|
+
this.listeners.get(type)?.delete(listener);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
class FakeHTMLElement extends FakeElement {}
|
|
99
|
+
|
|
100
|
+
const body = new FakeElement();
|
|
101
|
+
const head = new FakeElement();
|
|
102
|
+
const documentElement = new FakeElement();
|
|
103
|
+
globalThis.HTMLElement = FakeHTMLElement;
|
|
104
|
+
globalThis.document = {
|
|
105
|
+
body,
|
|
106
|
+
head,
|
|
107
|
+
documentElement,
|
|
108
|
+
createElement: () => new FakeElement(),
|
|
109
|
+
getElementById(id) {
|
|
110
|
+
return [head, ...head.children].find((element) => element.attributes.get('id') === id) || null;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
globalThis.customElements = {
|
|
114
|
+
registry: new Map(),
|
|
115
|
+
define(name, constructor) {
|
|
116
|
+
this.registry.set(name, constructor);
|
|
117
|
+
},
|
|
118
|
+
get(name) {
|
|
119
|
+
return this.registry.get(name);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
globalThis.innerHeight = 1000;
|
|
123
|
+
globalThis.pageYOffset = 0;
|
|
124
|
+
globalThis.scrollY = 0;
|
|
125
|
+
globalThis.listeners = new Map();
|
|
126
|
+
globalThis.addEventListener = (type, listener) => {
|
|
127
|
+
if (!globalThis.listeners.has(type)) globalThis.listeners.set(type, new Set());
|
|
128
|
+
globalThis.listeners.get(type).add(listener);
|
|
129
|
+
};
|
|
130
|
+
globalThis.removeEventListener = (type, listener) => globalThis.listeners.get(type)?.delete(listener);
|
|
131
|
+
globalThis.getComputedStyle = (element) => ({
|
|
132
|
+
overflow: element._overflow || 'visible',
|
|
133
|
+
overflowY: element._overflowY || 'visible'
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await import('../atharvmandlavdiya.js');
|
|
137
|
+
|
|
138
|
+
const ProgressCard = customElements.get('progress-card');
|
|
139
|
+
const createdCards = [];
|
|
140
|
+
|
|
141
|
+
afterEach(() => {
|
|
142
|
+
for (const card of createdCards.splice(0)) {
|
|
143
|
+
card.parentElement?.removeChild(card);
|
|
144
|
+
card.disconnectedCallback();
|
|
145
|
+
}
|
|
146
|
+
globalThis.pageYOffset = 0;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
function createCard(parent = body, scrollLength = '300') {
|
|
150
|
+
const card = new ProgressCard();
|
|
151
|
+
card.setAttribute('data-scroll-length', scrollLength);
|
|
152
|
+
parent.appendChild(card);
|
|
153
|
+
card.connectedCallback();
|
|
154
|
+
createdCards.push(card);
|
|
155
|
+
const wrapper = card.parentElement;
|
|
156
|
+
wrapper._height = 3000;
|
|
157
|
+
wrapper._rect = { top: 0, height: 3000 };
|
|
158
|
+
card._onScroll();
|
|
159
|
+
return { card, wrapper };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
test('registers automatically, injects CSS, and needs no StringTune', () => {
|
|
163
|
+
assert.equal(typeof ProgressCard, 'function');
|
|
164
|
+
assert.match(head.children[0].textContent || head.children[0].style?.textContent || '', /progress-wrapper/);
|
|
165
|
+
assert.equal(globalThis.StringTune, undefined);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('uses the window scroll range and clamps at both ends', () => {
|
|
169
|
+
const { card } = createCard();
|
|
170
|
+
assert.equal(card.style.getPropertyValue('--progress'), '0');
|
|
171
|
+
globalThis.pageYOffset = 1000;
|
|
172
|
+
card.parentElement._rect = { top: -1000, height: 3000 };
|
|
173
|
+
card._onScroll();
|
|
174
|
+
assert.equal(card.style.getPropertyValue('--progress'), '0.5');
|
|
175
|
+
globalThis.pageYOffset = 2000;
|
|
176
|
+
card.parentElement._rect = { top: -2000, height: 3000 };
|
|
177
|
+
card._onScroll();
|
|
178
|
+
assert.equal(card.style.getPropertyValue('--progress'), '1');
|
|
179
|
+
globalThis.pageYOffset = 2500;
|
|
180
|
+
card.parentElement._rect = { top: -2500, height: 3000 };
|
|
181
|
+
card._onScroll();
|
|
182
|
+
assert.equal(card.style.getPropertyValue('--progress'), '1');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('uses the nearest nested scroll container', () => {
|
|
186
|
+
globalThis.pageYOffset = 0;
|
|
187
|
+
const brand = new FakeElement();
|
|
188
|
+
brand._overflowY = 'auto';
|
|
189
|
+
brand.clientHeight = 500;
|
|
190
|
+
brand.scrollHeight = 2000;
|
|
191
|
+
brand._rect = { top: 10, height: 500 };
|
|
192
|
+
body.appendChild(brand);
|
|
193
|
+
const { card, wrapper } = createCard(brand);
|
|
194
|
+
wrapper._height = 1500;
|
|
195
|
+
wrapper._rect = { top: 10, height: 1500 };
|
|
196
|
+
brand.scrollTop = 500;
|
|
197
|
+
wrapper._rect = { top: -490, height: 1500 };
|
|
198
|
+
card._onScroll();
|
|
199
|
+
assert.equal(card.style.getPropertyValue('--progress'), '0.5');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('keeps cards independent and removes listeners on disconnect', () => {
|
|
203
|
+
const first = createCard();
|
|
204
|
+
const second = createCard();
|
|
205
|
+
assert.notEqual(first.card, second.card);
|
|
206
|
+
assert.equal(globalThis.listeners.get('resize').size >= 2, true);
|
|
207
|
+
first.card.parentElement.removeChild(first.card);
|
|
208
|
+
first.card.disconnectedCallback();
|
|
209
|
+
assert.equal(globalThis.listeners.get('resize').size >= 1, true);
|
|
210
|
+
second.card.parentElement.removeChild(second.card);
|
|
211
|
+
second.card.disconnectedCallback();
|
|
212
|
+
assert.equal(globalThis.listeners.get('resize').size, 0);
|
|
213
|
+
});
|