@lavalogic/scoria 0.37.32 → 0.37.33
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/dist/Helpers/dropdownPortal.js +29 -74
- package/package.json +1 -1
|
@@ -90,8 +90,6 @@ export function attachDropdownPortal(options) {
|
|
|
90
90
|
/* nothing wired up */
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
let originalParent = null;
|
|
94
|
-
let originalNextSibling = null;
|
|
95
93
|
let isPortalled = false;
|
|
96
94
|
const reposition = () => {
|
|
97
95
|
if (!isPortalled) {
|
|
@@ -140,68 +138,36 @@ export function attachDropdownPortal(options) {
|
|
|
140
138
|
const handleResize = () => {
|
|
141
139
|
throttled.schedule();
|
|
142
140
|
};
|
|
143
|
-
/**
|
|
144
|
-
* Direct mousedown listener attached to the portaled dropdown that
|
|
145
|
-
* calls `preventDefault()` to keep focus on the Svelecte input while
|
|
146
|
-
* the user clicks an option.
|
|
147
|
-
*
|
|
148
|
-
* Svelecte already attaches `onmousedown={preventDefault}` to the
|
|
149
|
-
* `.sv_dropdown` element in template, but Svelte 5 wires inline
|
|
150
|
-
* event handlers through its delegated-event chain rooted at the
|
|
151
|
-
* original mount point. Once we `appendChild` the dropdown to
|
|
152
|
-
* `document.body` (or to a `<dialog>` ancestor) the delegated chain
|
|
153
|
-
* no longer finds this element, the inline handler never fires,
|
|
154
|
-
* the browser's default mousedown shifts focus to the option (or to
|
|
155
|
-
* `body`), Svelecte's `on_blur` runs `updateDropdownState(false)`
|
|
156
|
-
* which closes the dropdown, this helper's MutationObserver moves
|
|
157
|
-
* the dropdown back into place, and the `mouseup` / `click` events
|
|
158
|
-
* never reach an option element. The visible symptom: keyboard
|
|
159
|
-
* selection (Enter) works, mouse click does not.
|
|
160
|
-
*
|
|
161
|
-
* Adding a *direct* `addEventListener` on the dropdown bypasses
|
|
162
|
-
* Svelte's delegation entirely. The listener is reset every
|
|
163
|
-
* `portalOut` / `portalIn` cycle.
|
|
164
|
-
*/
|
|
165
|
-
const preventFocusShiftOnMousedown = (e) => {
|
|
166
|
-
// Same intent as Svelecte's own `on_mouse_down`. Keep focus on
|
|
167
|
-
// the input so `on_blur` does not collapse the dropdown before
|
|
168
|
-
// the click event reaches its selection handler.
|
|
169
|
-
e.preventDefault();
|
|
170
|
-
};
|
|
171
141
|
const portalOut = () => {
|
|
172
142
|
if (isPortalled) {
|
|
173
143
|
return;
|
|
174
144
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
145
|
+
// PREVIOUSLY: this helper moved the dropdown to `document.body`
|
|
146
|
+
// (or to the open `<dialog>` ancestor) via `appendChild` so it
|
|
147
|
+
// would escape ancestor `overflow: hidden` / `z-index` clipping.
|
|
148
|
+
// That hop broke Svelte 5's per-component event delegation:
|
|
149
|
+
// inline `onmousedown` / `onclick` handlers in Svelecte's
|
|
150
|
+
// template (specifically the `.sv_dropdown` element) are wired
|
|
151
|
+
// through a delegated dispatch rooted at the component's
|
|
152
|
+
// original mount point, and the dispatch's parent-chain walk
|
|
153
|
+
// never reaches the moved element. The visible symptom: mouse
|
|
154
|
+
// clicks on dropdown options did not select (keyboard Enter
|
|
155
|
+
// did, because that path bypasses the dropdown's click
|
|
156
|
+
// handler).
|
|
157
|
+
//
|
|
158
|
+
// We now leave the dropdown in its original DOM location and
|
|
159
|
+
// only flip it to `position: fixed`. `position: fixed` escapes
|
|
160
|
+
// ancestor `overflow` clipping (the original motivation for
|
|
161
|
+
// portaling) without removing the element from its component
|
|
162
|
+
// tree, so Svelte's delegated dispatch continues to find it.
|
|
163
|
+
// The reposition logic below tracks the trigger via
|
|
164
|
+
// `getBoundingClientRect` exactly as before.
|
|
180
165
|
dropdown.style.display = '';
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
// Without this hop the dropdown's `z-index: 10000` was still painted
|
|
186
|
-
// behind the dialog backdrop and its content (the symptom that
|
|
187
|
-
// surfaced as "select options disappear behind the allocate modal").
|
|
188
|
-
const dialogHost = trigger.closest('dialog');
|
|
189
|
-
const portalTarget = dialogHost && dialogHost.open ? dialogHost : document.body;
|
|
190
|
-
portalTarget.appendChild(dropdown);
|
|
191
|
-
// Tag the teleported dropdown so any "click outside the
|
|
192
|
-
// panel" / "click outside the trigger" handler elsewhere in
|
|
193
|
-
// the codebase can recognise the dropdown as a logical
|
|
194
|
-
// extension of its trigger and ignore clicks landing inside
|
|
195
|
-
// it. The `TableSidebar` side-panel uses this marker (along
|
|
196
|
-
// with `closest('.sv_dropdown')`) so clicking an option in a
|
|
197
|
-
// teleported filter-row dropdown does not close the
|
|
198
|
-
// side-panel under it. Components that want to ignore
|
|
199
|
-
// portal clicks should check
|
|
200
|
-
// `el.closest('[data-scoria-portal-dropdown]')`.
|
|
166
|
+
// Marker preserved for any consumer that still uses it (e.g.
|
|
167
|
+
// the TableSidebar "click-outside" handler). The dropdown is
|
|
168
|
+
// no longer literally portaled, but the marker means "treat
|
|
169
|
+
// clicks landing here as part of the trigger".
|
|
201
170
|
dropdown.setAttribute('data-scoria-portal-dropdown', '');
|
|
202
|
-
// Restore the focus-preserving mousedown handler that Svelte's
|
|
203
|
-
// delegated event chain no longer reaches after the move.
|
|
204
|
-
dropdown.addEventListener('mousedown', preventFocusShiftOnMousedown);
|
|
205
171
|
isPortalled = true;
|
|
206
172
|
// First-frame measurement: lay out, then reposition again on
|
|
207
173
|
// the next frame so we measure the dropdown's real
|
|
@@ -220,7 +186,6 @@ export function attachDropdownPortal(options) {
|
|
|
220
186
|
return;
|
|
221
187
|
}
|
|
222
188
|
throttled.cancel();
|
|
223
|
-
dropdown.removeEventListener('mousedown', preventFocusShiftOnMousedown);
|
|
224
189
|
window.removeEventListener('scroll', handleScroll, { capture: true });
|
|
225
190
|
window.removeEventListener('resize', handleResize);
|
|
226
191
|
// Strip the inline overrides so Svelecte's next open starts
|
|
@@ -240,24 +205,14 @@ export function attachDropdownPortal(options) {
|
|
|
240
205
|
// `display: none` (e.g. on certain transition-cancel race paths
|
|
241
206
|
// the open/close class flip and the inline style update arrive
|
|
242
207
|
// out of order), the dropdown would now be `position: static;
|
|
243
|
-
// display: block`
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
208
|
+
// display: block` and contribute its option list's height to
|
|
209
|
+
// the page scroll size, which is what surfaces as a stray
|
|
210
|
+
// page-level vertical scrollbar after toggling a select. Force
|
|
211
|
+
// `display: none` here; Svelecte will restore the inline style
|
|
212
|
+
// on next open via its own class-driven render.
|
|
248
213
|
if (!dropdown.classList.contains('is-open')) {
|
|
249
214
|
dropdown.style.display = 'none';
|
|
250
215
|
}
|
|
251
|
-
if (originalParent != null) {
|
|
252
|
-
if (originalNextSibling != null && originalNextSibling.parentNode === originalParent) {
|
|
253
|
-
originalParent.insertBefore(dropdown, originalNextSibling);
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
originalParent.appendChild(dropdown);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
originalParent = null;
|
|
260
|
-
originalNextSibling = null;
|
|
261
216
|
isPortalled = false;
|
|
262
217
|
};
|
|
263
218
|
// Apply / unapply the portal whenever Svelecte toggles the
|