chore(release): version packages - #47
Merged
Merged
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
August 24, 2026 16:19
a21ca1b to
54c9d06
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
August 25, 2026 16:33
54c9d06 to
b52e026
Compare
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.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@dunky.dev/dialog@0.4.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
#39
6b51d8dThanks @ivanbanov! -closeOnBackis now symmetric: the browser's Forward reopens what Backclosed. The history entry a Back press spends survives in the forward stack
and keeps marking the dialog's open ground — traversing forward into it
reopens the dialog, guarded again for the next Back. Reopening through the
trigger instead plants a fresh entry, exactly like navigating after a Back.
No new setting: back-close and forward-reopen are one behavior, so the
existing
closeOnBackgates both. Both DOM substrates get it — React andSolid — from the same code.
The reopen follows the shared dismissal contract — a new
onForwardNavigationcallback fires first andpreventDefault()vetoes,and a controlled dialog only records the intent:
A nested dialog comes back too. Closing the layer it was opened from unmounts
it — machine and all — so the ground it lost to a Back press has no owner left
to reopen it. It reopens anyway: the ground belongs to the dialog's place in
the stack rather than to the instance that planted it, so the dialog that
comes back with its parent recognizes it. Two dialogs at the same place can't
be told apart, and then neither reopens. The same recognition survives a
reload, so a traversal back into that ground reopens the dialog even after the
page went away.
Under the hood,
interceptBackNavigation(onBack, options?)takes its optionalcallbacks as an object and grew
claim, the name for that ground, plus awatchSpentEntry(claim, reopen)for a closed layer waiting to be recognized.A Back-closed guard parks instead of dropping, a traversal re-entering its
spent entry asks the layer to reopen, and the guard re-arms on that entry in
place. A layer that passes neither option behaves exactly as before. A layer
that closed gave its ground up on purpose and nothing reopens from it —
Forward never undoes a dismissal the user made deliberately.
guardBackNavigation(@dunky.dev/dom-dialog) now returns{ sync, release }rather than a bare disposer: the guard outlives the openstate — that is the whole point of the Forward watch — so a host reports
every change through
sync(open)and ends the episode withrelease().Whether a close parks the registration or releases it stays a DOM-layer
decision, made once for every substrate.
One web-mechanics caveat, spec'd in the navigation util and both DOM
bindings: a controlled dialog's Back-close is completed by the consumer
rather than by the press, so its entry is consumed and Forward has nothing to
re-enter.
@dunky.dev/overlay@0.2.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
#39
4698e0cThanks @ivanbanov! - Assistive-tech containment no longer lapses while a non-modal layer is openabove a modal one.
Containment now follows the topmost modal layer rather than the topmost
layer. The ordinary layers — a select menu, a combobox list, a tooltip, a
context menu — are non-modal and live inside dialogs; opening one used to
release the dialog's containment, leaving the page behind reachable by
pointer, keyboard, and screen reader for exactly as long as someone was
interacting with the menu. The layers stacked above the modal one are held
out of the hiding — they portal to the body as siblings of the dialog, so
without the exception the containment would inert the very layer the user is
in. Topmost keeps its meaning: a non-modal layer above still owns Escape and
the focus trap; only containment stays put.
To support this, the agnostic stack gains a public
ordered()methodreturning every layer topmost first — the host needs to look past the top of
the stack, while modality stays a host concept:
@dunky.dev/dom-dialog@0.2.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
#39
6b51d8dThanks @ivanbanov! -closeOnBackis now symmetric: the browser's Forward reopens what Backclosed. The history entry a Back press spends survives in the forward stack
and keeps marking the dialog's open ground — traversing forward into it
reopens the dialog, guarded again for the next Back. Reopening through the
trigger instead plants a fresh entry, exactly like navigating after a Back.
No new setting: back-close and forward-reopen are one behavior, so the
existing
closeOnBackgates both. Both DOM substrates get it — React andSolid — from the same code.
The reopen follows the shared dismissal contract — a new
onForwardNavigationcallback fires first andpreventDefault()vetoes,and a controlled dialog only records the intent:
A nested dialog comes back too. Closing the layer it was opened from unmounts
it — machine and all — so the ground it lost to a Back press has no owner left
to reopen it. It reopens anyway: the ground belongs to the dialog's place in
the stack rather than to the instance that planted it, so the dialog that
comes back with its parent recognizes it. Two dialogs at the same place can't
be told apart, and then neither reopens. The same recognition survives a
reload, so a traversal back into that ground reopens the dialog even after the
page went away.
Under the hood,
interceptBackNavigation(onBack, options?)takes its optionalcallbacks as an object and grew
claim, the name for that ground, plus awatchSpentEntry(claim, reopen)for a closed layer waiting to be recognized.A Back-closed guard parks instead of dropping, a traversal re-entering its
spent entry asks the layer to reopen, and the guard re-arms on that entry in
place. A layer that passes neither option behaves exactly as before. A layer
that closed gave its ground up on purpose and nothing reopens from it —
Forward never undoes a dismissal the user made deliberately.
guardBackNavigation(@dunky.dev/dom-dialog) now returns{ sync, release }rather than a bare disposer: the guard outlives the openstate — that is the whole point of the Forward watch — so a host reports
every change through
sync(open)and ends the episode withrelease().Whether a close parks the registration or releases it stays a DOM-layer
decision, made once for every substrate.
One web-mechanics caveat, spec'd in the navigation util and both DOM
bindings: a controlled dialog's Back-close is completed by the consumer
rather than by the press, so its entry is consumed and Forward has nothing to
re-enter.
Patch Changes
#48
c35d1abThanks @ivanbanov! -openDialogLayernow warns when focus cannot move into the dialog at all —when the initial focus target refuses focus and the dialog window can't take
the fallback either (typically because it lacks
tabindex="-1"). Focusstranded outside an open modal breaks the modal dialog pattern; the miss used
to be silent, now the warning names the fix.
#46
5a58c2dThanks @ivanbanov! - Rename@dunky.dev/dom-navigationto@dunky.dev/browser-navigation.The util guards the browser's session history — Back, Forward, reload — and
never touches the DOM, so the old name pointed at the wrong layer. The API is
unchanged; only the package name moves:
@dunky.dev/dom-navigationwill receive no further releases.Updated dependencies [
a33e149,8ae32b4,ffa4fad,6b51d8d,979c3c7,560d539,6ed64a2,c35d1ab,4698e0c,5a58c2d]:@dunky.dev/browser-navigation@0.2.0
Minor Changes
#39
6b51d8dThanks @ivanbanov! -closeOnBackis now symmetric: the browser's Forward reopens what Backclosed. The history entry a Back press spends survives in the forward stack
and keeps marking the dialog's open ground — traversing forward into it
reopens the dialog, guarded again for the next Back. Reopening through the
trigger instead plants a fresh entry, exactly like navigating after a Back.
No new setting: back-close and forward-reopen are one behavior, so the
existing
closeOnBackgates both. Both DOM substrates get it — React andSolid — from the same code.
The reopen follows the shared dismissal contract — a new
onForwardNavigationcallback fires first andpreventDefault()vetoes,and a controlled dialog only records the intent:
A nested dialog comes back too. Closing the layer it was opened from unmounts
it — machine and all — so the ground it lost to a Back press has no owner left
to reopen it. It reopens anyway: the ground belongs to the dialog's place in
the stack rather than to the instance that planted it, so the dialog that
comes back with its parent recognizes it. Two dialogs at the same place can't
be told apart, and then neither reopens. The same recognition survives a
reload, so a traversal back into that ground reopens the dialog even after the
page went away.
Under the hood,
interceptBackNavigation(onBack, options?)takes its optionalcallbacks as an object and grew
claim, the name for that ground, plus awatchSpentEntry(claim, reopen)for a closed layer waiting to be recognized.A Back-closed guard parks instead of dropping, a traversal re-entering its
spent entry asks the layer to reopen, and the guard re-arms on that entry in
place. A layer that passes neither option behaves exactly as before. A layer
that closed gave its ground up on purpose and nothing reopens from it —
Forward never undoes a dismissal the user made deliberately.
guardBackNavigation(@dunky.dev/dom-dialog) now returns{ sync, release }rather than a bare disposer: the guard outlives the openstate — that is the whole point of the Forward watch — so a host reports
every change through
sync(open)and ends the episode withrelease().Whether a close parks the registration or releases it stays a DOM-layer
decision, made once for every substrate.
One web-mechanics caveat, spec'd in the navigation util and both DOM
bindings: a controlled dialog's Back-close is completed by the consumer
rather than by the press, so its entry is consumed and Forward has nothing to
re-enter.
#46
5a58c2dThanks @ivanbanov! - Rename@dunky.dev/dom-navigationto@dunky.dev/browser-navigation.The util guards the browser's session history — Back, Forward, reload — and
never touches the DOM, so the old name pointed at the wrong layer. The API is
unchanged; only the package name moves:
@dunky.dev/dom-navigationwill receive no further releases.Patch Changes
#39
a33e149Thanks @ivanbanov! - Fix: releasing a whole guarded stack in one turn (close-all, a route change,an unmounting subtree) only consumed the topmost guard's entry — each entry
beneath stayed behind and silently swallowed a later browser Back.
Release order doesn't matter, and an entry genuinely buried under later
in-app navigation is still left alone.
#39
8ae32b4Thanks @ivanbanov! - TwointerceptBackNavigationhardenings:single pops — instead of one
history.go(-n)jump. Entries below thecurrent one are opaque, so a multi-step jump could cross history entries
the app planted itself; the chain stops at the first entry that isn't the
guard's to spend. A released entry buried beneath a live layer is also no
longer able to swallow a Back: the press that surfaces it unwinds the live
layer and consumes the dead entry in one go.
onBackthat throws now counts as a decline: the guard re-arms so thenext Back still reaches the layer, and the error propagates instead of
aborting the unwind in an inconsistent state.
#48
979c3c7Thanks @ivanbanov! - Fix twointerceptBackNavigationbugs around releases:shared
popstatelistener: the first release's idle check could detach itwhile the second release's self-caused pop was still in flight, leaving
that pop uncounted — the next guard's first Back press was then misread as
self-caused and its
onBacknever fired.onBack(a legal use of thepublic API) no longer evicts the guard beneath it: the handler now removes
the answering guard by identity instead of positionally, so lower layers
stay armed and keep their history entries.
@dunky.dev/dom-overlay@0.2.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
Patch Changes
#48
c35d1abThanks @ivanbanov! - Two fixes to how containment and the exit window treat pre-existing markup:aria-hidden="false"are now hidden behind a modal layerlike any other, and the authored value is restored on undo.
"false"asserts visible — the opposite of author-hidden — so the previous skip left
such elements exposed to assistive tech behind an open modal. Only a truthy
aria-hidden(orinert) still counts as the author's own hiding.hideExitingLayerno longer inerts<html>when the supplied boundary isnot an ancestor of the content. A stale or mismatched boundary used to
exhaust the ancestor walk at the document root and take the whole page out
for the exit window; the hide now falls back to the content itself.
#39
4698e0cThanks @ivanbanov! - Assistive-tech containment no longer lapses while a non-modal layer is openabove a modal one.
Containment now follows the topmost modal layer rather than the topmost
layer. The ordinary layers — a select menu, a combobox list, a tooltip, a
context menu — are non-modal and live inside dialogs; opening one used to
release the dialog's containment, leaving the page behind reachable by
pointer, keyboard, and screen reader for exactly as long as someone was
interacting with the menu. The layers stacked above the modal one are held
out of the hiding — they portal to the body as siblings of the dialog, so
without the exception the containment would inert the very layer the user is
in. Topmost keeps its meaning: a non-modal layer above still owns Escape and
the focus trap; only containment stays put.
To support this, the agnostic stack gains a public
ordered()methodreturning every layer topmost first — the host needs to look past the top of
the stack, while modality stays a host concept:
Updated dependencies [
ffa4fad,4698e0c]:@dunky.dev/react-dialog@0.4.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
#39
6b51d8dThanks @ivanbanov! -closeOnBackis now symmetric: the browser's Forward reopens what Backclosed. The history entry a Back press spends survives in the forward stack
and keeps marking the dialog's open ground — traversing forward into it
reopens the dialog, guarded again for the next Back. Reopening through the
trigger instead plants a fresh entry, exactly like navigating after a Back.
No new setting: back-close and forward-reopen are one behavior, so the
existing
closeOnBackgates both. Both DOM substrates get it — React andSolid — from the same code.
The reopen follows the shared dismissal contract — a new
onForwardNavigationcallback fires first andpreventDefault()vetoes,and a controlled dialog only records the intent:
A nested dialog comes back too. Closing the layer it was opened from unmounts
it — machine and all — so the ground it lost to a Back press has no owner left
to reopen it. It reopens anyway: the ground belongs to the dialog's place in
the stack rather than to the instance that planted it, so the dialog that
comes back with its parent recognizes it. Two dialogs at the same place can't
be told apart, and then neither reopens. The same recognition survives a
reload, so a traversal back into that ground reopens the dialog even after the
page went away.
Under the hood,
interceptBackNavigation(onBack, options?)takes its optionalcallbacks as an object and grew
claim, the name for that ground, plus awatchSpentEntry(claim, reopen)for a closed layer waiting to be recognized.A Back-closed guard parks instead of dropping, a traversal re-entering its
spent entry asks the layer to reopen, and the guard re-arms on that entry in
place. A layer that passes neither option behaves exactly as before. A layer
that closed gave its ground up on purpose and nothing reopens from it —
Forward never undoes a dismissal the user made deliberately.
guardBackNavigation(@dunky.dev/dom-dialog) now returns{ sync, release }rather than a bare disposer: the guard outlives the openstate — that is the whole point of the Forward watch — so a host reports
every change through
sync(open)and ends the episode withrelease().Whether a close parks the registration or releases it stays a DOM-layer
decision, made once for every substrate.
One web-mechanics caveat, spec'd in the navigation util and both DOM
bindings: a controlled dialog's Back-close is completed by the consumer
rather than by the press, so its entry is consumed and Forward has nothing to
re-enter.
Patch Changes
ffa4fad,c35d1ab,6b51d8d,5a58c2d,4208569]:@dunky.dev/solid-dialog@0.2.0
Minor Changes
#39
ffa4fadThanks @ivanbanov! -escapeScopenow exists. It was documented in the dialog specs — one layer perEscape by default, or the whole stack — but no package implemented it, so
passing it did nothing.
Only the dialog that receives the Escape gates and vetoes it: its
closeOnEscapeandonEscapeKeyDowndecide, exactly as before. Once allowed,the layers beneath receive a plain close — their own dismissal settings are not
consulted again — unwinding top-down, so focus lands where it was before the
bottom-most dialog opened. A vetoed Escape leaves the whole stack standing.
The mechanics are shared rather than per-dialog: the layer stack gained
below(id)(@dunky.dev/overlay) andlayersBelow(id)plus an optionalLayer.dismiss(@dunky.dev/dom-overlay), so any overlay family can offer astack-scoped dismissal on the same stack. A layer that registers no
dismissopts out and stays open, which is what keeps a stack that mixes primitives from
being closed out from under them.
The specs also described a stack-scoped Close press; nothing implements that,
so the claim is removed rather than left standing.
#39
6b51d8dThanks @ivanbanov! -closeOnBackis now symmetric: the browser's Forward reopens what Backclosed. The history entry a Back press spends survives in the forward stack
and keeps marking the dialog's open ground — traversing forward into it
reopens the dialog, guarded again for the next Back. Reopening through the
trigger instead plants a fresh entry, exactly like navigating after a Back.
No new setting: back-close and forward-reopen are one behavior, so the
existing
closeOnBackgates both. Both DOM substrates get it — React andSolid — from the same code.
The reopen follows the shared dismissal contract — a new
onForwardNavigationcallback fires first andpreventDefault()vetoes,and a controlled dialog only records the intent:
A nested dialog comes back too. Closing the layer it was opened from unmounts
it — machine and all — so the ground it lost to a Back press has no owner left
to reopen it. It reopens anyway: the ground belongs to the dialog's place in
the stack rather than to the instance that planted it, so the dialog that
comes back with its parent recognizes it. Two dialogs at the same place can't
be told apart, and then neither reopens. The same recognition survives a
reload, so a traversal back into that ground reopens the dialog even after the
page went away.
Under the hood,
interceptBackNavigation(onBack, options?)takes its optionalcallbacks as an object and grew
claim, the name for that ground, plus awatchSpentEntry(claim, reopen)for a closed layer waiting to be recognized.A Back-closed guard parks instead of dropping, a traversal re-entering its
spent entry asks the layer to reopen, and the guard re-arms on that entry in
place. A layer that passes neither option behaves exactly as before. A layer
that closed gave its ground up on purpose and nothing reopens from it —
Forward never undoes a dismissal the user made deliberately.
guardBackNavigation(@dunky.dev/dom-dialog) now returns{ sync, release }rather than a bare disposer: the guard outlives the openstate — that is the whole point of the Forward watch — so a host reports
every change through
sync(open)and ends the episode withrelease().Whether a close parks the registration or releases it stays a DOM-layer
decision, made once for every substrate.
One web-mechanics caveat, spec'd in the navigation util and both DOM
bindings: a controlled dialog's Back-close is completed by the consumer
rather than by the press, so its entry is consumed and Forward has nothing to
re-enter.
Patch Changes
ffa4fad,c35d1ab,6b51d8d,5a58c2d,4208569]:@dunky.dev/dom-focus-trap@0.1.2
Patch Changes
#39
560d539Thanks @ivanbanov! - Two fixes to which elements the trap's Tab cycle visits:Element.checkVisibility(). The API is recent (Chrome/Edge 105+,Firefox 106+, Safari 17.4+), and the trap resolves focusables after the Tab
keydown's
preventDefault()— on a browser without it, the resulting throwleft Tab dead entirely. The walk checks the same conditions (
hiddenattribute,
visibility: hidden,display: noneon the element or anancestor) and works everywhere.
iframeanddetails > summarynow participate in the cycle. Browserstab to both, but the trap — which steps focus itself — skipped them, making
them unreachable by keyboard while trapped. Only a details' first summary is
matched, since that is the disclosure widget browsers focus.
#48
6ed64a2Thanks @ivanbanov! - Make the trap's Tab cycle match what a browser would actually focus.Three fixes, all consumer-visible:
listener moved from the container to the document (capture phase), so a Tab
pressed while focus is still outside — on the trigger, or on
body— wrapsinto the cycle at the edge instead of following native tab order out of the
trap. Initial focus on open remains the caller's job.
hiddenattribute,display: none(own or ancestor), orvisibility: hiddenare filtered out. Focusing a non-rendered element is ano-op, so a hidden element in the cycle used to stall the trap on it.
pattern, the stop is the checked radio, else the group's first; groups are
scoped by name and form owner. The trap steps focus itself, so it now
reproduces the browser's grouping instead of visiting every radio.
@dunky.dev/dom-scroll-lock@0.1.2
Patch Changes
#48
4208569Thanks @ivanbanov! - TwolockScrollfixes:the target's computed padding instead of assigned over it. Previously the
inline longhand won the cascade and erased any
padding-inline-end/padding-block-endthe target already had (inline or from a stylesheet),shifting layout the other way — the lock must not shift layout in either
direction.
style.setPropertyinstead ofbranching per value: a saved
''(originally unset) removes thedeclaration per CSSOM, so the target returns to exactly what the first
holder saw.
#39
9d93cfcThanks @ivanbanov! -lockScrollnow saves, hides, and restoresoverflowper axis(
overflow-x/overflow-y), never via the shorthand. Per CSSOM theoverflowshorthand serializes back to''unless both longhands are set,so a container that declares its scrolling on one axis only —
— saved as "unset"; release then removed the consumer's own declaration and
the container stopped scrolling permanently. Restore now returns the inline
style to exactly what the first holder saw, as the contract promises.
@dunky.dev/native-dialog@0.1.2
Patch Changes
ffa4fad,6b51d8d]:@dunky.dev/react-use-focus-trap@0.1.2
Patch Changes
560d539,6ed64a2]:@dunky.dev/react-use-scroll-lock@0.1.2
Patch Changes
#48
4208569Thanks @ivanbanov! -useScrollLocknow treats anulltarget as "no target yet" and locksnothing. Previously
nullcollapsed into "the page body", so passing anot-yet-resolved element (e.g.
ref.currenton the first run) locked thepage instead of the intended container — and never corrected itself. An
omitted target still means the page body.
Pass the element through something reactive so the lock engages once the
node resolves — in React hold it in state (a ref populating doesn't
re-render), in Solid pass a signal-backed element (a plain
refread isnot reactive):
Updated dependencies [
4208569,9d93cfc]:@dunky.dev/solid-use-focus-trap@0.1.1
Patch Changes
560d539,6ed64a2]:@dunky.dev/solid-use-scroll-lock@0.1.1
Patch Changes
#48
4208569Thanks @ivanbanov! -useScrollLocknow treats anulltarget as "no target yet" and locksnothing. Previously
nullcollapsed into "the page body", so passing anot-yet-resolved element (e.g.
ref.currenton the first run) locked thepage instead of the intended container — and never corrected itself. An
omitted target still means the page body.
Pass the element through something reactive so the lock engages once the
node resolves — in React hold it in state (a ref populating doesn't
re-render), in Solid pass a signal-backed element (a plain
refread isnot reactive):
Updated dependencies [
4208569,9d93cfc]: