foldkit 0.35.2 → 0.36.1
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/README.md +1 -1
- package/dist/devtools/overlay-styles.d.ts +1 -1
- package/dist/devtools/overlay-styles.d.ts.map +1 -1
- package/dist/devtools/overlay-styles.js +3 -0
- package/dist/devtools/overlay.d.ts.map +1 -1
- package/dist/devtools/overlay.js +10 -5
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +35 -17
- package/dist/runtime/{errorUI.d.ts → crashUI.d.ts} +4 -2
- package/dist/runtime/crashUI.d.ts.map +1 -0
- package/dist/runtime/{errorUI.js → crashUI.js} +8 -8
- package/dist/runtime/public.d.ts +1 -1
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/runtime.d.ts +44 -10
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +261 -203
- package/dist/task/dom.d.ts +5 -1
- package/dist/task/dom.d.ts.map +1 -1
- package/dist/task/dom.js +56 -8
- package/package.json +1 -1
- package/dist/runtime/errorUI.d.ts.map +0 -1
package/dist/task/dom.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { Array, Effect, Equal, Match as M, Number, Option } from 'effect';
|
|
1
|
+
import { Array, Effect, Equal, Function, Match as M, Number, Option, } from 'effect';
|
|
2
2
|
import { ElementNotFound } from './error';
|
|
3
|
+
const BASE_DIALOG_Z_INDEX = 2147483600;
|
|
4
|
+
let openDialogCount = 0;
|
|
5
|
+
const dialogCleanups = new WeakMap();
|
|
3
6
|
const FOCUSABLE_SELECTOR = Array.join([
|
|
4
|
-
'a[href]',
|
|
5
|
-
'button:not([disabled])',
|
|
6
|
-
'input:not([disabled])',
|
|
7
|
-
'select:not([disabled])',
|
|
8
|
-
'textarea:not([disabled])',
|
|
7
|
+
'a[href]:not([tabindex="-1"])',
|
|
8
|
+
'button:not([disabled]):not([tabindex="-1"])',
|
|
9
|
+
'input:not([disabled]):not([tabindex="-1"])',
|
|
10
|
+
'select:not([disabled]):not([tabindex="-1"])',
|
|
11
|
+
'textarea:not([disabled]):not([tabindex="-1"])',
|
|
9
12
|
'[tabindex]:not([tabindex="-1"])',
|
|
10
13
|
], ', ');
|
|
11
14
|
/**
|
|
@@ -31,7 +34,10 @@ export const focus = (selector) => Effect.async(resume => {
|
|
|
31
34
|
});
|
|
32
35
|
});
|
|
33
36
|
/**
|
|
34
|
-
* Opens a dialog element
|
|
37
|
+
* Opens a dialog element using `show()` with high z-index, focus trapping,
|
|
38
|
+
* and Escape key handling. Uses `show()` instead of `showModal()` so that
|
|
39
|
+
* DevTools (and any other high-z-index overlay) remains interactive — the
|
|
40
|
+
* Dialog component provides its own backdrop, scroll locking, and transitions.
|
|
35
41
|
* Uses requestAnimationFrame to ensure the DOM is updated before attempting to show.
|
|
36
42
|
* Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
|
|
37
43
|
*
|
|
@@ -44,7 +50,27 @@ export const showModal = (selector) => Effect.async(resume => {
|
|
|
44
50
|
requestAnimationFrame(() => {
|
|
45
51
|
const element = document.querySelector(selector);
|
|
46
52
|
if (element instanceof HTMLDialogElement) {
|
|
47
|
-
element.
|
|
53
|
+
element.style.position = 'fixed';
|
|
54
|
+
element.style.inset = '0';
|
|
55
|
+
openDialogCount++;
|
|
56
|
+
element.style.zIndex = String(BASE_DIALOG_Z_INDEX + openDialogCount);
|
|
57
|
+
element.show();
|
|
58
|
+
const handleKeydown = (event) => {
|
|
59
|
+
if (!element.open) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
M.value(event.key).pipe(M.when('Escape', () => {
|
|
63
|
+
if (event.defaultPrevented) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
element.dispatchEvent(new Event('cancel', { cancelable: true }));
|
|
68
|
+
}), M.when('Tab', () => {
|
|
69
|
+
trapFocusWithinDialog(event, element);
|
|
70
|
+
}), M.orElse(Function.constVoid));
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener('keydown', handleKeydown);
|
|
73
|
+
dialogCleanups.set(element, () => document.removeEventListener('keydown', handleKeydown));
|
|
48
74
|
resume(Effect.void);
|
|
49
75
|
}
|
|
50
76
|
else {
|
|
@@ -52,8 +78,24 @@ export const showModal = (selector) => Effect.async(resume => {
|
|
|
52
78
|
}
|
|
53
79
|
});
|
|
54
80
|
});
|
|
81
|
+
const trapFocusWithinDialog = (event, dialog) => {
|
|
82
|
+
const focusable = Array.fromIterable(dialog.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
83
|
+
if (Array.isNonEmptyArray(focusable)) {
|
|
84
|
+
const first = Array.headNonEmpty(focusable);
|
|
85
|
+
const last = Array.lastNonEmpty(focusable);
|
|
86
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
last.focus();
|
|
89
|
+
}
|
|
90
|
+
else if (!event.shiftKey && document.activeElement === last) {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
first.focus();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
55
96
|
/**
|
|
56
97
|
* Closes a dialog element using `.close()`.
|
|
98
|
+
* Cleans up the keyboard handlers installed by `showModal`.
|
|
57
99
|
* Uses requestAnimationFrame to ensure the DOM is updated before attempting to close.
|
|
58
100
|
* Fails with `ElementNotFound` if the selector does not match an `HTMLDialogElement`.
|
|
59
101
|
*
|
|
@@ -67,6 +109,12 @@ export const closeModal = (selector) => Effect.async(resume => {
|
|
|
67
109
|
const element = document.querySelector(selector);
|
|
68
110
|
if (element instanceof HTMLDialogElement) {
|
|
69
111
|
element.close();
|
|
112
|
+
openDialogCount = Math.max(0, openDialogCount - 1);
|
|
113
|
+
const cleanup = dialogCleanups.get(element);
|
|
114
|
+
if (cleanup) {
|
|
115
|
+
cleanup();
|
|
116
|
+
dialogCleanups.delete(element);
|
|
117
|
+
}
|
|
70
118
|
resume(Effect.void);
|
|
71
119
|
}
|
|
72
120
|
else {
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errorUI.d.ts","sourceRoot":"","sources":["../../src/runtime/errorUI.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE/B,OAAO,EAAE,IAAI,EAAQ,MAAM,SAAS,CAAA;AAEpC,eAAO,MAAM,YAAY;8BACG,OAAO;6BACR,OAAO;CACjC,CAAA;AAmBD,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,EAAE,YAAY,OAAO,KAAG,IA4LpE,CAAA"}
|