@excom/dialog-anchor 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.
- package/.rush/temp/chunked-rush-logs/dialog-anchor.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/dialog-anchor.build_docs.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/dialog-anchor.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_docs/all.log +1 -0
- package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_docs/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +5 -0
- package/dialog-anchor.css +1 -0
- package/dialog-anchor.ts +73 -0
- package/index.css +1 -0
- package/index.ts +17 -0
- package/package.json +44 -0
- package/rush-logs/dialog-anchor.apply-exports.cache.log +1 -0
- package/rush-logs/dialog-anchor.apply-exports.log +1 -0
- package/rush-logs/dialog-anchor.build_docs.cache.log +1 -0
- package/rush-logs/dialog-anchor.build_docs.log +1 -0
- package/rush-logs/dialog-anchor.build_package-metas.cache.log +1 -0
- package/rush-logs/dialog-anchor.build_package-metas.log +1 -0
- package/src/dialog-anchor.css +19 -0
- package/support/custom-elements.json +110 -0
- package/support/demos/auto-close.html +11 -0
- package/support/demos/is-modal.html +21 -0
- package/support/demos/simple.html +7 -0
- package/support/dist-docs/dialog-anchor.md +163 -0
- package/support/docs/INTERNAL.md +1 -0
- package/support/docs/README.md +58 -0
- package/support/package-meta.json +199 -0
- package/support/tests/auto-close.view.test.ts +31 -0
- package/support/tests/dialog-anchor.test.ts +102 -0
- package/support/tests/is-modal.view.test.ts +34 -0
- package/support/tests/simple.view.test.ts +31 -0
- 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 @@
|
|
|
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 @@
|
|
|
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"}
|
package/config/rig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./index.css";
|
package/dialog-anchor.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { selectOne } from "@excom/kit-utils";
|
|
2
|
+
import { ListenableElement } from "@excom/listenable-element";
|
|
3
|
+
import { Neutron } from "@excom/neutron";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Click target that opens or closes a `<dialog>` without any JavaScript.
|
|
7
|
+
* Wrap a button (or any clickable content) in `<dialog-anchor>` and point
|
|
8
|
+
* it at a `<dialog>` via `target-ref`, or let it find the nearest ancestor
|
|
9
|
+
* `<dialog>` automatically — the common case for a close button living
|
|
10
|
+
* inside the dialog it closes.
|
|
11
|
+
*
|
|
12
|
+
* By default it listens for `click`; set `listen-for` (from
|
|
13
|
+
* `ListenableElement`) to toggle on another event instead — e.g. auto-close
|
|
14
|
+
* a dialog when a nested `<super-form>` succeeds.
|
|
15
|
+
*
|
|
16
|
+
* @summary Open/close a `<dialog>` — by selector or nearest ancestor.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <dialog-anchor target-ref="#confirm" is-modal>
|
|
20
|
+
* <button>Delete</button>
|
|
21
|
+
* </dialog-anchor>
|
|
22
|
+
* <dialog id="confirm">...</dialog>
|
|
23
|
+
*/
|
|
24
|
+
export const DialogAnchor = Neutron.compose([
|
|
25
|
+
ListenableElement,
|
|
26
|
+
Neutron({
|
|
27
|
+
tag: "dialog-anchor",
|
|
28
|
+
props: {
|
|
29
|
+
/**
|
|
30
|
+
* @option
|
|
31
|
+
* CSS selector for the `<dialog>` to toggle. If omitted, the
|
|
32
|
+
* element toggles the nearest ancestor `<dialog>`.
|
|
33
|
+
* @values <CSS Selector>
|
|
34
|
+
*/
|
|
35
|
+
targetRef: String,
|
|
36
|
+
/**
|
|
37
|
+
* @option
|
|
38
|
+
* Open the dialog as a modal (blocks the rest of the page) instead
|
|
39
|
+
* of a non-modal popover.
|
|
40
|
+
*/
|
|
41
|
+
isModal: Boolean,
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
])
|
|
45
|
+
.defineMethods({
|
|
46
|
+
actionHandler: (element) => {
|
|
47
|
+
let dialog =
|
|
48
|
+
element.targetRef &&
|
|
49
|
+
selectOne(element.targetRef, {
|
|
50
|
+
scope: element,
|
|
51
|
+
});
|
|
52
|
+
if (!(dialog instanceof HTMLDialogElement)) {
|
|
53
|
+
dialog = element.closest("dialog");
|
|
54
|
+
}
|
|
55
|
+
if (dialog instanceof HTMLDialogElement) {
|
|
56
|
+
const isOpen = dialog.open;
|
|
57
|
+
const isModal = element.isModal;
|
|
58
|
+
if (isOpen) {
|
|
59
|
+
dialog.close();
|
|
60
|
+
} else {
|
|
61
|
+
dialog[isModal ? "showModal" : "show"]();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
.onConnected(
|
|
67
|
+
({ listenFor, listenForLifecycle, handleEvent, isMoving }) =>
|
|
68
|
+
!isMoving &&
|
|
69
|
+
!listenFor?.length &&
|
|
70
|
+
!listenForLifecycle?.length && {
|
|
71
|
+
addListener: ["click", handleEvent],
|
|
72
|
+
}
|
|
73
|
+
);
|
package/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "./src/dialog-anchor.css";
|
package/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DialogAnchor } from "./dialog-anchor";
|
|
2
|
+
|
|
3
|
+
DialogAnchor.define();
|
|
4
|
+
|
|
5
|
+
export { DialogAnchor };
|
|
6
|
+
|
|
7
|
+
type T_HTMLDialogAnchorElement = typeof DialogAnchor.CustomElement;
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLDialogAnchorElement extends T_HTMLDialogAnchorElement {}
|
|
10
|
+
interface Window {
|
|
11
|
+
HTMLDialogAnchorElement: HTMLDialogAnchorElement;
|
|
12
|
+
}
|
|
13
|
+
interface HTMLElementTagNameMap {
|
|
14
|
+
"dialog-anchor": HTMLDialogAnchorElement;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export type { HTMLDialogAnchorElement };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@excom/dialog-anchor",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "<dialog-anchor> custom element",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24.13.0"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@excom/listenable-element": "^0.1.0",
|
|
12
|
+
"@excom/neutron": "^0.1.0",
|
|
13
|
+
"@excom/kit-utils": "^0.1.0"
|
|
14
|
+
},
|
|
15
|
+
"peerDependencies": {},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@excom/heft-rig": "^0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"url": "excom-dev/nucleus",
|
|
21
|
+
"directory": "packages/dialog-anchor"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/excom-dev/nucleus/tree/main/packages/dialog-anchor/support/docs/README.md",
|
|
24
|
+
"bugs": "https://github.com/excom-dev/nucleus/issues",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"dialog-anchor",
|
|
27
|
+
"neutron",
|
|
28
|
+
"custom-elements"
|
|
29
|
+
],
|
|
30
|
+
"excom": {
|
|
31
|
+
"packageType": "kit-element"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "node node_modules/@excom/heft-rig/scripts/vite-build.mjs",
|
|
35
|
+
"build:watch": "node node_modules/@excom/heft-rig/scripts/vite-build-watch.mjs",
|
|
36
|
+
"format": "node node_modules/@excom/heft-rig/scripts/format.mjs",
|
|
37
|
+
"test": "node node_modules/@excom/heft-rig/scripts/vitest.mjs",
|
|
38
|
+
"coverage": "node node_modules/@excom/heft-rig/scripts/coverage.mjs",
|
|
39
|
+
"dev": "node node_modules/@excom/heft-rig/scripts/vite-dev.mjs",
|
|
40
|
+
"preview": "node node_modules/@excom/heft-rig/scripts/vite-preview.mjs",
|
|
41
|
+
"build:package-metas": "node node_modules/@excom/heft-rig/scripts/build-package-metas.mjs",
|
|
42
|
+
"build:docs": "node node_modules/@excom/heft-rig/scripts/build-docs.mjs"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -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,19 @@
|
|
|
1
|
+
@import "@excom/listenable-element/src/index.css";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Styles for `<dialog-anchor>`.
|
|
5
|
+
* @element dialog-anchor
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* Aliases */
|
|
9
|
+
@custom-selector :--dialog-anchor dialog-anchor, .tag-dialog-anchor;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Skip the pointer cursor from the listenable mixin.
|
|
13
|
+
* @cssclass unstyled
|
|
14
|
+
*/
|
|
15
|
+
@layer {
|
|
16
|
+
:--dialog-anchor:not(.unstyled) {
|
|
17
|
+
@mixin listenable-element;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "1.0.0",
|
|
3
|
+
"modules": [
|
|
4
|
+
{
|
|
5
|
+
"kind": "javascript-module",
|
|
6
|
+
"path": "dialog-anchor.ts",
|
|
7
|
+
"declarations": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "class",
|
|
10
|
+
"name": "DialogAnchor",
|
|
11
|
+
"customElement": true,
|
|
12
|
+
"tagName": "dialog-anchor",
|
|
13
|
+
"mixins": [
|
|
14
|
+
{
|
|
15
|
+
"name": "ListenableElement",
|
|
16
|
+
"package": "@excom/listenable-element"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"summary": "Open/close a `<dialog>` — by selector or nearest ancestor.",
|
|
20
|
+
"description": "Click target that opens or closes a `<dialog>` without any JavaScript. Wrap a button (or any clickable content) in `<dialog-anchor>` and point it at a `<dialog>` via `target-ref`, or let it find the nearest ancestor `<dialog>` automatically — the common case for a close button living inside the dialog it closes. By default it listens for `click`; set `listen-for` (from `ListenableElement`) to toggle on another event instead — e.g. auto-close a dialog when a nested `<super-form>` succeeds.",
|
|
21
|
+
"attributes": [
|
|
22
|
+
{
|
|
23
|
+
"name": "target-ref",
|
|
24
|
+
"type": {
|
|
25
|
+
"text": "string"
|
|
26
|
+
},
|
|
27
|
+
"description": "CSS selector for the `<dialog>` to toggle. If omitted, the element toggles the nearest ancestor `<dialog>`.",
|
|
28
|
+
"fieldName": "targetRef",
|
|
29
|
+
"values": [
|
|
30
|
+
"<CSS Selector>"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "is-modal",
|
|
35
|
+
"type": {
|
|
36
|
+
"text": "boolean"
|
|
37
|
+
},
|
|
38
|
+
"description": "Open the dialog as a modal (blocks the rest of the page) instead of a non-modal popover.",
|
|
39
|
+
"fieldName": "isModal"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"members": [
|
|
43
|
+
{
|
|
44
|
+
"kind": "field",
|
|
45
|
+
"name": "targetRef",
|
|
46
|
+
"type": {
|
|
47
|
+
"text": "string"
|
|
48
|
+
},
|
|
49
|
+
"privacy": "public",
|
|
50
|
+
"readonly": false,
|
|
51
|
+
"description": "CSS selector for the `<dialog>` to toggle. If omitted, the element toggles the nearest ancestor `<dialog>`.",
|
|
52
|
+
"_neutron": {
|
|
53
|
+
"surface": "option"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"kind": "field",
|
|
58
|
+
"name": "isModal",
|
|
59
|
+
"type": {
|
|
60
|
+
"text": "boolean"
|
|
61
|
+
},
|
|
62
|
+
"privacy": "public",
|
|
63
|
+
"readonly": false,
|
|
64
|
+
"description": "Open the dialog as a modal (blocks the rest of the page) instead of a non-modal popover.",
|
|
65
|
+
"_neutron": {
|
|
66
|
+
"surface": "option"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"_neutron": {
|
|
71
|
+
"cssClasses": [
|
|
72
|
+
{
|
|
73
|
+
"name": "unstyled",
|
|
74
|
+
"description": "Skip the pointer cursor from the listenable mixin."
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"cssAliases": [
|
|
78
|
+
{
|
|
79
|
+
"name": ":--dialog-anchor",
|
|
80
|
+
"selectors": [
|
|
81
|
+
"dialog-anchor",
|
|
82
|
+
".tag-dialog-anchor"
|
|
83
|
+
],
|
|
84
|
+
"kind": "element"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"exports": [
|
|
91
|
+
{
|
|
92
|
+
"kind": "js",
|
|
93
|
+
"name": "DialogAnchor",
|
|
94
|
+
"declaration": {
|
|
95
|
+
"name": "DialogAnchor",
|
|
96
|
+
"module": "dialog-anchor.ts"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"kind": "custom-element-definition",
|
|
101
|
+
"name": "dialog-anchor",
|
|
102
|
+
"declaration": {
|
|
103
|
+
"name": "DialogAnchor",
|
|
104
|
+
"module": "dialog-anchor.ts"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<dialog-anchor role="button" target-ref="#da-auto" is-modal>Open form</dialog-anchor>
|
|
3
|
+
<dialog id="da-auto">
|
|
4
|
+
<dialog-anchor listen-for="super-form-success">
|
|
5
|
+
<p>Simulating a form submit…</p>
|
|
6
|
+
<event-handler role="button" fire-event="super-form-success">
|
|
7
|
+
Submit
|
|
8
|
+
</event-handler>
|
|
9
|
+
</dialog-anchor>
|
|
10
|
+
</dialog>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<dialog-anchor role="button" target-ref="#da-modal" is-modal>
|
|
3
|
+
Open as modal
|
|
4
|
+
</dialog-anchor>
|
|
5
|
+
<dialog-anchor role="button" target-ref="#da-modal">
|
|
6
|
+
Open as non-modal
|
|
7
|
+
</dialog-anchor>
|
|
8
|
+
<dialog id="da-modal">
|
|
9
|
+
<article>
|
|
10
|
+
<header>
|
|
11
|
+
<dialog-anchor role="button" rel="prev"></dialog-anchor>
|
|
12
|
+
<h4>Modal dialogs block interaction with the rest of the page.</h4>
|
|
13
|
+
<p>This dialog is shown with Valence.css styling</p>
|
|
14
|
+
</header>
|
|
15
|
+
<p>Dialog content</p>
|
|
16
|
+
<footer>
|
|
17
|
+
Footer content
|
|
18
|
+
</footer>
|
|
19
|
+
</article>
|
|
20
|
+
</dialog>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# dialog-anchor
|
|
2
|
+
|
|
3
|
+
Open and close a native `<dialog>` — no JavaScript required.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
```html
|
|
7
|
+
<div>
|
|
8
|
+
<dialog-anchor role="button" target-ref="#da-simple" is-modal>Open dialog</dialog-anchor>
|
|
9
|
+
<dialog id="da-simple">
|
|
10
|
+
<p>A native, modal dialog.</p>
|
|
11
|
+
<dialog-anchor role="button">Close</dialog-anchor>
|
|
12
|
+
</dialog>
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **Click to toggle** Opens / closes a `<dialog>` on click
|
|
20
|
+
- **Target or fallback** Point at any `<dialog>` via `target-ref`, or let
|
|
21
|
+
it find the nearest ancestor automatically (great for close buttons)
|
|
22
|
+
- **Modal or non-modal** `is-modal` blocks the rest of the page; omit it
|
|
23
|
+
for a lightweight, dismissible popover
|
|
24
|
+
- **Any trigger event** Inherits `listen-for` to open/close on custom
|
|
25
|
+
events instead of `click`
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
`@excom/dialog-anchor` v0.1.0
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm add @excom/dialog-anchor
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @excom/dialog-anchor
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
yarn add @excom/dialog-anchor
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Import
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import "@excom/dialog-anchor";
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
@import "@excom/dialog-anchor/dialog-anchor.css";
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
Wrap a trigger in `<dialog-anchor>` and point it at a `<dialog>`. A
|
|
59
|
+
`<dialog-anchor>` with no `target-ref`, placed inside the `<dialog>` it
|
|
60
|
+
should close, needs no configuration at all.
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<dialog-anchor target-ref="#confirm" role="button">Delete</dialog-anchor>
|
|
64
|
+
<dialog id="confirm">
|
|
65
|
+
<p>Are you sure?</p>
|
|
66
|
+
<dialog-anchor role="button">Cancel</dialog-anchor>
|
|
67
|
+
</dialog>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### API Reference
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#### Attributes
|
|
74
|
+
|
|
75
|
+
| Name | Surface | Type | Default | Values | Description | Inherited from |
|
|
76
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
77
|
+
| `target-ref` | option | `string` | | `<CSS Selector>` | CSS selector for the `<dialog>` to toggle. If omitted, the element toggles the nearest ancestor `<dialog>`. | |
|
|
78
|
+
| `is-modal` | option | `boolean` | | | Open the dialog as a modal (blocks the rest of the page) instead of a non-modal popover. | |
|
|
79
|
+
| `host-ref` | option | `string` | | `<CSS Selector>` \| `"window"` \| `"document"` \| `"html"` \| `"body"` \| `"head"` | Listen on another element / `window` / `document` — e.g. Escape to dismiss a dialog from a global `keydown`. Defaults to `:scope`. Used with `listen-for`. Not compatible with `listen-for-lifecycle`. The selector MUST resolve when `host-ref` is set — it will not wait for a match to appear. | `@excom/listenable-element` |
|
|
80
|
+
| `listen-for` | option | `tokenlist` | | `<EventName>…` | Space-separated event names to listen for. Defaults to `click` when unset (and no lifecycle list is set). | `@excom/listenable-element` |
|
|
81
|
+
| `listen-for-lifecycle` | option | `tokenlist` | | `"connected"` \| `"disconnected"` \| `"adopted"` | Space-separated element lifecycles to handle. | `@excom/listenable-element` |
|
|
82
|
+
| `listen-once` | option | `boolean` | | | Handle each distinct event name / lifecycle at most once. | `@excom/listenable-element` |
|
|
83
|
+
| `selector-filter` | option | `string` | | `<CSS Selector>` | Only handle events whose `event.target` matches this CSS selector. Does not support `:scope` in the selector. | `@excom/listenable-element` |
|
|
84
|
+
| `keycode-filter` | option | `tokenlist` | | `<key` \| `mod+key>…` | Space-separated key filters (OR). Join modifiers with `+` (AND, any order): `shift+k tab` → Shift+K or Tab. Modifiers: `shift`, `alt`, `ctrl`/`control`, `meta`. Case-insensitive. | `@excom/listenable-element` |
|
|
85
|
+
| `pathname-filter` | option | `tokenlist` | | `<pathname>…` | Only handle when `location.pathname` is one of these values — route-aware behaviors without a separate router element. | `@excom/listenable-element` |
|
|
86
|
+
| `prevent-default` | option | `boolean` | | | Call `preventDefault()` on matched events (ignored for lifecycles). | `@excom/listenable-element` |
|
|
87
|
+
| `stop-propagation` | option | `boolean` | | | Call `stopPropagation()` on matched events (ignored for lifecycles). | `@excom/listenable-element` |
|
|
88
|
+
| `stop-immediate-propagation` | option | `boolean` | | | Call `stopImmediatePropagation()` on matched events (ignored for lifecycles). | `@excom/listenable-element` |
|
|
89
|
+
| `vibrate-ms` | option | `number` | `"20 (when attribute is present with no value)"` | | Vibrate on handle (`navigator.vibrate`). Empty / `0` uses a 20ms pulse. | `@excom/listenable-element` |
|
|
90
|
+
| `delay-ms` | option | `number` | | | Delay handling by this many milliseconds. | `@excom/listenable-element` |
|
|
91
|
+
| `is-debounced` | option | `boolean` | | | With `delay-ms`, coalesce bursts into one trailing call (debounce). | `@excom/listenable-element` |
|
|
92
|
+
|
|
93
|
+
#### CSS Classes
|
|
94
|
+
|
|
95
|
+
| Name | Description |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `.unstyled` | Skip the pointer cursor from the listenable mixin. |
|
|
98
|
+
|
|
99
|
+
#### CSS Aliases
|
|
100
|
+
|
|
101
|
+
| Alias | Kind | Matches | Description |
|
|
102
|
+
| --- | --- | --- | --- |
|
|
103
|
+
| `:--dialog-anchor` | element | `dialog-anchor`, `.tag-dialog-anchor` | |
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### Examples
|
|
108
|
+
|
|
109
|
+
#### Modal dialog
|
|
110
|
+
|
|
111
|
+
`is-modal` opens the dialog as a modal, blocking interaction with the rest
|
|
112
|
+
of the page until it's closed (using native `::backdrop`). Without that attribute,
|
|
113
|
+
the dialog is opened without a backdrop.
|
|
114
|
+
|
|
115
|
+
If using Valence.css, setting `.absolute` on the `dialog` element will display it `absolute`
|
|
116
|
+
in the surrounding content (as opposed to fixed).
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<div>
|
|
121
|
+
<dialog-anchor role="button" target-ref="#da-modal" is-modal>
|
|
122
|
+
Open as modal
|
|
123
|
+
</dialog-anchor>
|
|
124
|
+
<dialog-anchor role="button" target-ref="#da-modal">
|
|
125
|
+
Open as non-modal
|
|
126
|
+
</dialog-anchor>
|
|
127
|
+
<dialog id="da-modal">
|
|
128
|
+
<article>
|
|
129
|
+
<header>
|
|
130
|
+
<dialog-anchor role="button" rel="prev"></dialog-anchor>
|
|
131
|
+
<h4>Modal dialogs block interaction with the rest of the page.</h4>
|
|
132
|
+
<p>This dialog is shown with Valence.css styling</p>
|
|
133
|
+
</header>
|
|
134
|
+
<p>Dialog content</p>
|
|
135
|
+
<footer>
|
|
136
|
+
Footer content
|
|
137
|
+
</footer>
|
|
138
|
+
</article>
|
|
139
|
+
</dialog>
|
|
140
|
+
</div>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
#### Close on a custom event
|
|
145
|
+
|
|
146
|
+
`listen-for` swaps the default `click` for any event. Pair it with a real
|
|
147
|
+
`<super-form>`'s `super-form-success` event to auto-close a dialog
|
|
148
|
+
once a form inside it succeeds — simulated here with `<event-handler>`.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<div>
|
|
153
|
+
<dialog-anchor role="button" target-ref="#da-auto" is-modal>Open form</dialog-anchor>
|
|
154
|
+
<dialog id="da-auto">
|
|
155
|
+
<dialog-anchor listen-for="super-form-success">
|
|
156
|
+
<p>Simulating a form submit…</p>
|
|
157
|
+
<event-handler role="button" fire-event="super-form-success">
|
|
158
|
+
Submit
|
|
159
|
+
</event-handler>
|
|
160
|
+
</dialog-anchor>
|
|
161
|
+
</dialog>
|
|
162
|
+
</div>
|
|
163
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Will probably deprecate this element now that `<button command commandfor>` and `event-handler[command-name]` cover invoking dialogs and popovers.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# dialog-anchor
|
|
2
|
+
|
|
3
|
+
Open and close a native `<dialog>` — no JavaScript required.
|
|
4
|
+
|
|
5
|
+
<include-content data-demo="simple"></include-content>
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Click to toggle** Opens / closes a `<dialog>` on click
|
|
10
|
+
- **Target or fallback** Point at any `<dialog>` via `target-ref`, or let
|
|
11
|
+
it find the nearest ancestor automatically (great for close buttons)
|
|
12
|
+
- **Modal or non-modal** `is-modal` blocks the rest of the page; omit it
|
|
13
|
+
for a lightweight, dismissible popover
|
|
14
|
+
- **Any trigger event** Inherits `listen-for` to open/close on custom
|
|
15
|
+
events instead of `click`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
<include-content is-active template-ref="/views/install-section/install-section.html"></include-content>
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Wrap a trigger in `<dialog-anchor>` and point it at a `<dialog>`. A
|
|
24
|
+
`<dialog-anchor>` with no `target-ref`, placed inside the `<dialog>` it
|
|
25
|
+
should close, needs no configuration at all.
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<dialog-anchor target-ref="#confirm" role="button">Delete</dialog-anchor>
|
|
29
|
+
<dialog id="confirm">
|
|
30
|
+
<p>Are you sure?</p>
|
|
31
|
+
<dialog-anchor role="button">Cancel</dialog-anchor>
|
|
32
|
+
</dialog>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### API Reference
|
|
36
|
+
|
|
37
|
+
<include-content is-active template-ref="/views/api-reference/api-reference.html"></include-content>
|
|
38
|
+
|
|
39
|
+
### Examples
|
|
40
|
+
|
|
41
|
+
#### Modal dialog
|
|
42
|
+
|
|
43
|
+
`is-modal` opens the dialog as a modal, blocking interaction with the rest
|
|
44
|
+
of the page until it's closed (using native `::backdrop`). Without that attribute,
|
|
45
|
+
the dialog is opened without a backdrop.
|
|
46
|
+
|
|
47
|
+
If using Valence.css, setting `.absolute` on the `dialog` element will display it `absolute`
|
|
48
|
+
in the surrounding content (as opposed to fixed).
|
|
49
|
+
|
|
50
|
+
<include-content data-demo="is-modal"></include-content>
|
|
51
|
+
|
|
52
|
+
#### Close on a custom event
|
|
53
|
+
|
|
54
|
+
`listen-for` swaps the default `click` for any event. Pair it with a real
|
|
55
|
+
`<super-form>`'s `super-form-success` event to auto-close a dialog
|
|
56
|
+
once a form inside it succeeds — simulated here with `<event-handler>`.
|
|
57
|
+
|
|
58
|
+
<include-content data-demo="auto-close"></include-content>
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shortName": "dialog-anchor",
|
|
3
|
+
"package": {
|
|
4
|
+
"name": "@excom/dialog-anchor",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"description": "<dialog-anchor> custom element",
|
|
7
|
+
"peerDependencies": {},
|
|
8
|
+
"excom": {
|
|
9
|
+
"packageType": "kit-element"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"demos": {
|
|
13
|
+
"auto-close": "<div>\n <dialog-anchor role=\"button\" target-ref=\"#da-auto\" is-modal>Open form</dialog-anchor>\n <dialog id=\"da-auto\">\n <dialog-anchor listen-for=\"super-form-success\">\n <p>Simulating a form submit…</p>\n <event-handler role=\"button\" fire-event=\"super-form-success\">\n Submit\n </event-handler>\n </dialog-anchor>\n </dialog>\n</div>\n",
|
|
14
|
+
"is-modal": "<div>\n <dialog-anchor role=\"button\" target-ref=\"#da-modal\" is-modal>\n Open as modal\n </dialog-anchor>\n <dialog-anchor role=\"button\" target-ref=\"#da-modal\">\n Open as non-modal\n </dialog-anchor>\n <dialog id=\"da-modal\">\n <article>\n <header>\n <dialog-anchor role=\"button\" rel=\"prev\"></dialog-anchor>\n <h4>Modal dialogs block interaction with the rest of the page.</h4>\n <p>This dialog is shown with Valence.css styling</p>\n </header>\n <p>Dialog content</p>\n <footer>\n Footer content\n </footer>\n </article>\n </dialog>\n</div>",
|
|
15
|
+
"simple": "<div>\n <dialog-anchor role=\"button\" target-ref=\"#da-simple\" is-modal>Open dialog</dialog-anchor>\n <dialog id=\"da-simple\">\n <p>A native, modal dialog.</p>\n <dialog-anchor role=\"button\">Close</dialog-anchor>\n </dialog>\n</div>\n"
|
|
16
|
+
},
|
|
17
|
+
"readme": "<h1 id=\"md-dialog-anchor\">dialog-anchor</h1>\n<p>Open and close a native <code><dialog></code> — no JavaScript required.</p>\n<p><include-content data-demo=\"simple\"></include-content></p>\n<h2 id=\"md-features\">Features</h2>\n<ul>\n<li><strong>Click to toggle</strong> Opens / closes a <code><dialog></code> on click</li>\n<li><strong>Target or fallback</strong> Point at any <code><dialog></code> via <code>target-ref</code>, or let\nit find the nearest ancestor automatically (great for close buttons)</li>\n<li><strong>Modal or non-modal</strong> <code>is-modal</code> blocks the rest of the page; omit it\nfor a lightweight, dismissible popover</li>\n<li><strong>Any trigger event</strong> Inherits <code>listen-for</code> to open/close on custom\nevents instead of <code>click</code></li>\n</ul>\n<h2 id=\"md-installation\">Installation</h2>\n<p><include-content is-active template-ref=\"/views/install-section/install-section.html\"></include-content></p>\n<h2 id=\"md-usage\">Usage</h2>\n<p>Wrap a trigger in <code><dialog-anchor></code> and point it at a <code><dialog></code>. A\n<code><dialog-anchor></code> with no <code>target-ref</code>, placed inside the <code><dialog></code> it\nshould close, needs no configuration at all.</p>\n<include-content data-language=\"html\"><template><dialog-anchor target-ref=\"#confirm\" role=\"button\">Delete</dialog-anchor>\n<dialog id=\"confirm\">\n <p>Are you sure?</p>\n <dialog-anchor role=\"button\">Cancel</dialog-anchor>\n</dialog></template></include-content>\n<h3 id=\"md-api-reference\">API Reference</h3>\n<p><include-content is-active template-ref=\"/views/api-reference/api-reference.html\"></include-content></p>\n<h3 id=\"md-examples\">Examples</h3>\n<h4 id=\"md-modal-dialog\">Modal dialog</h4>\n<p><code>is-modal</code> opens the dialog as a modal, blocking interaction with the rest\nof the page until it's closed (using native <code>::backdrop</code>). Without that attribute,\nthe dialog is opened without a backdrop.</p>\n<p>If using Valence.css, setting <code>.absolute</code> on the <code>dialog</code> element will display it <code>absolute</code>\nin the surrounding content (as opposed to fixed).</p>\n<p><include-content data-demo=\"is-modal\"></include-content></p>\n<h4 id=\"md-close-on-a-custom-event\">Close on a custom event</h4>\n<p><code>listen-for</code> swaps the default <code>click</code> for any event. Pair it with a real\n<code><super-form></code>'s <code>super-form-success</code> event to auto-close a dialog\nonce a form inside it succeeds — simulated here with <code><event-handler></code>.</p>\n<p><include-content data-demo=\"auto-close\"></include-content></p>\n",
|
|
18
|
+
"docs": {
|
|
19
|
+
"readme": "<h1 id=\"md-dialog-anchor\">dialog-anchor</h1>\n<p>Open and close a native <code><dialog></code> — no JavaScript required.</p>\n<p><include-content data-demo=\"simple\"></include-content></p>\n<h2 id=\"md-features\">Features</h2>\n<ul>\n<li><strong>Click to toggle</strong> Opens / closes a <code><dialog></code> on click</li>\n<li><strong>Target or fallback</strong> Point at any <code><dialog></code> via <code>target-ref</code>, or let\nit find the nearest ancestor automatically (great for close buttons)</li>\n<li><strong>Modal or non-modal</strong> <code>is-modal</code> blocks the rest of the page; omit it\nfor a lightweight, dismissible popover</li>\n<li><strong>Any trigger event</strong> Inherits <code>listen-for</code> to open/close on custom\nevents instead of <code>click</code></li>\n</ul>\n<h2 id=\"md-installation\">Installation</h2>\n<p><include-content is-active template-ref=\"/views/install-section/install-section.html\"></include-content></p>\n<h2 id=\"md-usage\">Usage</h2>\n<p>Wrap a trigger in <code><dialog-anchor></code> and point it at a <code><dialog></code>. A\n<code><dialog-anchor></code> with no <code>target-ref</code>, placed inside the <code><dialog></code> it\nshould close, needs no configuration at all.</p>\n<include-content data-language=\"html\"><template><dialog-anchor target-ref=\"#confirm\" role=\"button\">Delete</dialog-anchor>\n<dialog id=\"confirm\">\n <p>Are you sure?</p>\n <dialog-anchor role=\"button\">Cancel</dialog-anchor>\n</dialog></template></include-content>\n<h3 id=\"md-api-reference\">API Reference</h3>\n<p><include-content is-active template-ref=\"/views/api-reference/api-reference.html\"></include-content></p>\n<h3 id=\"md-examples\">Examples</h3>\n<h4 id=\"md-modal-dialog\">Modal dialog</h4>\n<p><code>is-modal</code> opens the dialog as a modal, blocking interaction with the rest\nof the page until it's closed (using native <code>::backdrop</code>). Without that attribute,\nthe dialog is opened without a backdrop.</p>\n<p>If using Valence.css, setting <code>.absolute</code> on the <code>dialog</code> element will display it <code>absolute</code>\nin the surrounding content (as opposed to fixed).</p>\n<p><include-content data-demo=\"is-modal\"></include-content></p>\n<h4 id=\"md-close-on-a-custom-event\">Close on a custom event</h4>\n<p><code>listen-for</code> swaps the default <code>click</code> for any event. Pair it with a real\n<code><super-form></code>'s <code>super-form-success</code> event to auto-close a dialog\nonce a form inside it succeeds — simulated here with <code><event-handler></code>.</p>\n<p><include-content data-demo=\"auto-close\"></include-content></p>\n"
|
|
20
|
+
},
|
|
21
|
+
"installation": {
|
|
22
|
+
"name": "@excom/dialog-anchor",
|
|
23
|
+
"shortName": "dialog-anchor",
|
|
24
|
+
"version": "0.1.0",
|
|
25
|
+
"description": "<dialog-anchor> custom element",
|
|
26
|
+
"packageType": "kit-element",
|
|
27
|
+
"cdn": "<script src=\"https://unpkg.com/@excom/kit-utils/dist/index.umd.min.js\"></script>\n<script src=\"https://unpkg.com/@excom/neutron/dist/index.umd.min.js\"></script>\n<script src=\"https://unpkg.com/@excom/dialog-anchor@0.1.0/dist/index.umd.min.js\"></script>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@excom/dialog-anchor@0.1.0/dist/index.css\">",
|
|
28
|
+
"install": {
|
|
29
|
+
"npm": "npm install @excom/dialog-anchor"
|
|
30
|
+
},
|
|
31
|
+
"imports": {
|
|
32
|
+
"js": "import \"@excom/dialog-anchor\";",
|
|
33
|
+
"css": "@import \"@excom/dialog-anchor\";",
|
|
34
|
+
"html": "<!-- import path to `node_modules` will depend on your build setup -->\n<script type=\"module\" src=\"/node_modules/@excom/dialog-anchor\"></script>\n<link rel=\"stylesheet\" href=\"/node_modules/@excom/dialog-anchor\">"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": []
|
|
37
|
+
},
|
|
38
|
+
"elementApis": [
|
|
39
|
+
{
|
|
40
|
+
"tag": "dialog-anchor",
|
|
41
|
+
"summary": "Open/close a <code><dialog></code> — by selector or nearest ancestor.",
|
|
42
|
+
"kind": "class",
|
|
43
|
+
"attributes": [
|
|
44
|
+
{
|
|
45
|
+
"name": "delay-ms",
|
|
46
|
+
"type": "number",
|
|
47
|
+
"description": "Delay handling by this many milliseconds.",
|
|
48
|
+
"fieldName": "delayMs",
|
|
49
|
+
"surface": "option",
|
|
50
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "host-ref",
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "Listen on another element / <code>window</code> / <code>document</code> — e.g. Escape to dismiss a dialog from a global <code>keydown</code>. Defaults to <code>:scope</code>. Used with <code>listen-for</code>. Not compatible with <code>listen-for-lifecycle</code>. The selector MUST resolve when <code>host-ref</code> is set — it will not wait for a match to appear.",
|
|
56
|
+
"fieldName": "hostRef",
|
|
57
|
+
"surface": "option",
|
|
58
|
+
"values": "<CSS Selector> | \"window\" | \"document\" | \"html\" | \"body\" | \"head\"",
|
|
59
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "is-debounced",
|
|
63
|
+
"type": "boolean",
|
|
64
|
+
"description": "With <code>delay-ms</code>, coalesce bursts into one trailing call (debounce).",
|
|
65
|
+
"fieldName": "isDebounced",
|
|
66
|
+
"surface": "option",
|
|
67
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "is-modal",
|
|
71
|
+
"type": "boolean",
|
|
72
|
+
"description": "Open the dialog as a modal (blocks the rest of the page) instead of a non-modal popover.",
|
|
73
|
+
"fieldName": "isModal",
|
|
74
|
+
"surface": "option"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"name": "keycode-filter",
|
|
78
|
+
"type": "tokenlist",
|
|
79
|
+
"description": "Space-separated key filters (OR). Join modifiers with <code>+</code> (AND, any order): <code>shift+k tab</code> → Shift+K or Tab. Modifiers: <code>shift</code>, <code>alt</code>, <code>ctrl</code>/<code>control</code>, <code>meta</code>. Case-insensitive.",
|
|
80
|
+
"fieldName": "keycodeFilter",
|
|
81
|
+
"surface": "option",
|
|
82
|
+
"values": "<key | mod+key>…",
|
|
83
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "listen-for",
|
|
87
|
+
"type": "tokenlist",
|
|
88
|
+
"description": "Space-separated event names to listen for. Defaults to <code>click</code> when unset (and no lifecycle list is set).",
|
|
89
|
+
"fieldName": "listenFor",
|
|
90
|
+
"surface": "option",
|
|
91
|
+
"values": "<EventName>…",
|
|
92
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "listen-for-lifecycle",
|
|
96
|
+
"type": "tokenlist",
|
|
97
|
+
"description": "Space-separated element lifecycles to handle.",
|
|
98
|
+
"fieldName": "listenForLifecycle",
|
|
99
|
+
"surface": "option",
|
|
100
|
+
"values": "\"connected\" | \"disconnected\" | \"adopted\"",
|
|
101
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "listen-once",
|
|
105
|
+
"type": "boolean",
|
|
106
|
+
"description": "Handle each distinct event name / lifecycle at most once.",
|
|
107
|
+
"fieldName": "listenOnce",
|
|
108
|
+
"surface": "option",
|
|
109
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "pathname-filter",
|
|
113
|
+
"type": "tokenlist",
|
|
114
|
+
"description": "Only handle when <code>location.pathname</code> is one of these values — route-aware behaviors without a separate router element.",
|
|
115
|
+
"fieldName": "pathnameFilter",
|
|
116
|
+
"surface": "option",
|
|
117
|
+
"values": "<pathname>…",
|
|
118
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"name": "prevent-default",
|
|
122
|
+
"type": "boolean",
|
|
123
|
+
"description": "Call <code>preventDefault()</code> on matched events (ignored for lifecycles).",
|
|
124
|
+
"fieldName": "preventDefault",
|
|
125
|
+
"surface": "option",
|
|
126
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "selector-filter",
|
|
130
|
+
"type": "string",
|
|
131
|
+
"description": "Only handle events whose <code>event.target</code> matches this CSS selector. Does not support <code>:scope</code> in the selector.",
|
|
132
|
+
"fieldName": "selectorFilter",
|
|
133
|
+
"surface": "option",
|
|
134
|
+
"values": "<CSS Selector>",
|
|
135
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "stop-immediate-propagation",
|
|
139
|
+
"type": "boolean",
|
|
140
|
+
"description": "Call <code>stopImmediatePropagation()</code> on matched events (ignored for lifecycles).",
|
|
141
|
+
"fieldName": "stopImmediatePropagation",
|
|
142
|
+
"surface": "option",
|
|
143
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "stop-propagation",
|
|
147
|
+
"type": "boolean",
|
|
148
|
+
"description": "Call <code>stopPropagation()</code> on matched events (ignored for lifecycles).",
|
|
149
|
+
"fieldName": "stopPropagation",
|
|
150
|
+
"surface": "option",
|
|
151
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"name": "target-ref",
|
|
155
|
+
"type": "string",
|
|
156
|
+
"description": "CSS selector for the <code><dialog></code> to toggle. If omitted, the element toggles the nearest ancestor <code><dialog></code>.",
|
|
157
|
+
"fieldName": "targetRef",
|
|
158
|
+
"surface": "option",
|
|
159
|
+
"values": "<CSS Selector>"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "vibrate-ms",
|
|
163
|
+
"type": "number",
|
|
164
|
+
"description": "Vibrate on handle (<code>navigator.vibrate</code>). Empty / <code>0</code> uses a 20ms pulse.",
|
|
165
|
+
"fieldName": "vibrateMs",
|
|
166
|
+
"surface": "option",
|
|
167
|
+
"default": "\"20 (when attribute is present with no value)\"",
|
|
168
|
+
"inheritedFrom": "@excom/listenable-element"
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"events": [],
|
|
172
|
+
"slots": [],
|
|
173
|
+
"cssProperties": [],
|
|
174
|
+
"cssClasses": [
|
|
175
|
+
{
|
|
176
|
+
"name": "unstyled",
|
|
177
|
+
"description": "Skip the pointer cursor from the listenable mixin."
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"cssAliases": [
|
|
181
|
+
{
|
|
182
|
+
"name": ":--dialog-anchor",
|
|
183
|
+
"selectors": [
|
|
184
|
+
"dialog-anchor",
|
|
185
|
+
".tag-dialog-anchor"
|
|
186
|
+
],
|
|
187
|
+
"kind": "element",
|
|
188
|
+
"description": ""
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"listens": [],
|
|
192
|
+
"commands": [],
|
|
193
|
+
"defaultActions": [],
|
|
194
|
+
"expectedChildren": [],
|
|
195
|
+
"provisions": []
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
"exportedFiles": {}
|
|
199
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import {
|
|
10
|
+
click,
|
|
11
|
+
flush,
|
|
12
|
+
mountView,
|
|
13
|
+
readDemo,
|
|
14
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
15
|
+
|
|
16
|
+
describe("auto-close view", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = "";
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("closes the dialog on simulated submit success", async () => {
|
|
22
|
+
const { root } = await mountView(readDemo(import.meta.url, "auto-close"));
|
|
23
|
+
const dialog = root.querySelector("dialog")!;
|
|
24
|
+
click(root.querySelector("[target-ref]"));
|
|
25
|
+
await flush();
|
|
26
|
+
expect(dialog.open).toBe(true);
|
|
27
|
+
click(dialog.querySelector("[role='button']"));
|
|
28
|
+
await flush();
|
|
29
|
+
expect(dialog.open).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
describe,
|
|
4
|
+
expect,
|
|
5
|
+
fixture,
|
|
6
|
+
it,
|
|
7
|
+
vi,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import "../../index";
|
|
10
|
+
|
|
11
|
+
describe("dialog-anchor", () => {
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
document.body.innerHTML = "";
|
|
14
|
+
vi.restoreAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("opens and closes dialog properly", async () => {
|
|
18
|
+
fixture<HTMLDivElement>(
|
|
19
|
+
`<div>
|
|
20
|
+
<dialog-anchor target-ref="dialog" id="c"></dialog-anchor>
|
|
21
|
+
</div>
|
|
22
|
+
<dialog>
|
|
23
|
+
<dialog-anchor id="b"></dialog-anchor>
|
|
24
|
+
</dialog>
|
|
25
|
+
<dialog-anchor is-modal target-ref="dialog:has(+:scope)" id="a"></dialog-anchor>`,
|
|
26
|
+
);
|
|
27
|
+
const dialogAnchor1 = document.querySelector(
|
|
28
|
+
"#a",
|
|
29
|
+
) as HTMLDialogAnchorElement;
|
|
30
|
+
const dialogAnchor2 = document.querySelector(
|
|
31
|
+
"#b",
|
|
32
|
+
) as HTMLDialogAnchorElement;
|
|
33
|
+
const dialogAnchor3 = document.querySelector(
|
|
34
|
+
"#c",
|
|
35
|
+
) as HTMLDialogAnchorElement;
|
|
36
|
+
const dialog = document.querySelector("dialog")!;
|
|
37
|
+
const showSpy = vi.spyOn(dialog, "show");
|
|
38
|
+
const showModalSpy = vi.spyOn(dialog, "showModal");
|
|
39
|
+
const closeSpy = vi.spyOn(dialog, "close");
|
|
40
|
+
|
|
41
|
+
expect(dialog.open).toBe(false);
|
|
42
|
+
|
|
43
|
+
// modal, previous sibling
|
|
44
|
+
dialogAnchor1.dispatchEvent(new Event("click"));
|
|
45
|
+
expect(showModalSpy).toHaveBeenCalled();
|
|
46
|
+
expect(showSpy).not.toHaveBeenCalled();
|
|
47
|
+
expect(closeSpy).not.toHaveBeenCalled();
|
|
48
|
+
|
|
49
|
+
// close, child
|
|
50
|
+
dialogAnchor2.dispatchEvent(new Event("click"));
|
|
51
|
+
expect(closeSpy).toHaveBeenCalled();
|
|
52
|
+
|
|
53
|
+
// non-modal, target-ref
|
|
54
|
+
dialogAnchor3.dispatchEvent(new Event("click"));
|
|
55
|
+
expect(showSpy).toHaveBeenCalled();
|
|
56
|
+
expect(dialog.open).toBe(true);
|
|
57
|
+
|
|
58
|
+
// toggle
|
|
59
|
+
dialogAnchor3.dispatchEvent(new Event("click"));
|
|
60
|
+
expect(closeSpy).toHaveBeenCalledTimes(2);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("dialog-anchor (no dialog)", () => {
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
document.body.innerHTML = "";
|
|
67
|
+
vi.restoreAllMocks();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("does nothing when neither target-ref nor an ancestor resolves to a dialog", () => {
|
|
71
|
+
const wrapper = fixture<HTMLDivElement>(
|
|
72
|
+
`<div>
|
|
73
|
+
<p id="not-a-dialog"></p>
|
|
74
|
+
<dialog-anchor target-ref="#not-a-dialog" id="x"></dialog-anchor>
|
|
75
|
+
<dialog-anchor target-ref="#missing" id="y"></dialog-anchor>
|
|
76
|
+
<dialog-anchor id="z"></dialog-anchor>
|
|
77
|
+
</div>`,
|
|
78
|
+
);
|
|
79
|
+
const showSpy = vi.spyOn(HTMLDialogElement.prototype, "show");
|
|
80
|
+
const showModalSpy = vi.spyOn(HTMLDialogElement.prototype, "showModal");
|
|
81
|
+
const closeSpy = vi.spyOn(HTMLDialogElement.prototype, "close");
|
|
82
|
+
wrapper.querySelectorAll("dialog-anchor").forEach((anchor) => {
|
|
83
|
+
expect(() => anchor.dispatchEvent(new Event("click"))).not.toThrow();
|
|
84
|
+
});
|
|
85
|
+
expect(showSpy).not.toHaveBeenCalled();
|
|
86
|
+
expect(showModalSpy).not.toHaveBeenCalled();
|
|
87
|
+
expect(closeSpy).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("falls back to the closest dialog when target-ref is not a dialog", () => {
|
|
91
|
+
fixture<HTMLDialogElement>(
|
|
92
|
+
`<dialog>
|
|
93
|
+
<p id="inner-p"></p>
|
|
94
|
+
<dialog-anchor target-ref="#inner-p" is-modal></dialog-anchor>
|
|
95
|
+
</dialog>`,
|
|
96
|
+
);
|
|
97
|
+
const dialog = document.querySelector("dialog")!;
|
|
98
|
+
const showModalSpy = vi.spyOn(dialog, "showModal");
|
|
99
|
+
document.querySelector("dialog-anchor")!.dispatchEvent(new Event("click"));
|
|
100
|
+
expect(showModalSpy).toHaveBeenCalledTimes(1);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import "../../index";
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
it,
|
|
7
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
8
|
+
import {
|
|
9
|
+
click,
|
|
10
|
+
flush,
|
|
11
|
+
mountView,
|
|
12
|
+
readDemo,
|
|
13
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
14
|
+
|
|
15
|
+
describe("is-modal view", () => {
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
document.body.innerHTML = "";
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("opens modal and non-modal", async () => {
|
|
21
|
+
const { root } = await mountView(readDemo(import.meta.url, "is-modal"));
|
|
22
|
+
const dialog = root.querySelector("dialog")!;
|
|
23
|
+
const [modalBtn, modelessBtn] = root.querySelectorAll(
|
|
24
|
+
"dialog-anchor[target-ref]",
|
|
25
|
+
);
|
|
26
|
+
click(modalBtn);
|
|
27
|
+
await flush();
|
|
28
|
+
expect(dialog.open).toBe(true);
|
|
29
|
+
dialog.close();
|
|
30
|
+
click(modelessBtn);
|
|
31
|
+
await flush();
|
|
32
|
+
expect(dialog.open).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import "../../index";
|
|
2
|
+
import {
|
|
3
|
+
afterEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
it,
|
|
7
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
8
|
+
import {
|
|
9
|
+
click,
|
|
10
|
+
flush,
|
|
11
|
+
mountView,
|
|
12
|
+
readDemo,
|
|
13
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
14
|
+
|
|
15
|
+
describe("simple view", () => {
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
document.body.innerHTML = "";
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("opens and closes the dialog", async () => {
|
|
21
|
+
const { root } = await mountView(readDemo(import.meta.url, "simple"));
|
|
22
|
+
const dialog = root.querySelector("dialog")!;
|
|
23
|
+
expect(dialog.open).toBe(false);
|
|
24
|
+
click(root.querySelector("[target-ref]"));
|
|
25
|
+
await flush();
|
|
26
|
+
expect(dialog.open).toBe(true);
|
|
27
|
+
click(dialog.querySelector("dialog-anchor"));
|
|
28
|
+
await flush();
|
|
29
|
+
expect(dialog.open).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|