@brytdesigns/web-component-modal 1.1.8 → 3.0.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/dist/main/components/index.js +4 -10
- package/dist/main/components/modal-backdrop.js +50 -76
- package/dist/main/components/modal-backdrop.js.map +1 -1
- package/dist/main/components/modal-context.js +125 -126
- package/dist/main/components/modal-context.js.map +1 -1
- package/dist/main/components/modal-panel.js +63 -70
- package/dist/main/components/modal-panel.js.map +1 -1
- package/dist/main/components/modal-trigger.js +83 -74
- package/dist/main/components/modal-trigger.js.map +1 -1
- package/dist/main/hooks/index.js +2 -3
- package/dist/main/hooks/useModal.js +86 -85
- package/dist/main/hooks/useModal.js.map +1 -1
- package/dist/main/index.d.ts +32 -30
- package/dist/main/index.js +28 -32
- package/dist/main/index.js.map +1 -1
- package/dist/main/utils.js +5 -4
- package/dist/main/utils.js.map +1 -1
- package/package.json +8 -9
- package/dist/esm/index.js +0 -493
- package/dist/esm/index.js.map +0 -1
- package/dist/main/components/index.js.map +0 -1
- package/dist/main/consts.js +0 -10
- package/dist/main/consts.js.map +0 -1
- package/dist/main/hooks/index.js.map +0 -1
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import * as modalBackdrop_js from './modal-backdrop.js';
|
|
6
|
-
export { modalBackdrop_js as ModalBackdrop };
|
|
7
|
-
import * as modalContext_js from './modal-context.js';
|
|
8
|
-
export { modalContext_js as ModalContext };
|
|
9
|
-
//# sourceMappingURL=index.js.map
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import "./modal-backdrop.js";
|
|
2
|
+
import "./modal-context.js";
|
|
3
|
+
import "./modal-panel.js";
|
|
4
|
+
import "./modal-trigger.js";
|
|
@@ -1,79 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
function exit(element2) {
|
|
52
|
-
const style = window.getComputedStyle(element2);
|
|
53
|
-
const options = getTransitionConfig(style);
|
|
54
|
-
return animate(
|
|
55
|
-
element2,
|
|
56
|
-
{
|
|
57
|
-
opacity: [`var(--${Name}--opacity-to)`, `var(--${Name}--opacity-from)`]
|
|
58
|
-
},
|
|
59
|
-
options
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
element.addEventListener(
|
|
63
|
-
"click",
|
|
64
|
-
() => {
|
|
65
|
-
if (state.isAnimating) return;
|
|
66
|
-
close();
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
signal: controller.signal
|
|
70
|
-
}
|
|
71
|
-
);
|
|
72
|
-
onCleanup(() => {
|
|
73
|
-
controller.abort();
|
|
74
|
-
});
|
|
1
|
+
import { useModal } from "../hooks/useModal.js";
|
|
2
|
+
import "../hooks/index.js";
|
|
3
|
+
import { createGuardedEffect } from "@brytdesigns/web-component-core/utils";
|
|
4
|
+
import { getTransitionConfig } from "@brytdesigns/web-component-core/animation";
|
|
5
|
+
import { animate } from "motion";
|
|
6
|
+
import { onCleanup, onSettled } from "solid-js";
|
|
7
|
+
//#region src/components/modal-backdrop.ts
|
|
8
|
+
var Name = "modal-backdrop";
|
|
9
|
+
var Component = (_, { element }) => {
|
|
10
|
+
const [state, { updateAnimationQueue, close }] = useModal(element);
|
|
11
|
+
const controller = new AbortController();
|
|
12
|
+
let isFirstRender = true;
|
|
13
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
14
|
+
if (!isOpen || isFirstRender) return;
|
|
15
|
+
const animation = enter(element);
|
|
16
|
+
updateAnimationQueue(animation);
|
|
17
|
+
return () => {
|
|
18
|
+
if (animation.state !== "finished") animation.complete();
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
22
|
+
if (isOpen || isFirstRender) return;
|
|
23
|
+
const animation = exit(element);
|
|
24
|
+
updateAnimationQueue(animation);
|
|
25
|
+
return () => {
|
|
26
|
+
if (animation.state !== "finished") animation.complete();
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
onSettled(() => {
|
|
30
|
+
isFirstRender = false;
|
|
31
|
+
});
|
|
32
|
+
function enter(element) {
|
|
33
|
+
const style = window.getComputedStyle(element);
|
|
34
|
+
const options = getTransitionConfig(style);
|
|
35
|
+
return animate(element, { opacity: [`var(--${Name}--opacity-from)`, `var(--${Name}--opacity-to)`] }, options);
|
|
36
|
+
}
|
|
37
|
+
function exit(element) {
|
|
38
|
+
const style = window.getComputedStyle(element);
|
|
39
|
+
const options = getTransitionConfig(style);
|
|
40
|
+
return animate(element, { opacity: [`var(--${Name}--opacity-to)`, `var(--${Name}--opacity-from)`] }, options);
|
|
41
|
+
}
|
|
42
|
+
element.addEventListener("click", () => {
|
|
43
|
+
if (state.isAnimating) return;
|
|
44
|
+
close();
|
|
45
|
+
}, { signal: controller.signal });
|
|
46
|
+
onCleanup(() => {
|
|
47
|
+
controller.abort();
|
|
48
|
+
});
|
|
75
49
|
};
|
|
76
|
-
|
|
50
|
+
//#endregion
|
|
77
51
|
export { Component, Name };
|
|
78
|
-
|
|
52
|
+
|
|
79
53
|
//# sourceMappingURL=modal-backdrop.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"modal-backdrop.js","names":[],"sources":["../../../src/components/modal-backdrop.ts"],"sourcesContent":["import { getTransitionConfig } from \"@brytdesigns/web-component-core/animation\";\nimport type { CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\nimport { createGuardedEffect } from \"@brytdesigns/web-component-core/utils\";\nimport { animate } from \"motion\";\nimport { onCleanup, onSettled } from \"solid-js\";\n\nimport { useModal } from \"../hooks/index.js\";\n\nexport type Props = {};\n\nexport const Name = \"modal-backdrop\";\n\nexport const Component: CorrectComponentType<Props> = (_, { element }) => {\n\tconst [state, { updateAnimationQueue, close }] = useModal(element);\n\tconst controller = new AbortController();\n\n\tlet isFirstRender = true;\n\n\tcreateGuardedEffect(\n\t\t() => state.isOpen,\n\t\t(isOpen) => {\n\t\t\tif (!isOpen || isFirstRender) return;\n\t\t\tconst animation = enter(element);\n\t\t\tupdateAnimationQueue(animation);\n\t\t\treturn () => {\n\t\t\t\tif (animation.state !== \"finished\") animation.complete();\n\t\t\t};\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => state.isOpen,\n\t\t(isOpen) => {\n\t\t\tif (isOpen || isFirstRender) return;\n\t\t\tconst animation = exit(element);\n\t\t\tupdateAnimationQueue(animation);\n\t\t\treturn () => {\n\t\t\t\tif (animation.state !== \"finished\") animation.complete();\n\t\t\t};\n\t\t},\n\t);\n\n\tonSettled(() => {\n\t\tisFirstRender = false;\n\t});\n\n\tfunction enter(element: HTMLElement) {\n\t\tconst style = window.getComputedStyle(element);\n\t\tconst options = getTransitionConfig(style);\n\t\treturn animate(\n\t\t\telement,\n\t\t\t{\n\t\t\t\topacity: [`var(--${Name}--opacity-from)`, `var(--${Name}--opacity-to)`],\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n\n\tfunction exit(element: HTMLElement) {\n\t\tconst style = window.getComputedStyle(element);\n\t\tconst options = getTransitionConfig(style);\n\t\treturn animate(\n\t\t\telement,\n\t\t\t{\n\t\t\t\topacity: [`var(--${Name}--opacity-to)`, `var(--${Name}--opacity-from)`],\n\t\t\t},\n\t\t\toptions,\n\t\t);\n\t}\n\n\telement.addEventListener(\n\t\t\"click\",\n\t\t() => {\n\t\t\tif (state.isAnimating) return;\n\t\t\tclose();\n\t\t},\n\t\t{\n\t\t\tsignal: controller.signal,\n\t\t},\n\t);\n\n\tonCleanup(() => {\n\t\tcontroller.abort();\n\t});\n};\n"],"mappings":";;;;;;;AAUA,IAAa,OAAO;AAEpB,IAAa,aAA0C,GAAG,EAAE,cAAc;CACzE,MAAM,CAAC,OAAO,EAAE,sBAAsB,WAAW,SAAS,OAAO;CACjE,MAAM,aAAa,IAAI,gBAAgB;CAEvC,IAAI,gBAAgB;CAEpB,0BACO,MAAM,SACX,WAAW;EACX,IAAI,CAAC,UAAU,eAAe;EAC9B,MAAM,YAAY,MAAM,OAAO;EAC/B,qBAAqB,SAAS;EAC9B,aAAa;GACZ,IAAI,UAAU,UAAU,YAAY,UAAU,SAAS;EACxD;CACD,CACD;CAEA,0BACO,MAAM,SACX,WAAW;EACX,IAAI,UAAU,eAAe;EAC7B,MAAM,YAAY,KAAK,OAAO;EAC9B,qBAAqB,SAAS;EAC9B,aAAa;GACZ,IAAI,UAAU,UAAU,YAAY,UAAU,SAAS;EACxD;CACD,CACD;CAEA,gBAAgB;EACf,gBAAgB;CACjB,CAAC;CAED,SAAS,MAAM,SAAsB;EACpC,MAAM,QAAQ,OAAO,iBAAiB,OAAO;EAC7C,MAAM,UAAU,oBAAoB,KAAK;EACzC,OAAO,QACN,SACA,EACC,SAAS,CAAC,SAAS,KAAK,kBAAkB,SAAS,KAAK,cAAc,EACvE,GACA,OACD;CACD;CAEA,SAAS,KAAK,SAAsB;EACnC,MAAM,QAAQ,OAAO,iBAAiB,OAAO;EAC7C,MAAM,UAAU,oBAAoB,KAAK;EACzC,OAAO,QACN,SACA,EACC,SAAS,CAAC,SAAS,KAAK,gBAAgB,SAAS,KAAK,gBAAgB,EACvE,GACA,OACD;CACD;CAEA,QAAQ,iBACP,eACM;EACL,IAAI,MAAM,aAAa;EACvB,MAAM;CACP,GACA,EACC,QAAQ,WAAW,OACpB,CACD;CAEA,gBAAgB;EACf,WAAW,MAAM;CAClB,CAAC;AACF"}
|
|
@@ -1,129 +1,128 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
1
|
+
import { provideModalContext, useModalContext } from "../hooks/useModal.js";
|
|
2
|
+
import "../hooks/index.js";
|
|
3
|
+
import { hideElement, showElement } from "../utils.js";
|
|
4
|
+
import { closeNestedOverlays, createEscapeHandler, createFocusReturn, createGuardedEffect, disableBodyScroll, enableBodyScroll, findOverlayPanel } from "@brytdesigns/web-component-core/utils";
|
|
5
|
+
import { omit, onCleanup, onSettled } from "solid-js";
|
|
6
|
+
import { createFocusTrap } from "@brytdesigns/web-component-core/focusTrap";
|
|
7
|
+
//#region src/components/modal-context.ts
|
|
8
|
+
var Name = "modal-context";
|
|
9
|
+
var Component = (props, { element }) => {
|
|
10
|
+
const restProps = omit(props, "isOpen", "isAnimating");
|
|
11
|
+
const contextProps = {
|
|
12
|
+
get isOpen() {
|
|
13
|
+
return props.isOpen;
|
|
14
|
+
},
|
|
15
|
+
get isAnimating() {
|
|
16
|
+
return props.isAnimating;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const context = provideModalContext(contextProps, element);
|
|
20
|
+
const [state, { setElementState }] = context;
|
|
21
|
+
const [_, { updateAnimationQueue, ...events }] = useModalContext(context);
|
|
22
|
+
element.actions = events;
|
|
23
|
+
const panel = () => findOverlayPanel(element, "modal-panel");
|
|
24
|
+
const focusReturn = createFocusReturn(element);
|
|
25
|
+
const focusTrap = createFocusTrap(element, () => ({
|
|
26
|
+
allowOutsideClick: true,
|
|
27
|
+
escapeDeactivates: false,
|
|
28
|
+
returnFocusOnDeactivate: false,
|
|
29
|
+
initialFocus: () => panel() ?? false,
|
|
30
|
+
fallbackFocus: () => panel() ?? element
|
|
31
|
+
}));
|
|
32
|
+
createGuardedEffect(() => ({
|
|
33
|
+
isOpen: state.isOpen,
|
|
34
|
+
closeOnEscape: restProps.closeOnEscape
|
|
35
|
+
}), ({ isOpen, closeOnEscape }) => {
|
|
36
|
+
if (!isOpen || !closeOnEscape) return;
|
|
37
|
+
return createEscapeHandler({
|
|
38
|
+
element,
|
|
39
|
+
onEscape: () => setElementState("isOpen", false)
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
43
|
+
const eventName = isOpen ? "modal:open" : "modal:close";
|
|
44
|
+
element.dispatchEvent(new CustomEvent(eventName, {
|
|
45
|
+
bubbles: true,
|
|
46
|
+
detail: {
|
|
47
|
+
isOpen,
|
|
48
|
+
relatedTarget: element
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
element.dispatchEvent(new CustomEvent("drawer:toggle", {
|
|
52
|
+
bubbles: true,
|
|
53
|
+
detail: {
|
|
54
|
+
isOpen,
|
|
55
|
+
relatedTarget: element
|
|
56
|
+
}
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
createGuardedEffect(() => ({
|
|
60
|
+
isOpen: state.isOpen,
|
|
61
|
+
isAnimating: state.isAnimating,
|
|
62
|
+
focusTrap: focusTrap(),
|
|
63
|
+
shouldTrapFocus: restProps.shouldTrapFocus
|
|
64
|
+
}), ({ isOpen, isAnimating, focusTrap, shouldTrapFocus }) => {
|
|
65
|
+
if (!isOpen) return;
|
|
66
|
+
showElement(element);
|
|
67
|
+
if (!shouldTrapFocus || isAnimating) return;
|
|
68
|
+
focusReturn.record();
|
|
69
|
+
focusTrap.activate();
|
|
70
|
+
return () => {
|
|
71
|
+
focusTrap.deactivate();
|
|
72
|
+
focusReturn.restore();
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
createGuardedEffect(() => ({
|
|
76
|
+
isOpen: state.isOpen,
|
|
77
|
+
isAnimating: state.isAnimating,
|
|
78
|
+
shouldTrapFocus: restProps.shouldTrapFocus
|
|
79
|
+
}), ({ isOpen, isAnimating, shouldTrapFocus }) => {
|
|
80
|
+
if (!isOpen || isAnimating || !shouldTrapFocus) return;
|
|
81
|
+
disableBodyScroll(element, { allowTouchMove: (el) => {
|
|
82
|
+
if (el instanceof HTMLElement) {
|
|
83
|
+
let element = el;
|
|
84
|
+
while (element && element !== document.body) {
|
|
85
|
+
if (element.tagName === "MODAL-PANEL") return true;
|
|
86
|
+
element = element.parentElement;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
} });
|
|
91
|
+
return () => enableBodyScroll(element);
|
|
92
|
+
});
|
|
93
|
+
createGuardedEffect(() => state.isOpen, (isOpen, previous) => {
|
|
94
|
+
if (previous === void 0 || isOpen) return;
|
|
95
|
+
closeNestedOverlays(element);
|
|
96
|
+
});
|
|
97
|
+
createGuardedEffect(() => ({
|
|
98
|
+
isOpen: state.isOpen,
|
|
99
|
+
animationQueue: state.animationQueue
|
|
100
|
+
}), ({ isOpen, animationQueue }) => {
|
|
101
|
+
if (isOpen) return;
|
|
102
|
+
Promise.all(animationQueue).then(() => hideElement(element));
|
|
103
|
+
});
|
|
104
|
+
let openAfterDelayTimeoutId = null;
|
|
105
|
+
onSettled(() => {
|
|
106
|
+
if (!restProps.delay || contextProps.isOpen) return;
|
|
107
|
+
openAfterDelayTimeoutId = setTimeout(() => {
|
|
108
|
+
setElementState("isOpen", true);
|
|
109
|
+
}, props.delay);
|
|
110
|
+
return () => {
|
|
111
|
+
clearTimeout(openAfterDelayTimeoutId);
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
createGuardedEffect(() => ({
|
|
115
|
+
isOpen: state.isOpen,
|
|
116
|
+
openAfterDelay: restProps.delay > 0
|
|
117
|
+
}), ({ isOpen, openAfterDelay }) => {
|
|
118
|
+
if (!openAfterDelay && openAfterDelayTimeoutId) clearTimeout(openAfterDelayTimeoutId);
|
|
119
|
+
if (isOpen && openAfterDelayTimeoutId) clearTimeout(openAfterDelayTimeoutId);
|
|
120
|
+
});
|
|
121
|
+
onCleanup(() => {
|
|
122
|
+
enableBodyScroll(element);
|
|
123
|
+
});
|
|
125
124
|
};
|
|
126
|
-
|
|
125
|
+
//#endregion
|
|
127
126
|
export { Component, Name };
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
//# sourceMappingURL=modal-context.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"modal-context.js","names":[],"sources":["../../../src/components/modal-context.ts"],"sourcesContent":["import { createFocusTrap } from \"@brytdesigns/web-component-core/focusTrap\";\nimport {\n\ttype CorrectComponentType,\n\tcloseNestedOverlays,\n\tcreateEscapeHandler,\n\tcreateFocusReturn,\n\tcreateGuardedEffect,\n\tdisableBodyScroll,\n\tenableBodyScroll,\n\tfindOverlayPanel,\n} from \"@brytdesigns/web-component-core/utils\";\nimport { omit, onCleanup, onSettled, untrack } from \"solid-js\";\n\nimport { provideModalContext, useModalContext } from \"../hooks/index.js\";\nimport { hideElement, showElement } from \"../utils.js\";\n\nexport type Props = {\n\tisOpen: boolean;\n\tid: string;\n\tcloseOnEscape: boolean;\n\tshouldTrapFocus: boolean;\n\tisAnimating: boolean;\n\tdelay: number;\n};\n\nexport const Name = \"modal-context\";\n\nexport const Component: CorrectComponentType<Props> = (props, { element }) => {\n\t// `splitProps` is gone. `omit` gives the rest; the picked half is a getter\n\t// object so it stays reactive, which is what splitProps returned.\n\tconst restProps = omit(props, \"isOpen\", \"isAnimating\");\n\tconst contextProps = {\n\t\tget isOpen() {\n\t\t\treturn props.isOpen;\n\t\t},\n\t\tget isAnimating() {\n\t\t\treturn props.isAnimating;\n\t\t},\n\t};\n\n\tconst context = provideModalContext(contextProps, element);\n\n\tconst [state, { setElementState }] = context;\n\n\tconst [_, { updateAnimationQueue, ...events }] = useModalContext(context);\n\n\telement.actions = events;\n\n\tconst panel = () => findOverlayPanel(element, \"modal-panel\");\n\tconst focusReturn = createFocusReturn(element);\n\n\tconst focusTrap = createFocusTrap(element, () => ({\n\t\tallowOutsideClick: true,\n\t\t// Escape and focus return are handled explicitly below rather than as\n\t\t// focus-trap options. As options they only applied while a trap was\n\t\t// active, so `close-on-escape=\"true\" should-trap-focus=\"false\"` silently\n\t\t// did nothing, and returning focus was a side effect of trapping it.\n\t\tescapeDeactivates: false,\n\t\treturnFocusOnDeactivate: false,\n\t\t// The panel, not its first button: a screen reader then announces the\n\t\t// dialog's name and role on open instead of \"Close\".\n\t\tinitialFocus: () => panel() ?? false,\n\t\t// Without this, an overlay holding nothing tabbable throws on activate.\n\t\tfallbackFocus: () => panel() ?? element,\n\t\t// No `onDeactivate`. It used to close the overlay, because deactivation\n\t\t// was how focus-trap's `escapeDeactivates` reported an Escape press —\n\t\t// and with Escape handled explicitly above, closing on *any* deactivation\n\t\t// is actively wrong: the trap is also deactivated whenever this effect\n\t\t// re-runs, so an overlay would close itself the moment it started\n\t\t// animating open.\n\t}));\n\n\tcreateGuardedEffect(\n\t\t() => ({\n\t\t\tisOpen: state.isOpen,\n\t\t\tcloseOnEscape: restProps.closeOnEscape,\n\t\t}),\n\t\t({ isOpen, closeOnEscape }) => {\n\t\t\tif (!isOpen || !closeOnEscape) return;\n\t\t\t// Only the innermost open overlay responds, so Escape inside a nested\n\t\t\t// overlay closes that one rather than collapsing the whole stack.\n\t\t\treturn createEscapeHandler({\n\t\t\t\telement,\n\t\t\t\tonEscape: () => setElementState(\"isOpen\", false),\n\t\t\t});\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => state.isOpen,\n\t\t(isOpen) => {\n\t\t\tconst eventName = isOpen ? \"modal:open\" : \"modal:close\";\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew CustomEvent(eventName, {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tdetail: { isOpen, relatedTarget: element },\n\t\t\t\t}),\n\t\t\t);\n\t\t\telement.dispatchEvent(\n\t\t\t\tnew CustomEvent(\"drawer:toggle\", {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tdetail: { isOpen, relatedTarget: element },\n\t\t\t\t}),\n\t\t\t);\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => ({\n\t\t\tisOpen: state.isOpen,\n\t\t\tisAnimating: state.isAnimating,\n\t\t\tfocusTrap: focusTrap(),\n\t\t\tshouldTrapFocus: restProps.shouldTrapFocus,\n\t\t}),\n\t\t({ isOpen, isAnimating, focusTrap, shouldTrapFocus }) => {\n\t\t\tif (!isOpen) return;\n\t\t\tshowElement(element);\n\t\t\t// Waiting out the enter animation keeps the trap off content that is\n\t\t\t// still transitioning, and means `record()` reads the trigger rather\n\t\t\t// than whatever the animation left focused.\n\t\t\tif (!shouldTrapFocus || isAnimating) return;\n\t\t\tfocusReturn.record();\n\t\t\tfocusTrap.activate();\n\t\t\t// The apply phase is not a computation, so `onCleanup` here would\n\t\t\t// never register. Its return value IS the cleanup.\n\t\t\treturn () => {\n\t\t\t\tfocusTrap.deactivate();\n\t\t\t\tfocusReturn.restore();\n\t\t\t};\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => ({\n\t\t\tisOpen: state.isOpen,\n\t\t\tisAnimating: state.isAnimating,\n\t\t\tshouldTrapFocus: restProps.shouldTrapFocus,\n\t\t}),\n\t\t({ isOpen, isAnimating, shouldTrapFocus }) => {\n\t\t\tif (!isOpen || isAnimating || !shouldTrapFocus) return;\n\n\t\t\tdisableBodyScroll(element, {\n\t\t\t\tallowTouchMove: (el: EventTarget) => {\n\t\t\t\t\tif (el instanceof HTMLElement) {\n\t\t\t\t\t\tlet element = el as (EventTarget & HTMLElement) | null;\n\t\t\t\t\t\twhile (element && element !== document.body) {\n\t\t\t\t\t\t\tif (element.tagName === \"MODAL-PANEL\") {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\telement = element.parentElement;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\t// The apply phase’s return value IS the cleanup, and\n\t\t\t// `disableBodyScroll` returns void — so returning its call registered\n\t\t\t// no cleanup at all. The lock was only released on the *next* run’s\n\t\t\t// cleanup, i.e. when the drawer reopened, so closing it left the page\n\t\t\t// unscrollable.\n\t\t\treturn () => enableBodyScroll(element);\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => state.isOpen,\n\t\t(isOpen, previous) => {\n\t\t\t// Nothing to close on the mount run: a descendant that starts open was\n\t\t\t// authored that way, and closing it here would fight the markup.\n\t\t\tif (previous === undefined || isOpen) return;\n\t\t\t// Closing this one hides everything inside it, but a nested overlay\n\t\t\t// keeps its own `isOpen` until something changes it — so it would stay\n\t\t\t// \"open\" while invisible, never fire its close event, and reappear\n\t\t\t// still open when this one is opened again.\n\t\t\tcloseNestedOverlays(element);\n\t\t},\n\t);\n\n\tcreateGuardedEffect(\n\t\t() => ({ isOpen: state.isOpen, animationQueue: state.animationQueue }),\n\t\t({ isOpen, animationQueue }) => {\n\t\t\tif (isOpen) return;\n\t\t\t// Not returned: in v2 the apply phase's return value is the cleanup\n\t\t\t// function, and this is a promise chain.\n\t\t\tvoid Promise.all(animationQueue).then(() => hideElement(element));\n\t\t},\n\t);\n\n\tlet openAfterDelayTimeoutId: any = null;\n\n\tonSettled(() => {\n\t\tif (!restProps.delay || contextProps.isOpen) return;\n\n\t\topenAfterDelayTimeoutId = setTimeout(() => {\n\t\t\tsetElementState(\"isOpen\", true);\n\t\t}, props.delay);\n\n\t\treturn () => {\n\t\t\tclearTimeout(openAfterDelayTimeoutId);\n\t\t};\n\t});\n\n\tcreateGuardedEffect(\n\t\t() => ({\n\t\t\tisOpen: state.isOpen,\n\t\t\topenAfterDelay: restProps.delay > 0,\n\t\t}),\n\t\t({ isOpen, openAfterDelay }) => {\n\t\t\tif (!openAfterDelay && openAfterDelayTimeoutId)\n\t\t\t\tclearTimeout(openAfterDelayTimeoutId);\n\t\t\tif (isOpen && openAfterDelayTimeoutId)\n\t\t\t\tclearTimeout(openAfterDelayTimeoutId);\n\t\t},\n\t);\n\n\tonCleanup(() => {\n\t\tenableBodyScroll(element);\n\t});\n};\n"],"mappings":"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"}
|
|
@@ -1,73 +1,66 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
scaleY: [`var(--${Name}--scale-y-to)`, `var(--${Name}--scale-y-from)`],
|
|
63
|
-
scaleX: [`var(--${Name}--scale-x-to)`, `var(--${Name}--scale-x-from)`],
|
|
64
|
-
opacity: [`var(--${Name}--opacity-to)`, `var(--${Name}--opacity-from)`]
|
|
65
|
-
},
|
|
66
|
-
transition
|
|
67
|
-
);
|
|
68
|
-
}
|
|
1
|
+
import { useModal } from "../hooks/useModal.js";
|
|
2
|
+
import "../hooks/index.js";
|
|
3
|
+
import { createGuardedEffect } from "@brytdesigns/web-component-core/utils";
|
|
4
|
+
import { getTransitionConfig } from "@brytdesigns/web-component-core/animation";
|
|
5
|
+
import { animate } from "motion";
|
|
6
|
+
import { onSettled } from "solid-js";
|
|
7
|
+
//#region src/components/modal-panel.ts
|
|
8
|
+
var Name = "modal-panel";
|
|
9
|
+
var Component = (_, { element }) => {
|
|
10
|
+
const [state, { updateAnimationQueue }] = useModal(element);
|
|
11
|
+
let isFirstRender = true;
|
|
12
|
+
if (!element.hasAttribute("role")) element.setAttribute("role", "dialog");
|
|
13
|
+
if (!element.hasAttribute("tabindex")) element.setAttribute("tabindex", "-1");
|
|
14
|
+
onSettled(() => {
|
|
15
|
+
if (!(element.hasAttribute("aria-labelledby") || element.hasAttribute("aria-label"))) console.warn("modal-panel: no accessible name. Add an aria-label, or an aria-labelledby pointing at the heading inside it.", element);
|
|
16
|
+
});
|
|
17
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
18
|
+
if (isOpen) element.setAttribute("aria-modal", "true");
|
|
19
|
+
else element.removeAttribute("aria-modal");
|
|
20
|
+
});
|
|
21
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
22
|
+
if (!isOpen || isFirstRender) return;
|
|
23
|
+
const animation = enter(element);
|
|
24
|
+
updateAnimationQueue(animation);
|
|
25
|
+
return () => {
|
|
26
|
+
if (animation.state !== "finished") animation.complete();
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
createGuardedEffect(() => state.isOpen, (isOpen) => {
|
|
30
|
+
if (isOpen || isFirstRender) return;
|
|
31
|
+
const animation = exit(element);
|
|
32
|
+
updateAnimationQueue(animation);
|
|
33
|
+
return () => {
|
|
34
|
+
if (animation.state !== "finished") animation.complete();
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
onSettled(() => {
|
|
38
|
+
isFirstRender = false;
|
|
39
|
+
});
|
|
40
|
+
function enter(element) {
|
|
41
|
+
const style = window.getComputedStyle(element);
|
|
42
|
+
const transition = getTransitionConfig(style);
|
|
43
|
+
return animate(element, {
|
|
44
|
+
x: [`var(--${Name}--slide-x-from)`, `var(--${Name}--slide-x-to)`],
|
|
45
|
+
y: [`var(--${Name}--slide-y-from)`, `var(--${Name}--slide-y-to)`],
|
|
46
|
+
scaleY: [`var(--${Name}--scale-y-from)`, `var(--${Name}--scale-y-to)`],
|
|
47
|
+
scaleX: [`var(--${Name}--scale-x-from)`, `var(--${Name}--scale-x-to)`],
|
|
48
|
+
opacity: [`var(--${Name}--opacity-from)`, `var(--${Name}--opacity-to)`]
|
|
49
|
+
}, transition);
|
|
50
|
+
}
|
|
51
|
+
function exit(element) {
|
|
52
|
+
const style = window.getComputedStyle(element);
|
|
53
|
+
const transition = getTransitionConfig(style);
|
|
54
|
+
return animate(element, {
|
|
55
|
+
x: [`var(--${Name}--slide-x-to)`, `var(--${Name}--slide-x-from)`],
|
|
56
|
+
y: [`var(--${Name}--slide-y-to)`, `var(--${Name}--slide-y-from)`],
|
|
57
|
+
scaleY: [`var(--${Name}--scale-y-to)`, `var(--${Name}--scale-y-from)`],
|
|
58
|
+
scaleX: [`var(--${Name}--scale-x-to)`, `var(--${Name}--scale-x-from)`],
|
|
59
|
+
opacity: [`var(--${Name}--opacity-to)`, `var(--${Name}--opacity-from)`]
|
|
60
|
+
}, transition);
|
|
61
|
+
}
|
|
69
62
|
};
|
|
70
|
-
|
|
63
|
+
//#endregion
|
|
71
64
|
export { Component, Name };
|
|
72
|
-
|
|
65
|
+
|
|
73
66
|
//# sourceMappingURL=modal-panel.js.map
|