PageSourceSearch

https://www.ronc.ru/local/templates/ronc.site/app/composables/scrollStrategies.js

js ronc.ru collected 2026-10-02 06:37:09 UTC 3,442 bytes, 129 lines download raw bytes

1const scrollStrategies = {
2	none: null,
3	close: closeScrollStrategy,
4	block: blockScrollStrategy,
5	reposition: repositionScrollStrategy,
6}
7
8function makeScrollStrategyProps() {
9	return {
10		scrollStrategy: 'block', // [String, Function]
11	}
12}
13
14function useScrollStrategies(props, data) {
15	if (!IN_BROWSER) return
16
17	let scope
18	watchEffect(async () => {
19		scope?.stop()
20
21		if (!(data.isActive.value && props.scrollStrategy)) return
22
23		scope = effectScope()
24		await nextTick()
25		scope.run(() => {
26			if (typeof props.scrollStrategy === 'function') {
27				props.scrollStrategy(data)
28			} else {
29				scrollStrategies[props.scrollStrategy]?.(data)
30			}
31		})
32	})
33}
34
35function closeScrollStrategy(data) {
36	function onScroll(e) {
37		data.isActive.value = false
38	}
39
40	bindScroll(data.activatorEl.value ?? data.contentEl.value, onScroll)
41}
42
43function blockScrollStrategy(data) {
44	const scrollElements = [
45		...new Set([
46			...getScrollParents(data.activatorEl.value),
47			...getScrollParents(data.contentEl.value),
48		]),
49	].filter((el) => !el.classList.contains('x-overlay-scroll-blocked'))
50	const scrollbarWidth =
51		window.innerWidth - document.documentElement.offsetWidth
52
53	const scrollableParent = ((el) => hasScrollbar(el) && el)(
54		data.root.value?.offsetParent || document.documentElement,
55	)
56	if (scrollableParent) {
57		data.root.value.classList.add('x-overlay--scroll-blocked')
58	}
59
60	scrollElements.forEach((el, i) => {
61		el.style.setProperty('--x-body-scroll-x', convertToUnit(-el.scrollLeft))
62		el.style.setProperty('--x-body-scroll-y', convertToUnit(-el.scrollTop))
63		el.style.setProperty('--x-scrollbar-offset', convertToUnit(scrollbarWidth))
64		el.classList.add('x-overlay-scroll-blocked')
65	})
66
67	onScopeDispose(() => {
68		scrollElements.forEach((el, i) => {
69			const x = parseFloat(el.style.getPropertyValue('--x-body-scroll-x'))
70			const y = parseFloat(el.style.getPropertyValue('--x-body-scroll-y'))
71
72			el.style.removeProperty('--x-body-scroll-x')
73			el.style.removeProperty('--x-body-scroll-y')
74			el.style.removeProperty('--x-scrollbar-offset')
75			el.classList.remove('x-overlay-scroll-blocked')
76
77			el.scrollLeft = -x
78			el.scrollTop = -y
79		})
80		if (scrollableParent) {
81			data.root.value.classList.remove('x-overlay--scroll-blocked')
82		}
83	})
84}
85
86function repositionScrollStrategy(data) {
87	let slow = false
88	let raf = -1
89
90	function update(e) {
91		requestNewFrame(() => {
92			const start = performance.now()
93			data.updateLocation.value?.(e)
94			const time = performance.now() - start
95			slow = time / (1000 / 60) > 2
96		})
97	}
98
99	bindScroll(data.activatorEl.value ?? data.contentEl.value, (e) => {
100		if (slow) {
101			// If the position calculation is slow,
102			// defer updates until scrolling is finished.
103			// Browsers usually fire one scroll event per frame so
104			// we just wait until we've got two frames without an event
105			cancelAnimationFrame(raf)
106			raf = requestAnimationFrame(() => {
107				raf = requestAnimationFrame(() => {
108					update(e)
109				})
110			})
111		} else {
112			update(e)
113		}
114	})
115}
116
117/** @private */
118function bindScroll(el, onScroll) {
119	const scrollElements = [document, ...getScrollParents(el)]
120	scrollElements.forEach((el) => {
121		el.addEventListener('scroll', onScroll, { passive: true })
122	})
123
124	onScopeDispose(() => {
125		scrollElements.forEach((el) => {
126			el.removeEventListener('scroll', onScroll)
127		})
128	})
129}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.