dismiss-watcher
One dismissal Adapter for drawers, menus, dialogs and popovers — Escape / back gesture and outside click, without each panel element owning the logic.
Features
- Escape / back gesture Through a
CloseWatcher(Android back, Escape) viawatch-escape - Outside click A
mouseupoutside the target viawatch-outside-click - One event
dismiss-watcher-dismisswithdetail.reason; cancel it withpreventDefault() - Default action
command-namecommands invoked on the target (--close), orfire-eventnames dispatched at it - Any target The parent by default, or
target-ref(:scope-relative) - Gated by State Live only while
is-active— set it from Quark on the panel's open state
Installation
This package is available in the
<script src="https://unpkg.com/@excom/kit-utils@0.3.0/dist/index.umd.min.js"></script>
<script src="https://unpkg.com/@excom/neutron@0.2.0/dist/index.umd.min.js"></script>
<script src="https://unpkg.com/@excom/dismiss-watcher@0.1.8/dist/index.umd.min.js"></script>npm install @excom/dismiss-watcher<!-- import path to `node_modules` will depend on your build setup -->
<script type="module" src="/node_modules/@excom/dismiss-watcher"></script>
<link rel="stylesheet" href="/node_modules/@excom/dismiss-watcher">import "@excom/dismiss-watcher";Peer dependencies (0)
Packages a consumer must install alongside this one. Workspace deps are bundled.
| Package | Version |
|---|---|
|
Usage
Drop it inside the element being dismissed, gate is-active on that element's open state, and either react to dismiss-watcher-dismiss or let command-name / fire-event close the panel for you. When neither watch-escape nor watch-outside-click is present, both watchers are on.
<nav>
<dismiss-watcher fire-event="menu-close"></dismiss-watcher>
…
</nav><nav>
<dismiss-watcher fire-event="menu-close"></dismiss-watcher>
…
</nav>:scope {
@on menu-open { data-is-open: ""; }
@on menu-close { data-is-open: none; }
&[data-is-open] dismiss-watcher { is-active: ""; }
&:not([data-is-open]) dismiss-watcher { is-active: none; }
}:scope {
@on menu-open { data-is-open: ""; }
@on menu-close { data-is-open: none; }
&[data-is-open] dismiss-watcher { is-active: ""; }
&:not([data-is-open]) dismiss-watcher { is-active: none; }
}Why a separate element: dismissal is the same request whether the panel is a drawer, a menu, a dialog or a popover. Panel elements keep their own state (is-open); this Adapter only asks them to close. It renders nothing, listens only while is-active, and tears down when unset or removed. Write the inverse rule for is-active — Quark rules do not revert.
dismiss-watcher-dismiss bubbles and is cancelable. detail.reason is "escape" / "outside-click". The default action invokes each command-name on the target (a command event, as a <button command commandfor> would) and dispatches each fire-event name at it as a bubbling CustomEvent; preventDefault() keeps the panel open (an unsaved-changes guard, for instance).
API Reference
Attributes
Role —option is configurable, state
is managed by the element (read-only), or hybrid which is both.
Provision
Thisprovision property lives on the DOM node.
Read / watch it with Quark’s prop("provision"), or listen
for the neutron-provision event from app JS.
Events
Type
command event (HTML Command API): from a
<button command commandfor>, an <event-handler
command-name>, or a CommandEvent.
Recognized Elements
Child or descendant elements are recognized by and relevant to its functionality.Styles
@custom-selector synonyms so custom elements can share
semantic styles. Element aliases match the host tag / .tag-* class; state
aliases match attributes (nested under the element alias).
dismiss-watcher
Attributes (6)
Role —option is configurable, state
is managed by the element (read-only), or hybrid which is both.
command-name
dismiss-watcher-dismiss — --close for a <content-drawer>, or any --verb the panel handles.
commandName
tokenlist
<command>…nullfire-event
CustomEvents) as the default action of dismiss-watcher-dismiss, for panels driven by events rather than commands (menu-close).
fireEvent
tokenlist
nulltarget-ref
:scope-relative (:scope ~ nav). Unset = the parent element.
targetRef
string
nullwatch-escape
CloseWatcher. When neither watch-* attribute is present both watchers are on.
watchEscape
boolean
falsewatch-outside-click
mouseup on the document outside the target. When neither watch-* attribute is present both watchers are on.
watchOutsideClick
boolean
falseis-active
isActive
boolean
falseProvision (0)
Thisprovision property lives on the DOM node.
Read / watch it with Quark’s prop("provision"), or listen
for the neutron-provision event from app JS.
Events (1)
e.preventDefault() is not
synchronously called on the event.
Type
dismiss-watcher-dismiss
detail.reason is "escape" or "outside-click". Default action: invoke each command-name on the target and dispatch each fire-event name at it as a bubbling CustomEvent. preventDefault() skips both.
Type
DismissWatcherDismissEvent
command event (HTML Command API): from a
<button command commandfor>, an <event-handler
command-name>, or a CommandEvent.
Recognized Elements (0)
Child or descendant elements are recognized by dismiss-watcher and relevant to its functionality.Styles (0)
all: revert-layer.
Valence.css ships this as .unstyled and .unstyled-all for the entire tree.
@custom-selector synonyms so custom elements can share
semantic styles. Element aliases match the host tag / .tag-* class; state
aliases match attributes (nested under the element alias).
Release notes (1)
0.1.1
- Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
Release notes
e.preventDefault() is not
synchronously called on the event.
all: revert-layer.
Valence.css ships this as .unstyled and .unstyled-all for the entire tree.
Examples
Menu panel
Both watchers on (neither watch-* set), target = the parent <nav>. The sheet opens on menu-open, closes on dismiss-watcher-dismiss, and gates is-active on data-is-open with its inverse rule.
Content drawer
First child of <content-drawer>, command-name="--close" — the drawer needs no dismissal logic of its own. is-active follows content-drawer[is-open].
Open with --open, not --toggle: an outside mouseup on the button closes the drawer first, then the button's click re-opens it. With --toggle the same click would close it again.