fix: detached glass move/resize/activate work without a mounted window#85
Merged
Conversation
…rollbars Dragging a detached glass by its header could push it past the viewport edge and grow the page, surfacing browser scrollbars. Clamp the move to the viewport (clientWidth/Height, which exclude scrollbars), reserving the resize-handle overhang on the right/bottom so hover handles stay on-screen. Extract clamp() to utils and getResizeHandleOverhang() to detached-glass/utils.
Derive the containing block from the glass via offsetParent and bind pointer listeners to document instead of windowElement. getResizeHandleOverhang now reads the inherited handle-size var from the glass element itself.
addFreeGlass is a static BinaryWindow method that builds a detached glass and appends it to document.body instead of a bw-window, managed by the shared glass manager and tagged with a 'free' attribute. Free glasses default to close-only actions since minimize/attach need an owning window. Move math now resolves the containing-block origin via getContainingBlockOrigin: the positioned bw-window for a detached glass, or the scroll-shifted viewport origin for a free glass on a static body. CSS vars move to :root so a free glass outside any bw-window still inherits them.
Move the detached-glass resize and activate pointer listeners from windowElement to document so they also fire for a free glass living on document.body, and normalize resize start geometry via getContainingBlockOrigin (positioned bw-window for detached, scroll-shifted viewport for free). bringToFront now clears the [active] marker across all managed glasses rather than only :scope siblings, so a detached and a free glass (different parents) can't both look active at once. Dev page: add a fullscreen-popup button exercising a non-draggable free glass inset 20px from every viewport edge.
"Free" described a property a detached glass already has (it floats and moves freely within the window). The distinguishing trait is that this glass has no owning bw-window, so name it for that: addWindowlessGlass, DEFAULT_WINDOWLESS_GLASS_ACTIONS, and the bw-glass[windowless] attribute.
Split bw-window[theme='dark'] out of vars.css so vars.css holds only the :root token defaults. Import theme.css last so its overrides win on source order.
Match bw-glass[windowless][theme='dark'] so a windowless glass on the page body picks up dark tokens. TODO left to differentiate window vs windowless settings.
…glass button Rename the dark-theme example to the bwin-* convention, add an 'Add windowless glass' button, and have the index theme toggle also flip bw-glass[windowless].
Add a `modal` option to addWindowlessGlass that appends a <bw-glass-backdrop for="<glassId>"> behind the glass to block interaction underneath. The backdrop sits one z-index below its glass, using the slot the manager's topZIndex reservation leaves free. Tear down the backdrop in both removeWindowlessGlass and the detached close action via a shared removeGlassBackdrop helper. Expand the addWindowlessGlass JSDoc to enumerate all options.
Detached glass move/resize/activate attach document-global, instance- independent listeners, but were only installed by an instance's enableFeatures(). The static addWindowlessGlass() path never mounts an instance, so windowless glasses on a window-less page weren't movable. Split those listeners into enableDetachedGlassStandaloneFeatures(), invoked once at module load, leaving only the sill-bound restore handler per-instance. Drop the disabled native-DnD drag.js. Rename enableGlassFeature -> enableGlassFeatures and the restore handler to enableRestoreFromMinimizedDetachedGlass for clarity. Add a dedicated bwin-detached-windowless-glass dev page.
Update ARCHITECTURE §8.5/§8.6 for the standalone/per-instance split: activate/move/resize are document-global and installed once at module load (enableDetachedGlassStandaloneFeatures), which is what lets the static addWindowlessGlass work with no mounted window; restore stays per-instance. Drop the deleted drag.js from the file table and remove the now-resolved disabled-alternate-path entry from TECH_DEBT.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes detached-glass move / resize / activate work even when no
BinaryWindowis mounted — which is the case for windowless glasses created via the staticaddWindowlessGlass. (The windowless-glass and modal features themselves are already onmain; this is the follow-up that makes them fully interactive standalone.)The bug
move/resize/activateattach document-global, instance-independent listeners (they locate their target viaclosest('bw-glass[detached]')and never readthis). But they were only installed by an instance'senableFeatures()duringmount(). A page that only calls the staticaddWindowlessGlassnever mounts an instance, so those listeners were never attached and the glass couldn't be moved/resized/focused. It only appeared to work on pages that happened to also mount aBinaryWindow.The fix
enableDetachedGlassStandaloneFeatures(), invoked once at module load inbinary-window.js(module evaluation is one-time, so no idempotency flag needed). ImportingBinaryWindowis now enough to wire move/resize/activate.enableDetachedGlassFeatures()(per-instance) keeps only the sill-bound restore handler, which genuinely needsthis.sillElement.detached-glass/drag.jsin favor of free-floatingmove.js.Renames (clarity)
enableGlassFeature→enableGlassFeaturesenableRestoreFromMinimizedDetachedGlassDev page & docs
bwin-detached-windowless-glassdev page exercising windowless move/resize/activate with no mounted window.ARCHITECTURE.md§8.5 documents the standalone-vs-per-instance split; §8.6 notes windowless interactions work without a mounted window. Resolve the now-fixeddrag.jsentry inTECH_DEBT.md.