@asd20/ui-next 2.0.1 → 2.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.2](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.0.1...ui-next-v2.0.2) (2026-03-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * replace basicscroll scroll-track runtime ([c0fe361](https://github.com/academydistrict20/asd20-ui-next/commit/c0fe361c301bbf1d132eac7876c5e02cabe4a5b0))
9
+
3
10
  ## [2.0.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.0.0...ui-next-v2.0.1) (2026-03-27)
4
11
 
5
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -34,7 +34,6 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "axios": "^1.13.6",
37
- "basicscroll": "^3.0.2",
38
37
  "countup.js": "^2.0.0",
39
38
  "date-fns": "^2.30.0",
40
39
  "date-fns-tz": "^1.1.7",
@@ -1,32 +1,190 @@
1
- import * as basicScroll from 'basicscroll'
1
+ const DEFAULT_VARIABLE_NAME = 'scroll-progress'
2
2
 
3
- function mountScrollTrack(el, { modifiers = {}, expression } = {}) {
3
+ function clamp(value, min, max) {
4
+ return Math.min(Math.max(value, min), max)
5
+ }
6
+
7
+ function getScrollTop() {
8
+ const scrollingElement =
9
+ document.scrollingElement || document.documentElement || document.body
10
+
11
+ return scrollingElement ? scrollingElement.scrollTop : 0
12
+ }
13
+
14
+ function getViewportHeight() {
15
+ return (
16
+ window.innerHeight ||
17
+ window.outerHeight ||
18
+ document.documentElement?.clientHeight ||
19
+ 1
20
+ )
21
+ }
22
+
23
+ function parseAbsoluteValue(value) {
24
+ if (typeof value === 'number' && Number.isFinite(value)) {
25
+ return value
26
+ }
27
+
28
+ if (typeof value !== 'string') {
29
+ return null
30
+ }
31
+
32
+ const parsedValue = Number.parseFloat(value)
33
+
34
+ return Number.isFinite(parsedValue) ? parsedValue : null
35
+ }
36
+
37
+ function resolveKeywordValue(value, el, scrollTop, viewportHeight) {
38
+ if (!el || typeof value !== 'string') {
39
+ return null
40
+ }
41
+
42
+ const match = value.match(/^(top|middle|bottom)-(top|middle|bottom)$/)
43
+
44
+ if (!match) {
45
+ return null
46
+ }
47
+
48
+ const [, elementEdge, viewportEdge] = match
49
+ const rect = el.getBoundingClientRect()
50
+ let absoluteOffset = scrollTop + rect.top
51
+
52
+ if (elementEdge === 'middle') {
53
+ absoluteOffset += rect.height / 2
54
+ } else if (elementEdge === 'bottom') {
55
+ absoluteOffset += rect.height
56
+ }
57
+
58
+ if (viewportEdge === 'middle') {
59
+ absoluteOffset -= viewportHeight / 2
60
+ } else if (viewportEdge === 'bottom') {
61
+ absoluteOffset -= viewportHeight
62
+ }
63
+
64
+ return absoluteOffset
65
+ }
66
+
67
+ function resolveBoundary(value, el, scrollTop, viewportHeight) {
68
+ const absoluteValue = parseAbsoluteValue(value)
69
+
70
+ if (absoluteValue !== null) {
71
+ return absoluteValue
72
+ }
73
+
74
+ return resolveKeywordValue(value, el, scrollTop, viewportHeight)
75
+ }
76
+
77
+ function getBindingConfig(el, { modifiers = {}, expression } = {}) {
78
+ const viewportHeight = getViewportHeight()
79
+ const scrollTop = getScrollTop()
80
+ const from = modifiers.window
81
+ ? 0
82
+ : resolveBoundary('middle-top', el, scrollTop, viewportHeight)
83
+ const to = modifiers.window
84
+ ? window.outerHeight || viewportHeight
85
+ : resolveBoundary('middle-bottom', el, scrollTop, viewportHeight)
86
+
87
+ return {
88
+ cssVariable: `--${expression || DEFAULT_VARIABLE_NAME}`,
89
+ from,
90
+ to,
91
+ }
92
+ }
93
+
94
+ function setProgress(el, cssVariable, progress) {
95
+ const normalizedProgress = Number.isFinite(progress)
96
+ ? Math.round(progress * 10000) / 10000
97
+ : 0
98
+
99
+ el.style.setProperty(cssVariable, String(normalizedProgress))
100
+ }
101
+
102
+ function updateScrollTrack(el) {
103
+ if (typeof window === 'undefined' || !el.__scrollTrackState) {
104
+ return
105
+ }
106
+
107
+ const scrollTop = getScrollTop()
108
+ const { cssVariable, from, to } = getBindingConfig(
109
+ el,
110
+ el.__scrollTrackState.binding
111
+ )
112
+
113
+ if (from === null || to === null) {
114
+ setProgress(el, cssVariable, 0)
115
+ return
116
+ }
117
+
118
+ if (from === to) {
119
+ setProgress(el, cssVariable, scrollTop >= to ? 1 : 0)
120
+ return
121
+ }
122
+
123
+ const progress = clamp((scrollTop - from) / (to - from), 0, 1)
124
+
125
+ setProgress(el, cssVariable, progress)
126
+ }
127
+
128
+ function mountScrollTrack(el, binding = {}) {
4
129
  if (typeof window === 'undefined') return
5
130
 
6
- el.__scroll = basicScroll.create({
7
- elem: el,
8
- from: modifiers.window ? 0 : 'middle-top',
9
- to: modifiers.window ? window.outerHeight : 'middle-bottom',
10
- direct: true,
11
- props: {
12
- [`--${expression || 'scroll-progress'}`]: {
13
- from: '0',
14
- to: '1',
15
- },
131
+ unmountScrollTrack(el)
132
+
133
+ const state = {
134
+ binding,
135
+ frameId: null,
136
+ handleUpdate() {
137
+ updateScrollTrack(el)
138
+ },
139
+ scheduleUpdate() {
140
+ if (state.frameId !== null) {
141
+ return
142
+ }
143
+
144
+ state.frameId = window.requestAnimationFrame(() => {
145
+ state.frameId = null
146
+ state.handleUpdate()
147
+ })
16
148
  },
17
- })
18
- el.__scroll.start()
149
+ }
150
+
151
+ el.__scrollTrackState = state
152
+ updateScrollTrack(el)
153
+
154
+ window.addEventListener('scroll', state.scheduleUpdate, { passive: true })
155
+ window.addEventListener('resize', state.scheduleUpdate)
156
+ }
157
+
158
+ function updateBinding(el, binding = {}) {
159
+ if (!el.__scrollTrackState) {
160
+ mountScrollTrack(el, binding)
161
+ return
162
+ }
163
+
164
+ el.__scrollTrackState.binding = binding
165
+ updateScrollTrack(el)
19
166
  }
20
167
 
21
168
  function unmountScrollTrack(el) {
22
- if (!el.__scroll) return
23
- el.__scroll.stop()
24
- delete el.__scroll
169
+ const state = el.__scrollTrackState
170
+
171
+ if (!state || typeof window === 'undefined') return
172
+
173
+ window.removeEventListener('scroll', state.scheduleUpdate)
174
+ window.removeEventListener('resize', state.scheduleUpdate)
175
+
176
+ if (state.frameId !== null) {
177
+ window.cancelAnimationFrame(state.frameId)
178
+ }
179
+
180
+ delete el.__scrollTrackState
25
181
  }
26
182
 
27
183
  export default {
28
184
  inserted: mountScrollTrack,
29
185
  mounted: mountScrollTrack,
186
+ update: updateBinding,
187
+ updated: updateBinding,
30
188
  unbind: unmountScrollTrack,
31
189
  unmounted: unmountScrollTrack,
32
190
  }