PageSourceSearch

https://sorocaba.sp.gov.br/wp-content/themes/temaPortal2026/assets/js/portal-modal-motion.js?ver=1786620596

js sorocaba.sp.gov.br collected 2026-10-01 11:43:28 UTC 5,192 bytes, 174 lines download raw bytes

1(function () {
2    'use strict';
3
4    var MOTION = {
5        blur: 4,
6        scaleFrom: 0.91,
7        stiffness: 220,
8        damping: 31
9    };
10
11    var activeAnimations = new WeakMap();
12
13    function prefersReducedMotion() {
14        return window.matchMedia &&
15            window.matchMedia('(prefers-reduced-motion: reduce)').matches;
16    }
17
18    function getParts(modal) {
19        return {
20            backdrop: modal.querySelector('.portal-config-modal__backdrop'),
21            panel: modal.querySelector('.portal-config-modal__panel')
22        };
23    }
24
25    function cancelActive(modal) {
26        var animations = activeAnimations.get(modal) || [];
27
28        animations.forEach(function (animation) {
29            animation.cancel();
30        });
31
32        activeAnimations.delete(modal);
33    }
34
35    function simulateSpring(startScale, endScale, startOpacity, endOpacity) {
36        var dt = 1 / 60;
37        var minDuration = 0.18;
38        var maxDuration = 0.52;
39        var scale = startScale;
40        var velocity = 0;
41        var elapsed = 0;
42        var frames = [{
43            time: 0,
44            scale: startScale,
45            opacity: startOpacity
46        }];
47
48        while (elapsed < maxDuration) {
49            var displacement = scale - endScale;
50            var acceleration = (-MOTION.stiffness * displacement) - (MOTION.damping * velocity);
51
52            velocity += acceleration * dt;
53            scale += velocity * dt;
54            elapsed += dt;
55
56            var progress = Math.abs(endScale - startScale) > 0.0001
57                ? (scale - startScale) / (endScale - startScale)
58                : 1;
59            progress = Math.max(0, Math.min(1, progress));
60
61            frames.push({
62                time: elapsed,
63                scale: scale,
64                opacity: startOpacity + ((endOpacity - startOpacity) * progress)
65            });
66
67            if (elapsed >= minDuration && Math.abs(scale - endScale) < 0.001 && Math.abs(velocity) < 0.001) {
68                break;
69            }
70        }
71
72        frames[frames.length - 1] = {
73            time: elapsed,
74            scale: endScale,
75            opacity: endOpacity
76        };
77
78        return {
79            duration: Math.max(1, Math.round(elapsed * 1000)),
80            frames: frames
81        };
82    }
83
84    function buildKeyframes(simulation, includeTransform) {
85        var lastTime = simulation.frames[simulation.frames.length - 1].time || 1;
86
87        return simulation.frames.map(function (frame) {
88            var keyframe = {
89                offset: Math.max(0, Math.min(1, frame.time / lastTime)),
90                opacity: String(Math.max(0, Math.min(1, frame.opacity)))
91            };
92
93            if (includeTransform) {
94                keyframe.transform = 'scale(' + frame.scale.toFixed(4) + ')';
95            }
96
97            return keyframe;
98        });
99    }
100
101    function finishWithoutAnimation(modal, opening) {
102        modal.classList.toggle('hidden', !opening);
103        modal.setAttribute('data-state', opening ? 'open' : 'closed');
104
105        return Promise.resolve();
106    }
107
108    function run(modal, opening) {
109        if (!(modal instanceof HTMLElement)) {
110            return Promise.resolve();
111        }
112
113        cancelActive(modal);
114
115        var parts = getParts(modal);
116        if (!(parts.panel instanceof HTMLElement) || !(parts.backdrop instanceof HTMLElement)) {
117            return finishWithoutAnimation(modal, opening);
118        }
119
120        modal.style.setProperty('--portal-modal-backdrop-blur', MOTION.blur + 'px');
121        modal.style.setProperty('--portal-modal-scale-from', String(MOTION.scaleFrom));
122
123        if (prefersReducedMotion() || typeof parts.panel.animate !== 'function') {
124            return finishWithoutAnimation(modal, opening);
125        }
126
127        if (opening) {
128            modal.classList.remove('hidden');
129        }
130
131        modal.setAttribute('data-state', opening ? 'opening' : 'closing');
132
133        var simulation = opening
134            ? simulateSpring(MOTION.scaleFrom, 1, 0, 1)
135            : simulateSpring(1, MOTION.scaleFrom, 1, 0);
136        var timing = {
137            duration: simulation.duration,
138            easing: 'linear',
139            fill: 'both'
140        };
141        var animations = [
142            parts.backdrop.animate(buildKeyframes(simulation, false), timing),
143            parts.panel.animate(buildKeyframes(simulation, true), timing)
144        ];
145
146        activeAnimations.set(modal, animations);
147
148        return Promise.allSettled(animations.map(function (animation) {
149            return animation.finished;
150        })).then(function () {
151            if (activeAnimations.get(modal) !== animations) {
152                return;
153            }
154
155            modal.setAttribute('data-state', opening ? 'open' : 'closed');
156            modal.classList.toggle('hidden', !opening);
157
158            animations.forEach(function (animation) {
159                animation.cancel();
160            });
161
162            activeAnimations.delete(modal);
163        });
164    }
165
166    window.PortalModalMotion = {
167        open: function (modal) {
168            return run(modal, true);
169        },
170        close: function (modal) {
171            return run(modal, false);
172        }
173    };
174})();

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.