Skip to content

feat: windowless glass (floating on document.body) + modal option, with detached-glass move/resize hardening#75

Merged
ohxyz merged 12 commits into
mainfrom
feat/detached-glass-enhancement
Jun 17, 2026
Merged

feat: windowless glass (floating on document.body) + modal option, with detached-glass move/resize hardening#75
ohxyz merged 12 commits into
mainfrom
feat/detached-glass-enhancement

Conversation

@ohxyz

@ohxyz ohxyz commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Enhances detached glass and adds windowless glass — a detached glass that floats on document.body with no owning BinaryWindow. Along the way, hardens move/resize, extracts shared utilities, and extends theming.

What's in here

Windowless glass (new)

  • BinaryWindow.addWindowlessGlass(options) / removeWindowlessGlass(id) — a detached glass appended to document.body, registered with the shared detachedGlassManager for z-index/activation, with no owning window. Default actions are close only (DEFAULT_WINDOWLESS_GLASS_ACTIONS), since minimize/attach need a window.
  • Modal optionaddWindowlessGlass({ modal: true }) appends a <bw-glass-backdrop for="<glassId>"> behind the glass to block interaction underneath. It sits one z-index below its glass (using the slot the manager's topZIndex reservation leaves free) and is torn down by both removeWindowlessGlass and the close action via a shared removeGlassBackdrop helper.
  • Containing-block aware positioning so move/resize stay correct on a static body (origin = document origin, scroll-adjusted) vs. inside a positioned bw-window.

Fixes

  • Move/resize/activate work without a mounted window. Those listeners are document-global and instance-independent, but were only installed by an instance's enableFeatures(). Split them into enableDetachedGlassStandaloneFeatures(), invoked once at module load, so the static addWindowlessGlass path is fully interactive. Per-instance wiring keeps only the sill-bound restore handler.
  • Clamp detached-glass move to the viewport so dragging past an edge can't grow the page / trigger scrollbars.

Refactors

  • Extract a shared glass-transfer util (glass/utils.js) used by detach/attach.
  • Decouple detached-glass move from windowElement.
  • Move normActions into binary-window/utils.js.
  • Rename "free glass" → windowless glass throughout; enableGlassFeatureenableGlassFeatures; restore handler → enableRestoreFromMinimizedDetachedGlass.
  • Remove the disabled native-DnD detached-glass/drag.js in favor of free-floating move.js.

Theming

  • Move dark theme into its own theme.css; extend it to windowless glasses (themed via bw-glass[windowless]).

Dev pages & docs

  • New bwin-detached-windowless-glass dev page; windowless + modal + positioned + fullscreen cases also on the detached-glass page for comparison.
  • Rename dark-themebwin-dark-theme dev page.
  • Update ARCHITECTURE.md (§1 glossary, §8.5 standalone-vs-per-instance split, §8.6 windowless glass), conventions.md terminology, and resolve the now-fixed drag.js entry in TECH_DEBT.md.

ohxyz added 12 commits June 16, 2026 13:26
…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.
@ohxyz ohxyz changed the title Clamp detached glass move to the viewport + extract glass transfer util feat: windowless glass (floating on document.body) + modal option, with detached-glass move/resize hardening Jun 17, 2026
@ohxyz ohxyz merged commit 52e6292 into main Jun 17, 2026
@ohxyz ohxyz deleted the feat/detached-glass-enhancement branch June 17, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant