@marianmeres/stuic 3.105.0 → 3.107.0
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.
|
@@ -173,6 +173,15 @@ export function validate(el, fn) {
|
|
|
173
173
|
const _doValidate = () => {
|
|
174
174
|
if (!enabled)
|
|
175
175
|
return;
|
|
176
|
+
// A focused, dirty field torn down by a route change fires a final
|
|
177
|
+
// synchronous `change`/`blur` while being removed from the DOM. That
|
|
178
|
+
// removal runs inside Svelte's flush, so writing `validation` state here
|
|
179
|
+
// would throw `state_unsafe_mutation`. By then the node is already
|
|
180
|
+
// detached (`isConnected === false`) and the field is going away — skip.
|
|
181
|
+
// No-op for normal interactive validation and for the synchronous
|
|
182
|
+
// imperative `validate()` path, both of which run while connected.
|
|
183
|
+
if (!el.isConnected)
|
|
184
|
+
return;
|
|
176
185
|
el.checkValidity();
|
|
177
186
|
// Store customValidator message directly - hidden inputs (type="hidden")
|
|
178
187
|
// don't populate el.validationMessage even when setCustomValidity() is called.
|
|
@@ -210,9 +219,6 @@ export function validate(el, fn) {
|
|
|
210
219
|
return m;
|
|
211
220
|
}, []);
|
|
212
221
|
// console.log(1111, validityState, el);
|
|
213
|
-
// hm... Uncaught Svelte error: state_unsafe_mutation...
|
|
214
|
-
// the `tick` await helps, but I'm not really sure I understand the internals...
|
|
215
|
-
// tick().then(() => {
|
|
216
222
|
setValidationResult?.({
|
|
217
223
|
validity: validityState,
|
|
218
224
|
reasons,
|
|
@@ -224,7 +230,6 @@ export function validate(el, fn) {
|
|
|
224
230
|
el.validationMessage ||
|
|
225
231
|
"This field is invalid. Please review and try again."),
|
|
226
232
|
});
|
|
227
|
-
// });
|
|
228
233
|
};
|
|
229
234
|
// Expose the current validator to the host so it can trigger validation
|
|
230
235
|
// imperatively (e.g., on submit). The closure captures the current
|
|
@@ -26,6 +26,13 @@ import type { Attachment } from "svelte/attachments";
|
|
|
26
26
|
* then a `ResizeObserver` keeps it in sync. With no transition configured, or under
|
|
27
27
|
* `prefers-reduced-motion`, the height simply snaps and nothing is ever clipped.
|
|
28
28
|
*
|
|
29
|
+
* Resize-driven measures are coalesced to the next animation frame, so the height
|
|
30
|
+
* write never happens *inside* the `ResizeObserver` delivery cycle. Mutating layout
|
|
31
|
+
* synchronously in that callback is what triggers the browser's benign-but-noisy
|
|
32
|
+
* "ResizeObserver loop completed with undelivered notifications" warning; the
|
|
33
|
+
* one-frame deferral (~16ms, imperceptible against the transition) avoids it. The
|
|
34
|
+
* initial on-mount measure stays synchronous to keep the height lock before paint.
|
|
35
|
+
*
|
|
29
36
|
* @example
|
|
30
37
|
* ```svelte
|
|
31
38
|
* <div class="viewport" {@attach autoHeight}>
|
|
@@ -25,6 +25,13 @@
|
|
|
25
25
|
* then a `ResizeObserver` keeps it in sync. With no transition configured, or under
|
|
26
26
|
* `prefers-reduced-motion`, the height simply snaps and nothing is ever clipped.
|
|
27
27
|
*
|
|
28
|
+
* Resize-driven measures are coalesced to the next animation frame, so the height
|
|
29
|
+
* write never happens *inside* the `ResizeObserver` delivery cycle. Mutating layout
|
|
30
|
+
* synchronously in that callback is what triggers the browser's benign-but-noisy
|
|
31
|
+
* "ResizeObserver loop completed with undelivered notifications" warning; the
|
|
32
|
+
* one-frame deferral (~16ms, imperceptible against the transition) avoids it. The
|
|
33
|
+
* initial on-mount measure stays synchronous to keep the height lock before paint.
|
|
34
|
+
*
|
|
28
35
|
* @example
|
|
29
36
|
* ```svelte
|
|
30
37
|
* <div class="viewport" {@attach autoHeight}>
|
|
@@ -73,13 +80,22 @@ export const autoHeight = (node) => {
|
|
|
73
80
|
if (e.target === node && e.propertyName === "height")
|
|
74
81
|
node.style.overflow = "";
|
|
75
82
|
};
|
|
83
|
+
// Defer the resize-driven measure to the next frame so the layout write
|
|
84
|
+
// never lands inside the ResizeObserver delivery cycle (see top doc comment).
|
|
85
|
+
let rafId = 0;
|
|
86
|
+
const scheduleMeasure = () => {
|
|
87
|
+
cancelAnimationFrame(rafId);
|
|
88
|
+
rafId = requestAnimationFrame(measure);
|
|
89
|
+
};
|
|
90
|
+
// Initial measure stays synchronous: lock height from `auto` to px before paint.
|
|
76
91
|
measure();
|
|
77
|
-
const ro = new ResizeObserver(
|
|
92
|
+
const ro = new ResizeObserver(scheduleMeasure);
|
|
78
93
|
if (node.firstElementChild)
|
|
79
94
|
ro.observe(node.firstElementChild);
|
|
80
95
|
node.addEventListener("transitionend", reveal);
|
|
81
96
|
node.addEventListener("transitioncancel", reveal);
|
|
82
97
|
return () => {
|
|
98
|
+
cancelAnimationFrame(rafId);
|
|
83
99
|
ro.disconnect();
|
|
84
100
|
node.removeEventListener("transitionend", reveal);
|
|
85
101
|
node.removeEventListener("transitioncancel", reveal);
|