foldkit 0.20.0 → 0.22.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/README.md +2 -1
- package/dist/html/index.d.ts +90 -19
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +36 -6
- package/dist/html/public.d.ts +1 -1
- package/dist/html/public.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/runtime/public.d.ts +2 -2
- package/dist/runtime/public.d.ts.map +1 -1
- package/dist/runtime/public.js +1 -1
- package/dist/runtime/runtime.d.ts +16 -16
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +8 -8
- package/dist/task/dom.d.ts +13 -0
- package/dist/task/dom.d.ts.map +1 -1
- package/dist/task/dom.js +38 -1
- package/dist/task/elementMovement.d.ts +21 -0
- package/dist/task/elementMovement.d.ts.map +1 -0
- package/dist/task/elementMovement.js +48 -0
- package/dist/task/index.d.ts +3 -1
- package/dist/task/index.d.ts.map +1 -1
- package/dist/task/index.js +2 -1
- package/dist/task/scrollLock.d.ts +3 -0
- package/dist/task/scrollLock.d.ts.map +1 -1
- package/dist/task/scrollLock.js +36 -0
- package/dist/ui/dialog/index.d.ts.map +1 -1
- package/dist/ui/dialog/index.js +4 -10
- package/dist/ui/disclosure/index.d.ts.map +1 -1
- package/dist/ui/disclosure/index.js +4 -7
- package/dist/ui/menu/anchor.d.ts +18 -0
- package/dist/ui/menu/anchor.d.ts.map +1 -0
- package/dist/ui/menu/anchor.js +72 -0
- package/dist/ui/menu/index.d.ts +11 -5
- package/dist/ui/menu/index.d.ts.map +1 -1
- package/dist/ui/menu/index.js +45 -38
- package/dist/ui/menu/public.d.ts +1 -0
- package/dist/ui/menu/public.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/task/dom.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { Effect } from 'effect';
|
|
1
|
+
import { Array, Effect, Equal, Match as M, Number, Option } from 'effect';
|
|
2
2
|
import { ElementNotFound } from './error';
|
|
3
|
+
const FOCUSABLE_SELECTOR = Array.join([
|
|
4
|
+
'a[href]',
|
|
5
|
+
'button:not([disabled])',
|
|
6
|
+
'input:not([disabled])',
|
|
7
|
+
'select:not([disabled])',
|
|
8
|
+
'textarea:not([disabled])',
|
|
9
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
10
|
+
], ', ');
|
|
3
11
|
/**
|
|
4
12
|
* Focuses an element matching the given selector.
|
|
5
13
|
* Uses requestAnimationFrame to ensure the DOM is updated before attempting to focus.
|
|
@@ -110,3 +118,32 @@ export const scrollIntoView = (selector) => Effect.async(resume => {
|
|
|
110
118
|
}
|
|
111
119
|
});
|
|
112
120
|
});
|
|
121
|
+
/**
|
|
122
|
+
* Focuses the next or previous focusable element in the document relative to the element matching the given selector.
|
|
123
|
+
* Uses requestAnimationFrame to ensure the DOM is updated before querying focus order.
|
|
124
|
+
* Fails with `ElementNotFound` if the selector does not match an `HTMLElement`.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* Task.advanceFocus('#menu-button', 'Next').pipe(Effect.ignore, Effect.as(NoOp()))
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export const advanceFocus = (selector, direction) => Effect.async(resume => {
|
|
132
|
+
requestAnimationFrame(() => {
|
|
133
|
+
const reference = document.querySelector(selector);
|
|
134
|
+
if (!(reference instanceof HTMLElement)) {
|
|
135
|
+
return resume(Effect.fail(new ElementNotFound({ selector })));
|
|
136
|
+
}
|
|
137
|
+
const focusableElements = Array.fromIterable(document.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
138
|
+
const referenceElementIndex = Array.findFirstIndex(focusableElements, Equal.equals(reference));
|
|
139
|
+
if (Option.isNone(referenceElementIndex)) {
|
|
140
|
+
return resume(Effect.fail(new ElementNotFound({ selector })));
|
|
141
|
+
}
|
|
142
|
+
const offsetReferenceElementIndex = M.value(direction).pipe(M.when('Next', () => Number.increment), M.when('Previous', () => Number.decrement), M.exhaustive)(referenceElementIndex.value);
|
|
143
|
+
const nextElement = Array.get(focusableElements, offsetReferenceElementIndex);
|
|
144
|
+
if (Option.isSome(nextElement)) {
|
|
145
|
+
nextElement.value.focus();
|
|
146
|
+
}
|
|
147
|
+
resume(Effect.void);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
/**
|
|
3
|
+
* Detects if the element matching the given selector moves in the viewport.
|
|
4
|
+
* Snapshots the element's position via `getBoundingClientRect` and watches for
|
|
5
|
+
* changes using a `ResizeObserver` plus window `scroll` and `resize` listeners.
|
|
6
|
+
* Resolves when movement is detected. Falls back to completing immediately if
|
|
7
|
+
* the element is missing.
|
|
8
|
+
*
|
|
9
|
+
* Cleanup runs automatically when the fiber is interrupted (e.g. by
|
|
10
|
+
* `Effect.raceFirst`), removing the observer and event listeners via
|
|
11
|
+
* `AbortSignal`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* Task.detectElementMovement('#menu-button').pipe(
|
|
16
|
+
* Effect.as(DetectedButtonMovement()),
|
|
17
|
+
* )
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare const detectElementMovement: (selector: string) => Effect.Effect<void>;
|
|
21
|
+
//# sourceMappingURL=elementMovement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elementMovement.d.ts","sourceRoot":"","sources":["../../src/task/elementMovement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAI/B;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAqCvE,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
const rectToPosition = (rect) => `${rect.x},${rect.y}`;
|
|
3
|
+
/**
|
|
4
|
+
* Detects if the element matching the given selector moves in the viewport.
|
|
5
|
+
* Snapshots the element's position via `getBoundingClientRect` and watches for
|
|
6
|
+
* changes using a `ResizeObserver` plus window `scroll` and `resize` listeners.
|
|
7
|
+
* Resolves when movement is detected. Falls back to completing immediately if
|
|
8
|
+
* the element is missing.
|
|
9
|
+
*
|
|
10
|
+
* Cleanup runs automatically when the fiber is interrupted (e.g. by
|
|
11
|
+
* `Effect.raceFirst`), removing the observer and event listeners via
|
|
12
|
+
* `AbortSignal`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* Task.detectElementMovement('#menu-button').pipe(
|
|
17
|
+
* Effect.as(DetectedButtonMovement()),
|
|
18
|
+
* )
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export const detectElementMovement = (selector) => Effect.async((resume, signal) => {
|
|
22
|
+
requestAnimationFrame(() => {
|
|
23
|
+
if (signal.aborted) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const element = document.querySelector(selector);
|
|
27
|
+
if (!(element instanceof HTMLElement)) {
|
|
28
|
+
return resume(Effect.void);
|
|
29
|
+
}
|
|
30
|
+
const initialPosition = rectToPosition(element.getBoundingClientRect());
|
|
31
|
+
const cleanup = () => {
|
|
32
|
+
observer.disconnect();
|
|
33
|
+
window.removeEventListener('scroll', check, { capture: true });
|
|
34
|
+
window.removeEventListener('resize', check);
|
|
35
|
+
};
|
|
36
|
+
const check = () => {
|
|
37
|
+
if (rectToPosition(element.getBoundingClientRect()) !== initialPosition) {
|
|
38
|
+
cleanup();
|
|
39
|
+
resume(Effect.void);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const observer = new ResizeObserver(check);
|
|
43
|
+
observer.observe(element);
|
|
44
|
+
window.addEventListener('scroll', check, { passive: true, capture: true });
|
|
45
|
+
window.addEventListener('resize', check);
|
|
46
|
+
signal.addEventListener('abort', cleanup);
|
|
47
|
+
});
|
|
48
|
+
});
|
package/dist/task/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { ElementNotFound, TimeZoneError } from './error';
|
|
2
2
|
export { getTime, getTimeZone, getZonedTime, getZonedTimeIn } from './time';
|
|
3
|
-
export { focus, showModal, closeModal, clickElement, scrollIntoView, } from './dom';
|
|
3
|
+
export { advanceFocus, focus, showModal, closeModal, clickElement, scrollIntoView, } from './dom';
|
|
4
|
+
export type { FocusDirection } from './dom';
|
|
5
|
+
export { detectElementMovement } from './elementMovement';
|
|
4
6
|
export { delay, nextFrame, waitForTransitions } from './timing';
|
|
5
7
|
export { randomInt } from './random';
|
|
6
8
|
export { lockScroll, unlockScroll } from './scrollLock';
|
package/dist/task/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAC3E,OAAO,EACL,KAAK,EACL,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAC3E,OAAO,EACL,YAAY,EACZ,KAAK,EACL,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,OAAO,CAAA;AACd,YAAY,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/task/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ElementNotFound, TimeZoneError } from './error';
|
|
2
2
|
export { getTime, getTimeZone, getZonedTime, getZonedTimeIn } from './time';
|
|
3
|
-
export { focus, showModal, closeModal, clickElement, scrollIntoView, } from './dom';
|
|
3
|
+
export { advanceFocus, focus, showModal, closeModal, clickElement, scrollIntoView, } from './dom';
|
|
4
|
+
export { detectElementMovement } from './elementMovement';
|
|
4
5
|
export { delay, nextFrame, waitForTransitions } from './timing';
|
|
5
6
|
export { randomInt } from './random';
|
|
6
7
|
export { lockScroll, unlockScroll } from './scrollLock';
|
|
@@ -2,6 +2,8 @@ import { Effect } from 'effect';
|
|
|
2
2
|
/**
|
|
3
3
|
* Locks page scroll by setting `overflow: hidden` on the document element.
|
|
4
4
|
* Compensates for scrollbar width with padding to prevent layout shift.
|
|
5
|
+
* On iOS Safari, intercepts `touchmove` events to prevent page scroll
|
|
6
|
+
* while allowing scrolling within overflow containers.
|
|
5
7
|
* Uses reference counting so nested locks are safe — the page only unlocks
|
|
6
8
|
* when every lock has been released.
|
|
7
9
|
*
|
|
@@ -14,6 +16,7 @@ export declare const lockScroll: Effect.Effect<void>;
|
|
|
14
16
|
/**
|
|
15
17
|
* Releases one scroll lock. When the last lock is released, restores the
|
|
16
18
|
* original `overflow` and `padding-right` on the document element.
|
|
19
|
+
* On iOS Safari, removes the `touchmove` listener.
|
|
17
20
|
*
|
|
18
21
|
* @example
|
|
19
22
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrollLock.d.ts","sourceRoot":"","sources":["../../src/task/scrollLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"scrollLock.d.ts","sourceRoot":"","sources":["../../src/task/scrollLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAuCvC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAwBzC,CAAA;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAW3C,CAAA"}
|
package/dist/task/scrollLock.js
CHANGED
|
@@ -4,9 +4,38 @@ const scrollLockState = {
|
|
|
4
4
|
overflow: '',
|
|
5
5
|
paddingRight: '',
|
|
6
6
|
};
|
|
7
|
+
const isIOS = () => {
|
|
8
|
+
const { platform, maxTouchPoints } = window.navigator;
|
|
9
|
+
const isIPhone = /iPhone/gi.test(platform);
|
|
10
|
+
const isIPad = /Mac/gi.test(platform) && maxTouchPoints > 0;
|
|
11
|
+
return isIPhone || isIPad;
|
|
12
|
+
};
|
|
13
|
+
const isScrollableElement = (element) => {
|
|
14
|
+
const style = window.getComputedStyle(element);
|
|
15
|
+
const overflowY = style.overflowY;
|
|
16
|
+
const isOverflowable = overflowY === 'auto' || overflowY === 'scroll';
|
|
17
|
+
return isOverflowable && element.scrollHeight > element.clientHeight;
|
|
18
|
+
};
|
|
19
|
+
const findScrollableParent = (target) => {
|
|
20
|
+
let current = target;
|
|
21
|
+
while (current && current !== document.documentElement) {
|
|
22
|
+
if (isScrollableElement(current)) {
|
|
23
|
+
return current;
|
|
24
|
+
}
|
|
25
|
+
current = current.parentElement;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
const handleTouchMove = (event) => {
|
|
30
|
+
if (event.target instanceof Element && !findScrollableParent(event.target)) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
7
34
|
/**
|
|
8
35
|
* Locks page scroll by setting `overflow: hidden` on the document element.
|
|
9
36
|
* Compensates for scrollbar width with padding to prevent layout shift.
|
|
37
|
+
* On iOS Safari, intercepts `touchmove` events to prevent page scroll
|
|
38
|
+
* while allowing scrolling within overflow containers.
|
|
10
39
|
* Uses reference counting so nested locks are safe — the page only unlocks
|
|
11
40
|
* when every lock has been released.
|
|
12
41
|
*
|
|
@@ -24,12 +53,18 @@ export const lockScroll = Effect.sync(() => {
|
|
|
24
53
|
style.overflow = 'hidden';
|
|
25
54
|
style.paddingRight =
|
|
26
55
|
scrollbarWidth > 0 ? `${scrollbarWidth}px` : style.paddingRight;
|
|
56
|
+
if (isIOS()) {
|
|
57
|
+
document.addEventListener('touchmove', handleTouchMove, {
|
|
58
|
+
passive: false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
27
61
|
}
|
|
28
62
|
scrollLockState.count++;
|
|
29
63
|
});
|
|
30
64
|
/**
|
|
31
65
|
* Releases one scroll lock. When the last lock is released, restores the
|
|
32
66
|
* original `overflow` and `padding-right` on the document element.
|
|
67
|
+
* On iOS Safari, removes the `touchmove` listener.
|
|
33
68
|
*
|
|
34
69
|
* @example
|
|
35
70
|
* ```typescript
|
|
@@ -42,5 +77,6 @@ export const unlockScroll = Effect.sync(() => {
|
|
|
42
77
|
const { documentElement: { style }, } = document;
|
|
43
78
|
style.overflow = scrollLockState.overflow;
|
|
44
79
|
style.paddingRight = scrollLockState.paddingRight;
|
|
80
|
+
document.removeEventListener('touchmove', handleTouchMove);
|
|
45
81
|
}
|
|
46
82
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAOtC,8FAA8F;AAC9F,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,wEAAwE;AACxE,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,wHAAwH;AACxH,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,oHAAoH;AACpH,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,0LAAgC,CAAA;AAEpD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,yEAAyE;AACzE,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAMF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAOtC,8FAA8F;AAC9F,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,wEAAwE;AACxE,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,wHAAwH;AACxH,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,oHAAoH;AACpH,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,8DAA8D;AAC9D,eAAO,MAAM,OAAO,0LAAgC,CAAA;AAEpD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,6DAA6D;AAC7D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,yEAAyE;AACzE,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAMF,0EAA0E;AAC1E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA4BvC,CAAA;AAIH,iGAAiG;AACjG,eAAO,MAAM,OAAO,GAAI,OAAO,KAAK,KAAG,MAA6B,CAAA;AAEpE,wGAAwG;AACxG,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,MAAmC,CAAA;AAEhF,wDAAwD;AACxD,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IAC9C,YAAY,EAAE,IAAI,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,sGAAsG;AACtG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IA6C3D,CAAA"}
|
package/dist/ui/dialog/index.js
CHANGED
|
@@ -28,18 +28,12 @@ const dialogSelector = (id) => `#${id}`;
|
|
|
28
28
|
/** Processes a dialog message and returns the next model and commands. */
|
|
29
29
|
export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
|
|
30
30
|
Opened: () => {
|
|
31
|
-
const
|
|
32
|
-
return [
|
|
33
|
-
evo(model, { isOpen: () => true }),
|
|
34
|
-
Option.toArray(maybeShowCommand),
|
|
35
|
-
];
|
|
31
|
+
const maybeShow = Option.liftPredicate(Task.showModal(dialogSelector(model.id)).pipe(Effect.ignore, Effect.as(NoOp())), () => !model.isOpen);
|
|
32
|
+
return [evo(model, { isOpen: () => true }), Option.toArray(maybeShow)];
|
|
36
33
|
},
|
|
37
34
|
Closed: () => {
|
|
38
|
-
const
|
|
39
|
-
return [
|
|
40
|
-
evo(model, { isOpen: () => false }),
|
|
41
|
-
Option.toArray(maybeCloseCommand),
|
|
42
|
-
];
|
|
35
|
+
const maybeClose = Option.liftPredicate(Task.closeModal(dialogSelector(model.id)).pipe(Effect.ignore, Effect.as(NoOp())), () => model.isOpen);
|
|
36
|
+
return [evo(model, { isOpen: () => false }), Option.toArray(maybeClose)];
|
|
43
37
|
},
|
|
44
38
|
NoOp: () => [model, []],
|
|
45
39
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAO/C,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,gFAAgF;AAChF,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,kGAAkG;AAClG,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,kEAAkE;AAClE,eAAO,MAAM,OAAO,2LAAiC,CAAA;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAQF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/disclosure/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAO/C,kGAAkG;AAClG,eAAO,MAAM,KAAK;;;EAGhB,CAAA;AAEF,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAIrC,iFAAiF;AACjF,eAAO,MAAM,OAAO,4DAAe,CAAA;AACnC,gFAAgF;AAChF,eAAO,MAAM,MAAM,2DAAc,CAAA;AACjC,kGAAkG;AAClG,eAAO,MAAM,IAAI,yDAAY,CAAA;AAE7B,kEAAkE;AAClE,eAAO,MAAM,OAAO,2LAAiC,CAAA;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AACzC,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,CAAA;AAEnC,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAIzC,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GAAI,QAAQ,UAAU,KAAG,KAGxC,CAAA;AAQF,8EAA8E;AAC9E,eAAO,MAAM,MAAM,GACjB,OAAO,KAAK,EACZ,SAAS,OAAO,KACf,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA+BvC,CAAA;AAIH,4DAA4D;AAC5D,MAAM,MAAM,UAAU,CAAC,OAAO,IAAI,QAAQ,CAAC;IACzC,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,KAAK,OAAO,CAAA;IACxD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,IAAI,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,IAAI,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAC,CAAA;AAEF,oGAAoG;AACpG,eAAO,MAAM,IAAI,GAAI,OAAO,EAAE,QAAQ,UAAU,CAAC,OAAO,CAAC,KAAG,IAyF3D,CAAA"}
|
|
@@ -29,18 +29,15 @@ const panelId = (id) => `${id}-panel`;
|
|
|
29
29
|
/** Processes a disclosure message and returns the next model and commands. */
|
|
30
30
|
export const update = (model, message) => M.value(message).pipe(M.withReturnType(), M.tagsExhaustive({
|
|
31
31
|
Toggled: () => {
|
|
32
|
-
const
|
|
32
|
+
const maybeFocus = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`).pipe(Effect.ignore, Effect.as(NoOp())), () => model.isOpen);
|
|
33
33
|
return [
|
|
34
34
|
evo(model, { isOpen: () => !model.isOpen }),
|
|
35
|
-
Option.toArray(
|
|
35
|
+
Option.toArray(maybeFocus),
|
|
36
36
|
];
|
|
37
37
|
},
|
|
38
38
|
Closed: () => {
|
|
39
|
-
const
|
|
40
|
-
return [
|
|
41
|
-
evo(model, { isOpen: () => false }),
|
|
42
|
-
Option.toArray(maybeFocusCommand),
|
|
43
|
-
];
|
|
39
|
+
const maybeFocus = Option.liftPredicate(Task.focus(`#${buttonId(model.id)}`).pipe(Effect.ignore, Effect.as(NoOp())), () => model.isOpen);
|
|
40
|
+
return [evo(model, { isOpen: () => false }), Option.toArray(maybeFocus)];
|
|
44
41
|
},
|
|
45
42
|
NoOp: () => [model, []],
|
|
46
43
|
}));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Placement } from '@floating-ui/dom';
|
|
2
|
+
/** Static configuration for anchor-based positioning of menu items relative to the button. */
|
|
3
|
+
export type AnchorConfig = Readonly<{
|
|
4
|
+
placement?: Placement;
|
|
5
|
+
gap?: number;
|
|
6
|
+
offset?: number;
|
|
7
|
+
padding?: number;
|
|
8
|
+
portal?: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
/** Returns insert/destroy hook callbacks that position the menu items container relative to its button using Floating UI. */
|
|
11
|
+
export declare const anchorHooks: (config: {
|
|
12
|
+
buttonId: string;
|
|
13
|
+
anchor: AnchorConfig;
|
|
14
|
+
}) => Readonly<{
|
|
15
|
+
onInsert: (items: Element) => void;
|
|
16
|
+
onDestroy: (items: Element) => void;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=anchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../../src/ui/menu/anchor.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,8FAA8F;AAC9F,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAC,CAAA;AAmBF,6HAA6H;AAC7H,eAAO,MAAM,WAAW,GAAI,QAAQ;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,YAAY,CAAA;CACrB,KAAG,QAAQ,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC,CAsEC,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { autoUpdate, computePosition, flip, offset as floatingOffset, shift, size, } from '@floating-ui/dom';
|
|
2
|
+
const PORTAL_ROOT_ID = 'foldkit-portal-root';
|
|
3
|
+
const getOrCreatePortalRoot = () => {
|
|
4
|
+
const existing = document.getElementById(PORTAL_ROOT_ID);
|
|
5
|
+
if (existing) {
|
|
6
|
+
return existing;
|
|
7
|
+
}
|
|
8
|
+
const root = document.createElement('div');
|
|
9
|
+
root.id = PORTAL_ROOT_ID;
|
|
10
|
+
return document.body.appendChild(root);
|
|
11
|
+
};
|
|
12
|
+
const anchorCleanups = new WeakMap();
|
|
13
|
+
/** Returns insert/destroy hook callbacks that position the menu items container relative to its button using Floating UI. */
|
|
14
|
+
export const anchorHooks = (config) => ({
|
|
15
|
+
onInsert: (items) => {
|
|
16
|
+
const button = document.getElementById(config.buttonId);
|
|
17
|
+
if (!(button instanceof HTMLElement) || !(items instanceof HTMLElement)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const isPortal = config.anchor.portal ?? true;
|
|
21
|
+
if (isPortal) {
|
|
22
|
+
getOrCreatePortalRoot().appendChild(items);
|
|
23
|
+
}
|
|
24
|
+
const { placement, gap, offset: crossAxis, padding } = config.anchor;
|
|
25
|
+
let isFirstUpdate = true;
|
|
26
|
+
const floatingCleanup = autoUpdate(button, items, () => {
|
|
27
|
+
computePosition(button, items, {
|
|
28
|
+
placement: placement ?? 'bottom-start',
|
|
29
|
+
strategy: 'absolute',
|
|
30
|
+
middleware: [
|
|
31
|
+
floatingOffset({
|
|
32
|
+
mainAxis: gap ?? 0,
|
|
33
|
+
crossAxis: crossAxis ?? 0,
|
|
34
|
+
}),
|
|
35
|
+
flip({ padding: padding ?? 0 }),
|
|
36
|
+
shift({ padding: padding ?? 0 }),
|
|
37
|
+
size({
|
|
38
|
+
apply({ rects }) {
|
|
39
|
+
items.style.setProperty('--button-width', `${rects.reference.width}px`);
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
}).then(({ x, y }) => {
|
|
44
|
+
items.style.left = `${x}px`;
|
|
45
|
+
items.style.top = `${y}px`;
|
|
46
|
+
if (isFirstUpdate) {
|
|
47
|
+
isFirstUpdate = false;
|
|
48
|
+
items.style.visibility = '';
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
if (isPortal) {
|
|
53
|
+
const handleTabKey = (event) => {
|
|
54
|
+
if (event instanceof KeyboardEvent && event.key === 'Tab') {
|
|
55
|
+
button.focus();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
items.addEventListener('keydown', handleTabKey);
|
|
59
|
+
anchorCleanups.set(items, () => {
|
|
60
|
+
floatingCleanup();
|
|
61
|
+
items.removeEventListener('keydown', handleTabKey);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
anchorCleanups.set(items, floatingCleanup);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
onDestroy: (items) => {
|
|
69
|
+
anchorCleanups.get(items)?.();
|
|
70
|
+
anchorCleanups.delete(items);
|
|
71
|
+
},
|
|
72
|
+
});
|
package/dist/ui/menu/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Option, Schema as S } from 'effect';
|
|
2
2
|
import type { Command } from '../../command';
|
|
3
|
-
import type
|
|
3
|
+
import { type Html } from '../../html';
|
|
4
|
+
import type { AnchorConfig } from './anchor';
|
|
4
5
|
/** Schema for the activation trigger — whether the user interacted via mouse or keyboard. */
|
|
5
6
|
export declare const ActivationTrigger: S.Literal<["Pointer", "Keyboard"]>;
|
|
6
7
|
export type ActivationTrigger = typeof ActivationTrigger.Type;
|
|
@@ -36,7 +37,7 @@ export declare const Opened: import("../../schema").CallableTaggedStruct<"Opened
|
|
|
36
37
|
}>;
|
|
37
38
|
/** Sent when the menu closes via Escape key or backdrop click. */
|
|
38
39
|
export declare const Closed: import("../../schema").CallableTaggedStruct<"Closed", {}>;
|
|
39
|
-
/** Sent when focus leaves the menu items container via Tab key. */
|
|
40
|
+
/** Sent when focus leaves the menu items container via Tab key or blur. */
|
|
40
41
|
export declare const ClosedByTab: import("../../schema").CallableTaggedStruct<"ClosedByTab", {}>;
|
|
41
42
|
/** Sent when an item is highlighted via arrow keys or mouse hover. Includes activation trigger. */
|
|
42
43
|
export declare const ActivatedItem: import("../../schema").CallableTaggedStruct<"ActivatedItem", {
|
|
@@ -74,6 +75,8 @@ export declare const NoOp: import("../../schema").CallableTaggedStruct<"NoOp", {
|
|
|
74
75
|
export declare const AdvancedTransitionFrame: import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>;
|
|
75
76
|
/** Sent internally when all CSS transitions on the menu items container have completed. */
|
|
76
77
|
export declare const EndedTransition: import("../../schema").CallableTaggedStruct<"EndedTransition", {}>;
|
|
78
|
+
/** Sent internally when the menu button moves in the viewport during a leave transition, cancelling the animation. */
|
|
79
|
+
export declare const DetectedButtonMovement: import("../../schema").CallableTaggedStruct<"DetectedButtonMovement", {}>;
|
|
77
80
|
/** Sent when the user presses a pointer device on the menu button. Records pointer type and toggles for mouse. */
|
|
78
81
|
export declare const PressedPointerOnButton: import("../../schema").CallableTaggedStruct<"PressedPointerOnButton", {
|
|
79
82
|
pointerType: typeof S.String;
|
|
@@ -107,7 +110,7 @@ export declare const Message: S.Union<[import("../../schema").CallableTaggedStru
|
|
|
107
110
|
maybeTargetIndex: S.OptionFromSelf<typeof S.Number>;
|
|
108
111
|
}>, import("../../schema").CallableTaggedStruct<"ClearedSearch", {
|
|
109
112
|
version: typeof S.Number;
|
|
110
|
-
}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>, import("../../schema").CallableTaggedStruct<"PressedPointerOnButton", {
|
|
113
|
+
}>, import("../../schema").CallableTaggedStruct<"NoOp", {}>, import("../../schema").CallableTaggedStruct<"AdvancedTransitionFrame", {}>, import("../../schema").CallableTaggedStruct<"EndedTransition", {}>, import("../../schema").CallableTaggedStruct<"DetectedButtonMovement", {}>, import("../../schema").CallableTaggedStruct<"PressedPointerOnButton", {
|
|
111
114
|
pointerType: typeof S.String;
|
|
112
115
|
button: typeof S.Number;
|
|
113
116
|
screenX: typeof S.Number;
|
|
@@ -131,10 +134,11 @@ export type ClearedSearch = typeof ClearedSearch.Type;
|
|
|
131
134
|
export type NoOp = typeof NoOp.Type;
|
|
132
135
|
export type AdvancedTransitionFrame = typeof AdvancedTransitionFrame.Type;
|
|
133
136
|
export type EndedTransition = typeof EndedTransition.Type;
|
|
137
|
+
export type DetectedButtonMovement = typeof DetectedButtonMovement.Type;
|
|
134
138
|
export type PressedPointerOnButton = typeof PressedPointerOnButton.Type;
|
|
135
139
|
export type ReleasedPointerOnItems = typeof ReleasedPointerOnItems.Type;
|
|
136
140
|
export type Message = typeof Message.Type;
|
|
137
|
-
/** Configuration for creating a menu model with `init`. `isAnimated` enables CSS transition coordination (default `false`). `isModal` locks page scroll and inerts other elements when open (default `
|
|
141
|
+
/** Configuration for creating a menu model with `init`. `isAnimated` enables CSS transition coordination (default `false`). `isModal` locks page scroll and inerts other elements when open (default `false`). */
|
|
138
142
|
export type InitConfig = Readonly<{
|
|
139
143
|
id: string;
|
|
140
144
|
isAnimated?: boolean;
|
|
@@ -142,8 +146,9 @@ export type InitConfig = Readonly<{
|
|
|
142
146
|
}>;
|
|
143
147
|
/** Creates an initial menu model from a config. Defaults to closed with no active item. */
|
|
144
148
|
export declare const init: (config: InitConfig) => Model;
|
|
149
|
+
type UpdateReturn = [Model, ReadonlyArray<Command<Message>>];
|
|
145
150
|
/** Processes a menu message and returns the next model and commands. */
|
|
146
|
-
export declare const update: (model: Model, message: Message) =>
|
|
151
|
+
export declare const update: (model: Model, message: Message) => UpdateReturn;
|
|
147
152
|
/** Configuration for an individual menu item's appearance. */
|
|
148
153
|
export type ItemConfig = Readonly<{
|
|
149
154
|
className: string;
|
|
@@ -175,6 +180,7 @@ export type ViewConfig<Message, Item extends string> = Readonly<{
|
|
|
175
180
|
groupToHeading?: (groupKey: string) => GroupHeading | undefined;
|
|
176
181
|
groupClassName?: string;
|
|
177
182
|
separatorClassName?: string;
|
|
183
|
+
anchor?: AnchorConfig;
|
|
178
184
|
}>;
|
|
179
185
|
type Segment<A> = Readonly<{
|
|
180
186
|
key: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/menu/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,MAAM,EACN,MAAM,IAAI,CAAC,EAGZ,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/menu/index.ts"],"names":[],"mappings":"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"}
|