@excom/dismiss-watcher 0.1.0

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.
Files changed (33) hide show
  1. package/.rush/temp/chunked-rush-logs/dismiss-watcher.apply-exports.chunks.jsonl +1 -0
  2. package/.rush/temp/chunked-rush-logs/dismiss-watcher.build_docs.chunks.jsonl +1 -0
  3. package/.rush/temp/chunked-rush-logs/dismiss-watcher.build_package-metas.chunks.jsonl +1 -0
  4. package/.rush/temp/operation/apply-exports/all.log +1 -0
  5. package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
  6. package/.rush/temp/operation/apply-exports/state.json +3 -0
  7. package/.rush/temp/operation/build_docs/all.log +1 -0
  8. package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
  9. package/.rush/temp/operation/build_docs/state.json +3 -0
  10. package/.rush/temp/operation/build_package-metas/all.log +1 -0
  11. package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
  12. package/.rush/temp/operation/build_package-metas/state.json +3 -0
  13. package/.rush/temp/shrinkwrap-deps.json +3 -0
  14. package/config/rig.json +6 -0
  15. package/dismiss-watcher.ts +209 -0
  16. package/index.ts +21 -0
  17. package/package.json +48 -0
  18. package/rush-logs/dismiss-watcher.apply-exports.cache.log +1 -0
  19. package/rush-logs/dismiss-watcher.apply-exports.log +1 -0
  20. package/rush-logs/dismiss-watcher.build_docs.cache.log +1 -0
  21. package/rush-logs/dismiss-watcher.build_docs.log +1 -0
  22. package/rush-logs/dismiss-watcher.build_package-metas.cache.log +1 -0
  23. package/rush-logs/dismiss-watcher.build_package-metas.log +1 -0
  24. package/support/custom-elements.json +180 -0
  25. package/support/demos/drawer.html +19 -0
  26. package/support/demos/simple.html +24 -0
  27. package/support/dist-docs/dismiss-watcher.md +176 -0
  28. package/support/docs/README.md +62 -0
  29. package/support/package-meta.json +106 -0
  30. package/support/tests/dismiss-watcher.test.ts +370 -0
  31. package/support/tests/drawer.view.test.ts +71 -0
  32. package/support/tests/simple.view.test.ts +57 -0
  33. package/tsconfig.json +5 -0
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
@@ -0,0 +1 @@
1
+ Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: cd \"$RUSH_PROJECT_FOLDER\" && node ../heft-rig/scripts/apply-exports.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 37.36495500000001
3
+ }
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 48.852697000000035
3
+ }
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
@@ -0,0 +1 @@
1
+ {"kind":"O","text":"Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs \n"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "nonCachedDurationMs": 105.63776599999983
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "../../packages/dismiss-watcher": "../../packages/dismiss-watcher:crnI8zrhGnIZQxhLw4BKNf1dqfZ8PVcoMDfa7J8QXek=:"
3
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
3
+ "rigPackageName": "@excom/heft-rig",
4
+ "rigProfile": "default"
5
+ }
6
+
@@ -0,0 +1,209 @@
1
+ import { CloseWatcher } from "@excom/kit-shims";
2
+ import { selectOne } from "@excom/kit-utils";
3
+ import {
4
+ ConstructorType,
5
+ Neutron,
6
+ TEvent,
7
+ TokenList,
8
+ } from "@excom/neutron";
9
+
10
+ export type DismissWatcherReason = "escape" | "outside-click";
11
+
12
+ export type DismissWatcherDismissEvent = TEvent & {
13
+ type: "dismiss-watcher-dismiss";
14
+ detail: { reason: DismissWatcherReason };
15
+ };
16
+
17
+ const DISMISS_EVENT = "dismiss-watcher-dismiss";
18
+ const OUTSIDE_EVENT = "mouseup";
19
+
20
+ /**
21
+ * Dismissal-request Adapter for drawers, menus, dialogs and popovers. While
22
+ * `is-active` it watches for Escape / the platform back gesture (through a
23
+ * `CloseWatcher`) and for a `mouseup` outside its target, then fires
24
+ * `dismiss-watcher-dismiss`. The default action invokes each `command-name`
25
+ * (`--close`) and dispatches each `fire-event` name at the target;
26
+ * `preventDefault()` keeps the panel open. Renders nothing — drop it inside
27
+ * the element being dismissed, or point `target-ref` at it.
28
+ *
29
+ * @summary Escape / back-gesture and outside-click dismissal for any panel.
30
+ *
31
+ * @fires dismiss-watcher-dismiss - A dismissal was requested; `detail.reason`
32
+ * is `"escape"` or `"outside-click"`. Default action: invoke each
33
+ * `command-name` on the target and dispatch each `fire-event` name at it
34
+ * as a bubbling `CustomEvent`. `preventDefault()` skips both.
35
+ * @type DismissWatcherDismissEvent
36
+ */
37
+ export const DismissWatcher = Neutron({
38
+ tag: "dismiss-watcher",
39
+ props: {
40
+ /**
41
+ * @option
42
+ * @state
43
+ * Watchers are live while set. Gate it from Quark on the panel's open
44
+ * state, and write the inverse rule.
45
+ */
46
+ isActive: Boolean,
47
+ /**
48
+ * @option
49
+ * Watch Escape / the back gesture through a `CloseWatcher`. When neither
50
+ * `watch-*` attribute is present both watchers are on.
51
+ */
52
+ watchEscape: Boolean,
53
+ /**
54
+ * @option
55
+ * Watch for a `mouseup` on the document outside the target. When neither
56
+ * `watch-*` attribute is present both watchers are on.
57
+ */
58
+ watchOutsideClick: Boolean,
59
+ /**
60
+ * @option
61
+ * Selector for the element being dismissed, `:scope`-relative
62
+ * (`:scope ~ nav`). Unset = the parent element.
63
+ */
64
+ targetRef: String,
65
+ /**
66
+ * @option
67
+ * Commands invoked on the target as the default action of
68
+ * `dismiss-watcher-dismiss` — `--close` for a `<content-drawer>`, or any
69
+ * `--verb` the panel handles.
70
+ * @values <command>…
71
+ */
72
+ commandName: TokenList,
73
+ /**
74
+ * @option
75
+ * Event names dispatched at the target (bubbling `CustomEvent`s) as the
76
+ * default action of `dismiss-watcher-dismiss`, for panels driven by
77
+ * events rather than commands (`menu-close`).
78
+ */
79
+ fireEvent: TokenList,
80
+ // private state
81
+ _closeWatcher: Object as unknown as ConstructorType<CloseWatcher>,
82
+ },
83
+ })
84
+ .defineMethods({
85
+ _handleOutsideMouseup: (element, e: MouseEvent) => {
86
+ const target = resolveTarget(element);
87
+ if (!target || !(e.target instanceof Node) || target.contains(e.target)) {
88
+ return;
89
+ }
90
+ return {
91
+ emit: [DISMISS_EVENT, { detail: { reason: "outside-click" } }],
92
+ };
93
+ },
94
+ _handleClose: () => [
95
+ /* CloseWatcher deactivates after `close`: drop it and re-arm before
96
+ emitting, so a cancelled dismissal (`preventDefault()`) keeps Escape. */
97
+ { _closeWatcher: null },
98
+ { _apply: [] },
99
+ { emit: [DISMISS_EVENT, { detail: { reason: "escape" } }] },
100
+ ],
101
+ })
102
+ // Second `defineMethods` so the handlers above are typed on the element
103
+ .defineMethods({
104
+ _apply: ({
105
+ watchEscape,
106
+ watchOutsideClick,
107
+ _closeWatcher,
108
+ _handleClose,
109
+ _handleOutsideMouseup,
110
+ }) => {
111
+ // Neither `watch-*` set → both
112
+ const wantsEscape = !!watchEscape || !watchOutsideClick;
113
+ const wantsOutsideClick = !!watchOutsideClick || !watchEscape;
114
+ return [
115
+ wantsOutsideClick
116
+ ? {
117
+ addListener: [
118
+ OUTSIDE_EVENT,
119
+ _handleOutsideMouseup,
120
+ { target: document },
121
+ ],
122
+ }
123
+ : {
124
+ removeListener: [
125
+ OUTSIDE_EVENT,
126
+ _handleOutsideMouseup,
127
+ { target: document },
128
+ ],
129
+ },
130
+ wantsEscape
131
+ ? !_closeWatcher && {
132
+ _closeWatcher: createCloseWatcher(_handleClose),
133
+ }
134
+ : !!_closeWatcher && {
135
+ _closeWatcher: destroyCloseWatcher(_closeWatcher, _handleClose),
136
+ },
137
+ ].filter(Boolean);
138
+ },
139
+ _teardown: ({ _closeWatcher, _handleClose, _handleOutsideMouseup }) =>
140
+ [
141
+ {
142
+ removeListener: [
143
+ OUTSIDE_EVENT,
144
+ _handleOutsideMouseup,
145
+ { target: document },
146
+ ],
147
+ },
148
+ !!_closeWatcher && {
149
+ _closeWatcher: destroyCloseWatcher(_closeWatcher, _handleClose),
150
+ },
151
+ ].filter(Boolean),
152
+ })
153
+ .onPropSet("isActive", () => ({ _apply: [] }))
154
+ .onPropUnset("isActive", () => ({ _teardown: [] }))
155
+ .onPropChanged(
156
+ ["watchEscape", "watchOutsideClick", "targetRef"],
157
+ ({ isActive }) => !!isActive && { _apply: [] }
158
+ )
159
+ .onConnected(
160
+ ({ wasMounted, isActive, isMoving }) =>
161
+ // Real reconnect rebuilds; first mount is the prop flush
162
+ wasMounted && !!isActive && !isMoving && { _apply: [] }
163
+ )
164
+ .onDisconnected(
165
+ ({ isMoving }) =>
166
+ // Neutron restores tracked listeners on a move; keep the watcher too
167
+ !isMoving && { _teardown: [] }
168
+ )
169
+ .onEventDefault(DISMISS_EVENT, (element) => {
170
+ const target = resolveTarget(element);
171
+ const commands = element.commandName || [];
172
+ const names = element.fireEvent || [];
173
+ return (
174
+ !!target && [
175
+ commands.length > 0 && {
176
+ commands: commands.map((name) => [name, { target }]),
177
+ },
178
+ names.length > 0 && {
179
+ emits: names.map((type) => [type, { target }]),
180
+ },
181
+ ]
182
+ );
183
+ });
184
+
185
+ /** `target-ref`, `:scope`-relative to the watcher; default = parent. */
186
+ function resolveTarget(
187
+ element: HTMLElement & { targetRef?: string | null }
188
+ ): HTMLElement | null {
189
+ return element.targetRef
190
+ ? selectOne(element.targetRef, { scope: element })
191
+ : element.parentElement;
192
+ }
193
+
194
+ function createCloseWatcher(onClose: EventListener) {
195
+ const watcher = new CloseWatcher();
196
+ watcher.addEventListener("close", onClose);
197
+ return watcher;
198
+ }
199
+
200
+ function destroyCloseWatcher(
201
+ watcher: CloseWatcher | null | undefined,
202
+ onClose: EventListener
203
+ ) {
204
+ if (watcher) {
205
+ watcher.removeEventListener("close", onClose);
206
+ watcher.destroy();
207
+ }
208
+ return null;
209
+ }
package/index.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { DismissWatcher } from "./dismiss-watcher";
2
+
3
+ DismissWatcher.define();
4
+
5
+ export { DismissWatcher };
6
+ export type {
7
+ DismissWatcherDismissEvent,
8
+ DismissWatcherReason,
9
+ } from "./dismiss-watcher";
10
+
11
+ type T_HTMLDismissWatcherElement = typeof DismissWatcher.CustomElement;
12
+ declare global {
13
+ interface HTMLDismissWatcherElement extends T_HTMLDismissWatcherElement {}
14
+ interface Window {
15
+ HTMLDismissWatcherElement: HTMLDismissWatcherElement;
16
+ }
17
+ interface HTMLElementTagNameMap {
18
+ "dismiss-watcher": HTMLDismissWatcherElement;
19
+ }
20
+ }
21
+ export type { HTMLDismissWatcherElement };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@excom/dismiss-watcher",
3
+ "version": "0.1.0",
4
+ "description": "<dismiss-watcher> custom element",
5
+ "license": "MIT",
6
+ "engines": {
7
+ "node": ">=24.13.0"
8
+ },
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@excom/kit-utils": "^0.1.0",
12
+ "@excom/neutron": "^0.1.0",
13
+ "@excom/kit-shims": "^0.1.0"
14
+ },
15
+ "peerDependencies": {},
16
+ "devDependencies": {
17
+ "@excom/content-drawer": "^0.1.0",
18
+ "@excom/heft-rig": "^0.1.0",
19
+ "@excom/quark": "^0.1.0",
20
+ "@excom/event-handler": "^0.1.0",
21
+ "@excom/quark-sheet": "^0.1.0"
22
+ },
23
+ "repository": {
24
+ "url": "excom-dev/nucleus",
25
+ "directory": "packages/dismiss-watcher"
26
+ },
27
+ "homepage": "https://github.com/excom-dev/nucleus/tree/main/packages/dismiss-watcher/support/docs/README.md",
28
+ "bugs": "https://github.com/excom-dev/nucleus/issues",
29
+ "keywords": [
30
+ "dismiss-watcher",
31
+ "neutron",
32
+ "custom-elements"
33
+ ],
34
+ "excom": {
35
+ "packageType": "kit-element"
36
+ },
37
+ "scripts": {
38
+ "build": "node node_modules/@excom/heft-rig/scripts/vite-build.mjs",
39
+ "build:watch": "node node_modules/@excom/heft-rig/scripts/vite-build-watch.mjs",
40
+ "format": "node node_modules/@excom/heft-rig/scripts/format.mjs",
41
+ "test": "node node_modules/@excom/heft-rig/scripts/vitest.mjs",
42
+ "coverage": "node node_modules/@excom/heft-rig/scripts/coverage.mjs",
43
+ "dev": "node node_modules/@excom/heft-rig/scripts/vite-dev.mjs",
44
+ "preview": "node node_modules/@excom/heft-rig/scripts/vite-preview.mjs",
45
+ "build:package-metas": "node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs",
46
+ "build:docs": "node node_modules/@excom/heft-rig/scripts/build-docs.mjs"
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ Caching has been disabled for this project's "apply-exports" command.
@@ -0,0 +1 @@
1
+ Invoking: cd "$RUSH_PROJECT_FOLDER" && node ../heft-rig/scripts/apply-exports.mjs
@@ -0,0 +1 @@
1
+ This project does not define the caching behavior of the "build:docs" command, so caching has been disabled.
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-docs.mjs
@@ -0,0 +1 @@
1
+ This project does not define the caching behavior of the "build:package-metas" command, so caching has been disabled.
@@ -0,0 +1 @@
1
+ Invoking: node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs
@@ -0,0 +1,180 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "modules": [
4
+ {
5
+ "kind": "javascript-module",
6
+ "path": "dismiss-watcher.ts",
7
+ "declarations": [
8
+ {
9
+ "kind": "class",
10
+ "name": "DismissWatcher",
11
+ "customElement": true,
12
+ "tagName": "dismiss-watcher",
13
+ "summary": "Escape / back-gesture and outside-click dismissal for any panel.",
14
+ "description": "Dismissal-request Adapter for drawers, menus, dialogs and popovers. While `is-active` it watches for Escape / the platform back gesture (through a `CloseWatcher`) and for a `mouseup` outside its target, then fires `dismiss-watcher-dismiss`. The default action invokes each `command-name` (`--close`) and dispatches each `fire-event` name at the target; `preventDefault()` keeps the panel open. Renders nothing — drop it inside the element being dismissed, or point `target-ref` at it.",
15
+ "attributes": [
16
+ {
17
+ "name": "is-active",
18
+ "type": {
19
+ "text": "boolean"
20
+ },
21
+ "description": "Watchers are live while set. Gate it from Quark on the panel's open state, and write the inverse rule.",
22
+ "fieldName": "isActive"
23
+ },
24
+ {
25
+ "name": "watch-escape",
26
+ "type": {
27
+ "text": "boolean"
28
+ },
29
+ "description": "Watch Escape / the back gesture through a `CloseWatcher`. When neither `watch-*` attribute is present both watchers are on.",
30
+ "fieldName": "watchEscape"
31
+ },
32
+ {
33
+ "name": "watch-outside-click",
34
+ "type": {
35
+ "text": "boolean"
36
+ },
37
+ "description": "Watch for a `mouseup` on the document outside the target. When neither `watch-*` attribute is present both watchers are on.",
38
+ "fieldName": "watchOutsideClick"
39
+ },
40
+ {
41
+ "name": "target-ref",
42
+ "type": {
43
+ "text": "string"
44
+ },
45
+ "description": "Selector for the element being dismissed, `:scope`-relative (`:scope ~ nav`). Unset = the parent element.",
46
+ "fieldName": "targetRef"
47
+ },
48
+ {
49
+ "name": "command-name",
50
+ "type": {
51
+ "text": "tokenlist"
52
+ },
53
+ "description": "Commands invoked on the target as the default action of `dismiss-watcher-dismiss` — `--close` for a `<content-drawer>`, or any `--verb` the panel handles.",
54
+ "fieldName": "commandName",
55
+ "values": [
56
+ "<command>…"
57
+ ]
58
+ },
59
+ {
60
+ "name": "fire-event",
61
+ "type": {
62
+ "text": "tokenlist"
63
+ },
64
+ "description": "Event names dispatched at the target (bubbling `CustomEvent`s) as the default action of `dismiss-watcher-dismiss`, for panels driven by events rather than commands (`menu-close`).",
65
+ "fieldName": "fireEvent"
66
+ }
67
+ ],
68
+ "members": [
69
+ {
70
+ "kind": "field",
71
+ "name": "isActive",
72
+ "type": {
73
+ "text": "boolean"
74
+ },
75
+ "privacy": "public",
76
+ "readonly": false,
77
+ "description": "Watchers are live while set. Gate it from Quark on the panel's open state, and write the inverse rule.",
78
+ "_neutron": {
79
+ "surface": "hybrid"
80
+ }
81
+ },
82
+ {
83
+ "kind": "field",
84
+ "name": "watchEscape",
85
+ "type": {
86
+ "text": "boolean"
87
+ },
88
+ "privacy": "public",
89
+ "readonly": false,
90
+ "description": "Watch Escape / the back gesture through a `CloseWatcher`. When neither `watch-*` attribute is present both watchers are on.",
91
+ "_neutron": {
92
+ "surface": "option"
93
+ }
94
+ },
95
+ {
96
+ "kind": "field",
97
+ "name": "watchOutsideClick",
98
+ "type": {
99
+ "text": "boolean"
100
+ },
101
+ "privacy": "public",
102
+ "readonly": false,
103
+ "description": "Watch for a `mouseup` on the document outside the target. When neither `watch-*` attribute is present both watchers are on.",
104
+ "_neutron": {
105
+ "surface": "option"
106
+ }
107
+ },
108
+ {
109
+ "kind": "field",
110
+ "name": "targetRef",
111
+ "type": {
112
+ "text": "string"
113
+ },
114
+ "privacy": "public",
115
+ "readonly": false,
116
+ "description": "Selector for the element being dismissed, `:scope`-relative (`:scope ~ nav`). Unset = the parent element.",
117
+ "_neutron": {
118
+ "surface": "option"
119
+ }
120
+ },
121
+ {
122
+ "kind": "field",
123
+ "name": "commandName",
124
+ "type": {
125
+ "text": "tokenlist"
126
+ },
127
+ "privacy": "public",
128
+ "readonly": false,
129
+ "description": "Commands invoked on the target as the default action of `dismiss-watcher-dismiss` — `--close` for a `<content-drawer>`, or any `--verb` the panel handles.",
130
+ "_neutron": {
131
+ "surface": "option"
132
+ }
133
+ },
134
+ {
135
+ "kind": "field",
136
+ "name": "fireEvent",
137
+ "type": {
138
+ "text": "tokenlist"
139
+ },
140
+ "privacy": "public",
141
+ "readonly": false,
142
+ "description": "Event names dispatched at the target (bubbling `CustomEvent`s) as the default action of `dismiss-watcher-dismiss`, for panels driven by events rather than commands (`menu-close`).",
143
+ "_neutron": {
144
+ "surface": "option"
145
+ }
146
+ }
147
+ ],
148
+ "events": [
149
+ {
150
+ "name": "dismiss-watcher-dismiss",
151
+ "description": "A dismissal was requested; `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.",
152
+ "type": {
153
+ "text": "DismissWatcherDismissEvent",
154
+ "expanded": "CustomEvent & { type: \"dismiss-watcher-dismiss\"; detail: { reason: \"escape\" | \"outside-click\" }; bubbles: true; cancelable: true; composed: true }"
155
+ }
156
+ }
157
+ ]
158
+ }
159
+ ],
160
+ "exports": [
161
+ {
162
+ "kind": "js",
163
+ "name": "DismissWatcher",
164
+ "declaration": {
165
+ "name": "DismissWatcher",
166
+ "module": "dismiss-watcher.ts"
167
+ }
168
+ },
169
+ {
170
+ "kind": "custom-element-definition",
171
+ "name": "dismiss-watcher",
172
+ "declaration": {
173
+ "name": "DismissWatcher",
174
+ "module": "dismiss-watcher.ts"
175
+ }
176
+ }
177
+ ]
178
+ }
179
+ ]
180
+ }
@@ -0,0 +1,19 @@
1
+ <section>
2
+ <quark-sheet>
3
+ :scope {
4
+ content-drawer[is-open] dismiss-watcher { is-active: ""; }
5
+ content-drawer:not([is-open]) dismiss-watcher { is-active: none; }
6
+ }
7
+ </quark-sheet>
8
+ <button type="button" command="--open" commandfor="demo-dismiss-drawer">
9
+ Open drawer
10
+ </button>
11
+ <content-drawer id="demo-dismiss-drawer">
12
+ <dismiss-watcher watch-escape watch-outside-click command-name="--close"></dismiss-watcher>
13
+ <header>
14
+ <h2>Drawer</h2>
15
+ </header>
16
+ <p>Press Escape or click outside to close.</p>
17
+ </content-drawer>
18
+ <event-handler class="tag-backdrop" role="presentation" target-ref="content-drawer:has(+ :scope)" command-name="--close"></event-handler>
19
+ </section>
@@ -0,0 +1,24 @@
1
+ <div>
2
+ <quark-sheet>
3
+ :scope {
4
+ @on menu-open { data-is-open: ""; }
5
+ @on dismiss-watcher-dismiss { data-is-open: none; }
6
+ &[data-is-open] dismiss-watcher { is-active: ""; }
7
+ &:not([data-is-open]) dismiss-watcher { is-active: none; }
8
+ }
9
+ </quark-sheet>
10
+ <style>
11
+ [data-demo-menu] { display: none; }
12
+ [data-is-open] > [data-demo-menu] { display: block; }
13
+ </style>
14
+ <event-handler role="button" fire-event="menu-open">Open menu</event-handler>
15
+ <nav data-demo-menu>
16
+ <dismiss-watcher></dismiss-watcher>
17
+ <ul>
18
+ <li><a href="#">Profile</a></li>
19
+ <li><a href="#">Settings</a></li>
20
+ <li><a href="#">Sign out</a></li>
21
+ </ul>
22
+ <p>Press Escape or click outside to close.</p>
23
+ </nav>
24
+ </div>