foldkit-primitives 0.15.3 → 0.16.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/device/fullscreen.d.ts +28 -0
- package/dist/device/fullscreen.d.ts.map +1 -0
- package/dist/device/fullscreen.js +69 -0
- package/dist/device/fullscreen.js.map +1 -0
- package/dist/device/geolocation.d.ts +56 -0
- package/dist/device/geolocation.d.ts.map +1 -0
- package/dist/device/geolocation.js +87 -0
- package/dist/device/geolocation.js.map +1 -0
- package/dist/device/index.d.ts +5 -0
- package/dist/device/index.js +6 -0
- package/dist/device/media-devices.d.ts +88 -0
- package/dist/device/media-devices.d.ts.map +1 -0
- package/dist/device/media-devices.js +117 -0
- package/dist/device/media-devices.js.map +1 -0
- package/dist/device/media-stream.d.ts +93 -0
- package/dist/device/media-stream.d.ts.map +1 -0
- package/dist/device/media-stream.js +106 -0
- package/dist/device/media-stream.js.map +1 -0
- package/dist/device/permissions.d.ts +106 -0
- package/dist/device/permissions.d.ts.map +1 -0
- package/dist/device/permissions.js +143 -0
- package/dist/device/permissions.js.map +1 -0
- package/dist/dom/autofocus.d.ts +15 -0
- package/dist/dom/autofocus.d.ts.map +1 -0
- package/dist/dom/autofocus.js +22 -0
- package/dist/dom/autofocus.js.map +1 -0
- package/dist/dom/clipboard.d.ts +30 -0
- package/dist/dom/clipboard.d.ts.map +1 -0
- package/dist/dom/clipboard.js +50 -0
- package/dist/dom/clipboard.js.map +1 -0
- package/dist/dom/editable-text.d.ts +72 -0
- package/dist/dom/editable-text.d.ts.map +1 -0
- package/dist/dom/editable-text.js +232 -0
- package/dist/dom/editable-text.js.map +1 -0
- package/dist/dom/fluid-hover.d.ts +93 -0
- package/dist/dom/fluid-hover.d.ts.map +1 -0
- package/dist/dom/fluid-hover.js +294 -0
- package/dist/dom/fluid-hover.js.map +1 -0
- package/dist/dom/focus-scope.d.ts +21 -0
- package/dist/dom/focus-scope.d.ts.map +1 -0
- package/dist/dom/focus-scope.js +93 -0
- package/dist/dom/focus-scope.js.map +1 -0
- package/dist/dom/follow-tab-stop.d.ts +11 -0
- package/dist/dom/follow-tab-stop.d.ts.map +1 -0
- package/dist/dom/follow-tab-stop.js +54 -0
- package/dist/dom/follow-tab-stop.js.map +1 -0
- package/dist/dom/image-decode.d.ts +27 -0
- package/dist/dom/image-decode.d.ts.map +1 -0
- package/dist/dom/image-decode.js +50 -0
- package/dist/dom/image-decode.js.map +1 -0
- package/dist/dom/index.d.ts +24 -0
- package/dist/dom/index.js +25 -0
- package/dist/dom/input-mask.d.ts +35 -0
- package/dist/dom/input-mask.d.ts.map +1 -0
- package/dist/dom/input-mask.js +90 -0
- package/dist/dom/input-mask.js.map +1 -0
- package/dist/dom/keep-in-view.d.ts +16 -0
- package/dist/dom/keep-in-view.d.ts.map +1 -0
- package/dist/dom/keep-in-view.js +38 -0
- package/dist/dom/keep-in-view.js.map +1 -0
- package/dist/dom/keyboard-inset.d.ts +29 -0
- package/dist/dom/keyboard-inset.d.ts.map +1 -0
- package/dist/dom/keyboard-inset.js +45 -0
- package/dist/dom/keyboard-inset.js.map +1 -0
- package/dist/dom/layers.d.ts +6 -0
- package/dist/dom/layers.d.ts.map +1 -0
- package/dist/dom/layers.js +35 -0
- package/dist/dom/layers.js.map +1 -0
- package/dist/dom/measure.d.ts +42 -0
- package/dist/dom/measure.d.ts.map +1 -0
- package/dist/dom/measure.js +123 -0
- package/dist/dom/measure.js.map +1 -0
- package/dist/dom/move.d.ts +45 -0
- package/dist/dom/move.d.ts.map +1 -0
- package/dist/dom/move.js +96 -0
- package/dist/dom/move.js.map +1 -0
- package/dist/dom/pointed-links.d.ts +13 -0
- package/dist/dom/pointed-links.d.ts.map +1 -0
- package/dist/dom/pointed-links.js +59 -0
- package/dist/dom/pointed-links.js.map +1 -0
- package/dist/dom/pointer-drag.d.ts +132 -0
- package/dist/dom/pointer-drag.d.ts.map +1 -0
- package/dist/dom/pointer-drag.js +307 -0
- package/dist/dom/pointer-drag.js.map +1 -0
- package/dist/dom/pointer-position.d.ts +133 -0
- package/dist/dom/pointer-position.d.ts.map +1 -0
- package/dist/dom/pointer-position.js +173 -0
- package/dist/dom/pointer-position.js.map +1 -0
- package/dist/dom/script-loader.d.ts +12 -0
- package/dist/dom/script-loader.d.ts.map +1 -0
- package/dist/dom/script-loader.js +54 -0
- package/dist/dom/script-loader.js.map +1 -0
- package/dist/dom/scroll-bars.d.ts +52 -0
- package/dist/dom/scroll-bars.d.ts.map +1 -0
- package/dist/dom/scroll-bars.js +259 -0
- package/dist/dom/scroll-bars.js.map +1 -0
- package/dist/dom/scroll-settle.d.ts +33 -0
- package/dist/dom/scroll-settle.d.ts.map +1 -0
- package/dist/dom/scroll-settle.js +84 -0
- package/dist/dom/scroll-settle.js.map +1 -0
- package/dist/dom/scroll.d.ts +21 -0
- package/dist/dom/scroll.d.ts.map +1 -0
- package/dist/dom/scroll.js +141 -0
- package/dist/dom/scroll.js.map +1 -0
- package/dist/dom/share.d.ts +19 -0
- package/dist/dom/share.d.ts.map +1 -0
- package/dist/dom/share.js +41 -0
- package/dist/dom/share.js.map +1 -0
- package/dist/dom/swipe.d.ts +121 -0
- package/dist/dom/swipe.d.ts.map +1 -0
- package/dist/dom/swipe.js +291 -0
- package/dist/dom/swipe.js.map +1 -0
- package/dist/dom/targets.d.ts +45 -0
- package/dist/dom/targets.d.ts.map +1 -0
- package/dist/dom/targets.js +70 -0
- package/dist/dom/targets.js.map +1 -0
- package/dist/dom/track-box.d.ts +61 -0
- package/dist/dom/track-box.d.ts.map +1 -0
- package/dist/dom/track-box.js +131 -0
- package/dist/dom/track-box.js.map +1 -0
- package/dist/events/active-element.d.ts +15 -0
- package/dist/events/active-element.d.ts.map +1 -0
- package/dist/events/active-element.js +33 -0
- package/dist/events/active-element.js.map +1 -0
- package/dist/events/hotkeys.d.ts +22 -0
- package/dist/events/hotkeys.d.ts.map +1 -0
- package/dist/events/hotkeys.js +56 -0
- package/dist/events/hotkeys.js.map +1 -0
- package/dist/events/idle.d.ts +29 -0
- package/dist/events/idle.d.ts.map +1 -0
- package/dist/events/idle.js +51 -0
- package/dist/events/idle.js.map +1 -0
- package/dist/events/index.d.ts +9 -0
- package/dist/events/index.js +10 -0
- package/dist/{input-modality-BY-bSrEc.d.mts → events/input-modality.d.ts} +9 -12
- package/dist/events/input-modality.d.ts.map +1 -0
- package/dist/{input-modality-BXD383jg.mjs → events/input-modality.js} +3 -4
- package/dist/events/input-modality.js.map +1 -0
- package/dist/events/keyboard.d.ts +30 -0
- package/dist/events/keyboard.d.ts.map +1 -0
- package/dist/events/keyboard.js +55 -0
- package/dist/events/keyboard.js.map +1 -0
- package/dist/events/pointer.d.ts +15 -0
- package/dist/events/pointer.d.ts.map +1 -0
- package/dist/events/pointer.js +28 -0
- package/dist/events/pointer.js.map +1 -0
- package/dist/events/scroll.d.ts +16 -0
- package/dist/events/scroll.d.ts.map +1 -0
- package/dist/events/scroll.js +29 -0
- package/dist/events/scroll.js.map +1 -0
- package/dist/events/visibility.d.ts +25 -0
- package/dist/events/visibility.d.ts.map +1 -0
- package/dist/events/visibility.js +28 -0
- package/dist/events/visibility.js.map +1 -0
- package/dist/events/window-size.d.ts +30 -0
- package/dist/events/window-size.d.ts.map +1 -0
- package/dist/events/window-size.js +63 -0
- package/dist/events/window-size.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/dist/interaction/bundle-behavior.d.ts +37 -0
- package/dist/interaction/bundle-behavior.d.ts.map +1 -0
- package/dist/interaction/bundle-behavior.js +34 -0
- package/dist/interaction/bundle-behavior.js.map +1 -0
- package/dist/interaction/dismiss-layer.d.ts +100 -0
- package/dist/interaction/dismiss-layer.d.ts.map +1 -0
- package/dist/interaction/dismiss-layer.js +140 -0
- package/dist/interaction/dismiss-layer.js.map +1 -0
- package/dist/interaction/editable-text.d.ts +13 -0
- package/dist/interaction/editable-text.d.ts.map +1 -0
- package/dist/interaction/editable-text.js +17 -0
- package/dist/interaction/editable-text.js.map +1 -0
- package/dist/interaction/focus-scope.d.ts +21 -0
- package/dist/interaction/focus-scope.d.ts.map +1 -0
- package/dist/interaction/focus-scope.js +25 -0
- package/dist/interaction/focus-scope.js.map +1 -0
- package/dist/interaction/focus-visible.d.ts +9 -0
- package/dist/interaction/focus-visible.d.ts.map +1 -0
- package/dist/interaction/focus-visible.js +10 -0
- package/dist/interaction/focus-visible.js.map +1 -0
- package/dist/interaction/grid-navigation.d.ts +73 -0
- package/dist/interaction/grid-navigation.d.ts.map +1 -0
- package/dist/interaction/grid-navigation.js +137 -0
- package/dist/interaction/grid-navigation.js.map +1 -0
- package/dist/interaction/index.d.ts +21 -0
- package/dist/interaction/index.js +21 -0
- package/dist/interaction/layers.d.ts +12 -0
- package/dist/interaction/layers.d.ts.map +1 -0
- package/dist/interaction/layers.js +14 -0
- package/dist/interaction/layers.js.map +1 -0
- package/dist/interaction/list-navigation.d.ts +105 -0
- package/dist/interaction/list-navigation.d.ts.map +1 -0
- package/dist/interaction/list-navigation.js +168 -0
- package/dist/interaction/list-navigation.js.map +1 -0
- package/dist/interaction/live-announce.d.ts +70 -0
- package/dist/interaction/live-announce.d.ts.map +1 -0
- package/dist/interaction/live-announce.js +115 -0
- package/dist/interaction/live-announce.js.map +1 -0
- package/dist/interaction/long-press.d.ts +102 -0
- package/dist/interaction/long-press.d.ts.map +1 -0
- package/dist/interaction/long-press.js +115 -0
- package/dist/interaction/long-press.js.map +1 -0
- package/dist/interaction/move.d.ts +10 -0
- package/dist/interaction/move.d.ts.map +1 -0
- package/dist/interaction/move.js +17 -0
- package/dist/interaction/move.js.map +1 -0
- package/dist/interaction/overlay.d.ts +45 -0
- package/dist/interaction/overlay.d.ts.map +1 -0
- package/dist/interaction/overlay.js +57 -0
- package/dist/interaction/overlay.js.map +1 -0
- package/dist/interaction/placing.d.ts +86 -0
- package/dist/interaction/placing.d.ts.map +1 -0
- package/dist/interaction/placing.js +239 -0
- package/dist/interaction/placing.js.map +1 -0
- package/dist/interaction/pointer-drag.d.ts +23 -0
- package/dist/interaction/pointer-drag.d.ts.map +1 -0
- package/dist/interaction/pointer-drag.js +21 -0
- package/dist/interaction/pointer-drag.js.map +1 -0
- package/dist/interaction/press.d.ts +152 -0
- package/dist/interaction/press.d.ts.map +1 -0
- package/dist/interaction/press.js +229 -0
- package/dist/interaction/press.js.map +1 -0
- package/dist/interaction/roving-tabindex.d.ts +85 -0
- package/dist/interaction/roving-tabindex.d.ts.map +1 -0
- package/dist/interaction/roving-tabindex.js +142 -0
- package/dist/interaction/roving-tabindex.js.map +1 -0
- package/dist/interaction/selection.d.ts +72 -0
- package/dist/interaction/selection.d.ts.map +1 -0
- package/dist/interaction/selection.js +129 -0
- package/dist/interaction/selection.js.map +1 -0
- package/dist/interaction/targets.d.ts +15 -0
- package/dist/interaction/targets.d.ts.map +1 -0
- package/dist/interaction/targets.js +20 -0
- package/dist/interaction/targets.js.map +1 -0
- package/dist/interaction/tree-navigation.d.ts +111 -0
- package/dist/interaction/tree-navigation.d.ts.map +1 -0
- package/dist/interaction/tree-navigation.js +207 -0
- package/dist/interaction/tree-navigation.js.map +1 -0
- package/dist/interaction/typeahead.d.ts +73 -0
- package/dist/interaction/typeahead.d.ts.map +1 -0
- package/dist/interaction/typeahead.js +113 -0
- package/dist/interaction/typeahead.js.map +1 -0
- package/dist/internal.d.ts +16 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/{internal-DP-xLKbT.mjs → internal.js} +8 -7
- package/dist/internal.js.map +1 -0
- package/dist/media/breakpoints.d.ts +37 -0
- package/dist/media/breakpoints.d.ts.map +1 -0
- package/dist/media/breakpoints.js +64 -0
- package/dist/media/breakpoints.js.map +1 -0
- package/dist/media/index.d.ts +3 -0
- package/dist/media/index.js +4 -0
- package/dist/media/mediaquery.d.ts +40 -0
- package/dist/media/mediaquery.d.ts.map +1 -0
- package/dist/media/mediaquery.js +42 -0
- package/dist/media/mediaquery.js.map +1 -0
- package/dist/media/platform.d.ts +30 -0
- package/dist/media/platform.d.ts.map +1 -0
- package/dist/media/platform.js +50 -0
- package/dist/media/platform.js.map +1 -0
- package/dist/motion/index.d.ts +5 -0
- package/dist/motion/index.js +5 -0
- package/dist/motion/motion.d.ts +16 -0
- package/dist/motion/motion.d.ts.map +1 -0
- package/dist/motion/motion.js +25 -0
- package/dist/motion/motion.js.map +1 -0
- package/dist/motion/presence.d.ts +37 -0
- package/dist/motion/presence.d.ts.map +1 -0
- package/dist/motion/presence.js +65 -0
- package/dist/motion/presence.js.map +1 -0
- package/dist/motion/spring.d.ts +50 -0
- package/dist/motion/spring.d.ts.map +1 -0
- package/dist/motion/spring.js +92 -0
- package/dist/motion/spring.js.map +1 -0
- package/dist/motion/tween.d.ts +44 -0
- package/dist/motion/tween.d.ts.map +1 -0
- package/dist/motion/tween.js +65 -0
- package/dist/motion/tween.js.map +1 -0
- package/dist/net/broadcast.d.ts +39 -0
- package/dist/net/broadcast.d.ts.map +1 -0
- package/dist/net/broadcast.js +73 -0
- package/dist/net/broadcast.js.map +1 -0
- package/dist/net/index.d.ts +5 -0
- package/dist/net/index.js +6 -0
- package/dist/net/online.d.ts +24 -0
- package/dist/net/online.d.ts.map +1 -0
- package/dist/net/online.js +26 -0
- package/dist/net/online.js.map +1 -0
- package/dist/net/sharedHost.d.ts +64 -0
- package/dist/net/sharedHost.d.ts.map +1 -0
- package/dist/net/sharedHost.js +124 -0
- package/dist/net/sharedHost.js.map +1 -0
- package/dist/net/sse.d.ts +115 -0
- package/dist/net/sse.d.ts.map +1 -0
- package/dist/net/sse.js +138 -0
- package/dist/net/sse.js.map +1 -0
- package/dist/net/websocket.d.ts +172 -0
- package/dist/net/websocket.d.ts.map +1 -0
- package/dist/net/websocket.js +199 -0
- package/dist/net/websocket.js.map +1 -0
- package/dist/observers/bounds.d.ts +24 -0
- package/dist/observers/bounds.d.ts.map +1 -0
- package/dist/observers/bounds.js +51 -0
- package/dist/observers/bounds.js.map +1 -0
- package/dist/observers/index.d.ts +4 -0
- package/dist/observers/index.js +5 -0
- package/dist/observers/intersection.d.ts +18 -0
- package/dist/observers/intersection.d.ts.map +1 -0
- package/dist/observers/intersection.js +33 -0
- package/dist/observers/intersection.js.map +1 -0
- package/dist/observers/mutation.d.ts +25 -0
- package/dist/observers/mutation.d.ts.map +1 -0
- package/dist/observers/mutation.js +53 -0
- package/dist/observers/mutation.js.map +1 -0
- package/dist/observers/resize.d.ts +18 -0
- package/dist/observers/resize.d.ts.map +1 -0
- package/dist/observers/resize.js +33 -0
- package/dist/observers/resize.js.map +1 -0
- package/dist/state/history.d.ts +115 -0
- package/dist/state/history.d.ts.map +1 -0
- package/dist/state/history.js +167 -0
- package/dist/state/history.js.map +1 -0
- package/dist/state/index.d.ts +6 -0
- package/dist/state/index.js +7 -0
- package/dist/state/locale.d.ts +27 -0
- package/dist/state/locale.d.ts.map +1 -0
- package/dist/state/locale.js +25 -0
- package/dist/state/locale.js.map +1 -0
- package/dist/state/pagination.d.ts +53 -0
- package/dist/state/pagination.d.ts.map +1 -0
- package/dist/state/pagination.js +72 -0
- package/dist/state/pagination.js.map +1 -0
- package/dist/state/range.d.ts +9 -0
- package/dist/state/range.d.ts.map +1 -0
- package/dist/state/range.js +18 -0
- package/dist/state/range.js.map +1 -0
- package/dist/state/selection.d.ts +47 -0
- package/dist/state/selection.d.ts.map +1 -0
- package/dist/state/selection.js +39 -0
- package/dist/state/selection.js.map +1 -0
- package/dist/state/virtual.d.ts +201 -0
- package/dist/state/virtual.d.ts.map +1 -0
- package/dist/state/{index.mjs → virtual.js} +11 -313
- package/dist/state/virtual.js.map +1 -0
- package/dist/time/debounce.d.ts +43 -0
- package/dist/time/debounce.d.ts.map +1 -0
- package/dist/time/debounce.js +65 -0
- package/dist/time/debounce.js.map +1 -0
- package/dist/time/index.d.ts +6 -0
- package/dist/time/index.js +7 -0
- package/dist/time/interval.d.ts +37 -0
- package/dist/time/interval.d.ts.map +1 -0
- package/dist/time/interval.js +52 -0
- package/dist/time/interval.js.map +1 -0
- package/dist/time/relative.d.ts +8 -0
- package/dist/time/relative.d.ts.map +1 -0
- package/dist/time/relative.js +27 -0
- package/dist/time/relative.js.map +1 -0
- package/dist/time/throttle.d.ts +38 -0
- package/dist/time/throttle.d.ts.map +1 -0
- package/dist/time/throttle.js +39 -0
- package/dist/time/throttle.js.map +1 -0
- package/dist/time/ticks.d.ts +21 -0
- package/dist/time/ticks.d.ts.map +1 -0
- package/dist/time/ticks.js +30 -0
- package/dist/time/ticks.js.map +1 -0
- package/dist/time/timer.d.ts +32 -0
- package/dist/time/timer.d.ts.map +1 -0
- package/dist/time/timer.js +50 -0
- package/dist/time/timer.js.map +1 -0
- package/package.json +31 -31
- package/dist/device/index.d.mts +0 -345
- package/dist/device/index.d.mts.map +0 -1
- package/dist/device/index.mjs +0 -498
- package/dist/device/index.mjs.map +0 -1
- package/dist/dom/index.d.mts +0 -750
- package/dist/dom/index.d.mts.map +0 -1
- package/dist/dom/index.mjs +0 -1857
- package/dist/dom/index.mjs.map +0 -1
- package/dist/editable-text-1D31qthY.d.mts +0 -319
- package/dist/editable-text-1D31qthY.d.mts.map +0 -1
- package/dist/events/index.d.mts +0 -184
- package/dist/events/index.d.mts.map +0 -1
- package/dist/events/index.mjs +0 -315
- package/dist/events/index.mjs.map +0 -1
- package/dist/follow-tab-stop-Caog2qg1.mjs +0 -863
- package/dist/follow-tab-stop-Caog2qg1.mjs.map +0 -1
- package/dist/index-CmmxqSEi.d.mts +0 -149
- package/dist/index-CmmxqSEi.d.mts.map +0 -1
- package/dist/index.d.mts +0 -12
- package/dist/index.mjs +0 -12
- package/dist/input-modality-BXD383jg.mjs.map +0 -1
- package/dist/input-modality-BY-bSrEc.d.mts.map +0 -1
- package/dist/interaction/index.d.mts +0 -1194
- package/dist/interaction/index.d.mts.map +0 -1
- package/dist/interaction/index.mjs +0 -2012
- package/dist/interaction/index.mjs.map +0 -1
- package/dist/internal-DP-xLKbT.mjs.map +0 -1
- package/dist/media/index.d.mts +0 -109
- package/dist/media/index.d.mts.map +0 -1
- package/dist/media/index.mjs +0 -149
- package/dist/media/index.mjs.map +0 -1
- package/dist/motion/index.d.mts +0 -2
- package/dist/motion/index.mjs +0 -1
- package/dist/motion-DmFDppRn.mjs +0 -240
- package/dist/motion-DmFDppRn.mjs.map +0 -1
- package/dist/net/index.d.mts +0 -348
- package/dist/net/index.d.mts.map +0 -1
- package/dist/net/index.mjs +0 -535
- package/dist/net/index.mjs.map +0 -1
- package/dist/observers/index.d.mts +0 -84
- package/dist/observers/index.d.mts.map +0 -1
- package/dist/observers/index.mjs +0 -159
- package/dist/observers/index.mjs.map +0 -1
- package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
- package/dist/state/index.d.mts +0 -444
- package/dist/state/index.d.mts.map +0 -1
- package/dist/state/index.mjs.map +0 -1
- package/dist/time/index.d.mts +0 -179
- package/dist/time/index.d.mts.map +0 -1
- package/dist/time/index.mjs +0 -242
- package/dist/time/index.mjs.map +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import * as Mount from "foldkit/mount";
|
|
3
|
+
export declare const ScrollSettled: Schema.TaggedStruct<"ScrollSettled", {
|
|
4
|
+
/** The item whose start lies nearest the scroller's start, from 0. */
|
|
5
|
+
readonly index: Schema.Number;
|
|
6
|
+
}>;
|
|
7
|
+
export type ScrollSettled = typeof ScrollSettled.Type;
|
|
8
|
+
/** How long a scroll must be still to count as settled, where `scrollend` is missing. */
|
|
9
|
+
export declare const SETTLE_QUIET = 120;
|
|
10
|
+
/**
|
|
11
|
+
* Hears a scroller come to rest, as a Mount: after a swipe, a fling, a
|
|
12
|
+
* trackpad or a scroll a Command made, it reports which of its items starts
|
|
13
|
+
* nearest its own start (inside its `scroll-padding`), the start being the
|
|
14
|
+
* right edge right to left. A snapping carousel reads it as the slide shown.
|
|
15
|
+
*
|
|
16
|
+
* At insert it first scrolls, at once, to item `start` (the Mount's args are
|
|
17
|
+
* read only then, so this is where a redrawn or restored scroller begins),
|
|
18
|
+
* and reports where it lies, since a scroller drawn already at rest sends no
|
|
19
|
+
* `scrollend`. It listens for `scrollend` where the browser has it, and
|
|
20
|
+
* otherwise for a scroll that is quiet for `SETTLE_QUIET` milliseconds.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ScrollSettle: Mount.MountDefinitionWithArgs<"ScrollSettle", {
|
|
23
|
+
/** Which children are the items; default every child. */
|
|
24
|
+
item: Schema.optional<Schema.String>;
|
|
25
|
+
/** Default `inline`, the row a carousel scrolls along. */
|
|
26
|
+
axis: Schema.optional<Schema.Literals<readonly ["inline", "block"]>>;
|
|
27
|
+
/** The item to scroll to at insert; default the first, which needs no scroll. */
|
|
28
|
+
start: Schema.optional<Schema.Number>;
|
|
29
|
+
}, {
|
|
30
|
+
readonly _tag: "ScrollSettled";
|
|
31
|
+
readonly index: number;
|
|
32
|
+
}>;
|
|
33
|
+
//# sourceMappingURL=scroll-settle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-settle.d.ts","names":[],"sources":["../../src/dom/scroll-settle.ts"],"mappings":";;qBAGa,eAAa,OAAA;;;;YAId,uBAAuB,cAAc;;qBAGpC;;;;;;;;;;;;;qBAcA,cAAY,MAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Effect, Queue, Schema, Stream } from "effect";
|
|
2
|
+
import * as Mount from "foldkit/mount";
|
|
3
|
+
// src/dom/scroll-settle.ts
|
|
4
|
+
const ScrollSettled = Schema.TaggedStruct("ScrollSettled", {
|
|
5
|
+
/** The item whose start lies nearest the scroller's start, from 0. */
|
|
6
|
+
index: Schema.Number });
|
|
7
|
+
/** How long a scroll must be still to count as settled, where `scrollend` is missing. */
|
|
8
|
+
const SETTLE_QUIET = 120;
|
|
9
|
+
/**
|
|
10
|
+
* Hears a scroller come to rest, as a Mount: after a swipe, a fling, a
|
|
11
|
+
* trackpad or a scroll a Command made, it reports which of its items starts
|
|
12
|
+
* nearest its own start (inside its `scroll-padding`), the start being the
|
|
13
|
+
* right edge right to left. A snapping carousel reads it as the slide shown.
|
|
14
|
+
*
|
|
15
|
+
* At insert it first scrolls, at once, to item `start` (the Mount's args are
|
|
16
|
+
* read only then, so this is where a redrawn or restored scroller begins),
|
|
17
|
+
* and reports where it lies, since a scroller drawn already at rest sends no
|
|
18
|
+
* `scrollend`. It listens for `scrollend` where the browser has it, and
|
|
19
|
+
* otherwise for a scroll that is quiet for `SETTLE_QUIET` milliseconds.
|
|
20
|
+
*/
|
|
21
|
+
const ScrollSettle = Mount.defineStream("ScrollSettle", {
|
|
22
|
+
messages: [ScrollSettled],
|
|
23
|
+
args: {
|
|
24
|
+
/** Which children are the items; default every child. */
|
|
25
|
+
item: Schema.optional(Schema.String),
|
|
26
|
+
/** Default `inline`, the row a carousel scrolls along. */
|
|
27
|
+
axis: Schema.optional(Schema.Literals(["inline", "block"])),
|
|
28
|
+
/** The item to scroll to at insert; default the first, which needs no scroll. */
|
|
29
|
+
start: Schema.optional(Schema.Number)
|
|
30
|
+
},
|
|
31
|
+
execute: ({ element, item, axis = "inline", start = 0 }) => Stream.callback((queue) => Effect.acquireRelease(Effect.sync(() => {
|
|
32
|
+
const items = () => Array.from(item === void 0 ? element.children : element.querySelectorAll(`:scope > ${item}`));
|
|
33
|
+
/** How far `child`'s start lies past the scroller's start, along the axis. */
|
|
34
|
+
const offsetOf = (child) => {
|
|
35
|
+
const style = getComputedStyle(element);
|
|
36
|
+
const box = element.getBoundingClientRect();
|
|
37
|
+
const own = child.getBoundingClientRect();
|
|
38
|
+
if (axis === "block") return own.top - box.top - (parseFloat(style.scrollPaddingBlockStart) || 0);
|
|
39
|
+
const padding = parseFloat(style.scrollPaddingInlineStart) || 0;
|
|
40
|
+
return style.direction === "rtl" ? box.right - padding - own.right : own.left - box.left - padding;
|
|
41
|
+
};
|
|
42
|
+
const report = () => {
|
|
43
|
+
let nearest = -1;
|
|
44
|
+
let distance = Infinity;
|
|
45
|
+
items().forEach((child, index) => {
|
|
46
|
+
const away = Math.abs(offsetOf(child));
|
|
47
|
+
if (away < distance) {
|
|
48
|
+
nearest = index;
|
|
49
|
+
distance = away;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
if (nearest >= 0) Queue.offerUnsafe(queue, ScrollSettled.make({ index: nearest }));
|
|
53
|
+
};
|
|
54
|
+
const first = items()[start];
|
|
55
|
+
const before = element.scrollLeft + element.scrollTop;
|
|
56
|
+
if (start > 0 && first !== void 0) {
|
|
57
|
+
const by = offsetOf(first);
|
|
58
|
+
const rtl = axis === "inline" && getComputedStyle(element).direction === "rtl";
|
|
59
|
+
element.scrollTo(axis === "block" ? {
|
|
60
|
+
top: element.scrollTop + by,
|
|
61
|
+
behavior: "instant"
|
|
62
|
+
} : {
|
|
63
|
+
left: element.scrollLeft + (rtl ? -by : by),
|
|
64
|
+
behavior: "instant"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (element.scrollLeft + element.scrollTop === before) report();
|
|
68
|
+
let quiet;
|
|
69
|
+
const hasEnd = "onscrollend" in element;
|
|
70
|
+
const listener = hasEnd ? report : () => {
|
|
71
|
+
clearTimeout(quiet);
|
|
72
|
+
quiet = setTimeout(report, 120);
|
|
73
|
+
};
|
|
74
|
+
const type = hasEnd ? "scrollend" : "scroll";
|
|
75
|
+
element.addEventListener(type, listener);
|
|
76
|
+
return () => {
|
|
77
|
+
clearTimeout(quiet);
|
|
78
|
+
element.removeEventListener(type, listener);
|
|
79
|
+
};
|
|
80
|
+
}), (detach) => Effect.sync(detach)))
|
|
81
|
+
});
|
|
82
|
+
export { SETTLE_QUIET, ScrollSettle, ScrollSettled };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=scroll-settle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll-settle.js","names":[],"sources":["../../src/dom/scroll-settle.ts"],"sourcesContent":["import { Effect, Queue, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\n\nexport const ScrollSettled = Schema.TaggedStruct('ScrollSettled', {\n /** The item whose start lies nearest the scroller's start, from 0. */\n index: Schema.Number,\n})\nexport type ScrollSettled = typeof ScrollSettled.Type\n\n/** How long a scroll must be still to count as settled, where `scrollend` is missing. */\nexport const SETTLE_QUIET = 120\n\n/**\n * Hears a scroller come to rest, as a Mount: after a swipe, a fling, a\n * trackpad or a scroll a Command made, it reports which of its items starts\n * nearest its own start (inside its `scroll-padding`), the start being the\n * right edge right to left. A snapping carousel reads it as the slide shown.\n *\n * At insert it first scrolls, at once, to item `start` (the Mount's args are\n * read only then, so this is where a redrawn or restored scroller begins),\n * and reports where it lies, since a scroller drawn already at rest sends no\n * `scrollend`. It listens for `scrollend` where the browser has it, and\n * otherwise for a scroll that is quiet for `SETTLE_QUIET` milliseconds.\n */\nexport const ScrollSettle = Mount.defineStream('ScrollSettle', {\n messages: [ScrollSettled],\n args: {\n /** Which children are the items; default every child. */\n item: Schema.optional(Schema.String),\n /** Default `inline`, the row a carousel scrolls along. */\n axis: Schema.optional(Schema.Literals(['inline', 'block'])),\n /** The item to scroll to at insert; default the first, which needs no scroll. */\n start: Schema.optional(Schema.Number),\n },\n execute: ({ element, item, axis = 'inline', start = 0 }) =>\n Stream.callback<ScrollSettled>(queue =>\n Effect.acquireRelease(\n Effect.sync(() => {\n const items = () =>\n Array.from(\n item === undefined ? element.children : element.querySelectorAll(`:scope > ${item}`),\n )\n /** How far `child`'s start lies past the scroller's start, along the axis. */\n const offsetOf = (child: Element): number => {\n const style = getComputedStyle(element)\n const box = element.getBoundingClientRect()\n const own = child.getBoundingClientRect()\n if (axis === 'block') {\n return own.top - box.top - (parseFloat(style.scrollPaddingBlockStart) || 0)\n }\n const padding = parseFloat(style.scrollPaddingInlineStart) || 0\n return style.direction === 'rtl'\n ? box.right - padding - own.right\n : own.left - box.left - padding\n }\n const report = () => {\n let nearest = -1\n let distance = Infinity\n items().forEach((child, index) => {\n const away = Math.abs(offsetOf(child))\n if (away < distance) {\n nearest = index\n distance = away\n }\n })\n if (nearest >= 0) Queue.offerUnsafe(queue, ScrollSettled.make({ index: nearest }))\n }\n const first = items()[start]\n const before = element.scrollLeft + element.scrollTop\n if (start > 0 && first !== undefined) {\n const by = offsetOf(first)\n const rtl = axis === 'inline' && getComputedStyle(element).direction === 'rtl'\n // A larger `scrollLeft` moves the content toward the start either way, so right to\n // left the way to an item's start is the other sign. To a position, not by a\n // distance: a relative scroll stops at every `scroll-snap-stop: always` on the way.\n element.scrollTo(\n axis === 'block'\n ? { top: element.scrollTop + by, behavior: 'instant' }\n : { left: element.scrollLeft + (rtl ? -by : by), behavior: 'instant' },\n )\n }\n // A scroll just made reports itself when it ends; one that moved nothing never ends.\n if (element.scrollLeft + element.scrollTop === before) report()\n let quiet: ReturnType<typeof setTimeout> | undefined\n const hasEnd = 'onscrollend' in element\n const listener = hasEnd\n ? report\n : () => {\n clearTimeout(quiet)\n quiet = setTimeout(report, SETTLE_QUIET)\n }\n const type = hasEnd ? 'scrollend' : 'scroll'\n element.addEventListener(type, listener)\n return () => {\n clearTimeout(quiet)\n element.removeEventListener(type, listener)\n }\n }),\n detach => Effect.sync(detach),\n ),\n ),\n})\n"],"mappings":";;;AAGA,MAAa,gBAAgB,OAAO,aAAa,iBAAiB;;AAEhE,OAAO,OAAO,OAChB,CAAC;;AAID,MAAa,eAAe;;;;;;;;;;;;;AAc5B,MAAa,eAAe,MAAM,aAAa,gBAAgB;CAC7D,UAAU,CAAC,aAAa;CACxB,MAAM;;EAEJ,MAAM,OAAO,SAAS,OAAO,MAAM;;EAEnC,MAAM,OAAO,SAAS,OAAO,SAAS,CAAC,UAAU,OAAO,CAAC,CAAC;;EAE1D,OAAO,OAAO,SAAS,OAAO,MAAM;CACtC;CACA,UAAU,EAAE,SAAS,MAAM,OAAO,UAAU,QAAQ,QAClD,OAAO,UAAwB,UAC7B,OAAO,eACL,OAAO,WAAW;EAChB,MAAM,cACJ,MAAM,KACJ,SAAS,KAAA,IAAY,QAAQ,WAAW,QAAQ,iBAAiB,YAAY,MAAM,CACrF;;EAEF,MAAM,YAAY,UAA2B;GAC3C,MAAM,QAAQ,iBAAiB,OAAO;GACtC,MAAM,MAAM,QAAQ,sBAAsB;GAC1C,MAAM,MAAM,MAAM,sBAAsB;GACxC,IAAI,SAAS,SACX,OAAO,IAAI,MAAM,IAAI,OAAO,WAAW,MAAM,uBAAuB,KAAK;GAE3E,MAAM,UAAU,WAAW,MAAM,wBAAwB,KAAK;GAC9D,OAAO,MAAM,cAAc,QACvB,IAAI,QAAQ,UAAU,IAAI,QAC1B,IAAI,OAAO,IAAI,OAAO;EAC5B;EACA,MAAM,eAAe;GACnB,IAAI,UAAU;GACd,IAAI,WAAW;GACf,MAAM,CAAC,CAAC,SAAS,OAAO,UAAU;IAChC,MAAM,OAAO,KAAK,IAAI,SAAS,KAAK,CAAC;IACrC,IAAI,OAAO,UAAU;KACnB,UAAU;KACV,WAAW;IACb;GACF,CAAC;GACD,IAAI,WAAW,GAAG,MAAM,YAAY,OAAO,cAAc,KAAK,EAAE,OAAO,QAAQ,CAAC,CAAC;EACnF;EACA,MAAM,QAAQ,MAAM,CAAC,CAAC;EACtB,MAAM,SAAS,QAAQ,aAAa,QAAQ;EAC5C,IAAI,QAAQ,KAAK,UAAU,KAAA,GAAW;GACpC,MAAM,KAAK,SAAS,KAAK;GACzB,MAAM,MAAM,SAAS,YAAY,iBAAiB,OAAO,CAAC,CAAC,cAAc;GAIzE,QAAQ,SACN,SAAS,UACL;IAAE,KAAK,QAAQ,YAAY;IAAI,UAAU;GAAU,IACnD;IAAE,MAAM,QAAQ,cAAc,MAAM,CAAC,KAAK;IAAK,UAAU;GAAU,CACzE;EACF;EAEA,IAAI,QAAQ,aAAa,QAAQ,cAAc,QAAQ,OAAO;EAC9D,IAAI;EACJ,MAAM,SAAS,iBAAiB;EAChC,MAAM,WAAW,SACb,eACM;GACJ,aAAa,KAAK;GAClB,QAAQ,WAAW,QAAA,GAAoB;EACzC;EACJ,MAAM,OAAO,SAAS,cAAc;EACpC,QAAQ,iBAAiB,MAAM,QAAQ;EACvC,aAAa;GACX,aAAa,KAAK;GAClB,QAAQ,oBAAoB,MAAM,QAAQ;EAC5C;CACF,CAAC,IACD,WAAU,OAAO,KAAK,MAAM,CAC9B,CACF;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Stream } from "effect";
|
|
2
|
+
/** How `keepScroll` remembers and restores each history entry's offset. */
|
|
3
|
+
export interface KeepScrollOptions {
|
|
4
|
+
/** The `sessionStorage` key holding entry offsets. Default `'foldkit:scroll'`. */
|
|
5
|
+
readonly storageKey?: string | undefined;
|
|
6
|
+
/** Entries remembered at most: the oldest are forgotten first. Default 50. */
|
|
7
|
+
readonly kept?: number | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* How long a restore holds its place while the next screen settles, in
|
|
10
|
+
* milliseconds. Default 2000.
|
|
11
|
+
*/
|
|
12
|
+
readonly patience?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Keeps the window's scroll across same-document navigations: a pushed entry
|
|
16
|
+
* starts at the top, and Back, Forward or a reload return where that entry
|
|
17
|
+
* was. Without a window the stream is empty instead of throwing. Lift with
|
|
18
|
+
* `Subscription.persistentEntry`; the stream sends no Messages.
|
|
19
|
+
*/
|
|
20
|
+
export declare const keepScroll: (options?: KeepScrollOptions) => Stream.Stream<never>;
|
|
21
|
+
//# sourceMappingURL=scroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll.d.ts","names":[],"sources":["../../src/dom/scroll.ts"],"mappings":";;iBAkCiB;;WAEN;;WAEA;;;;;WAKA;;;;;;;;qBAuHE,aAAU,UAAa,sBAAyB,OAAO"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Effect, Option, Stream } from "effect";
|
|
2
|
+
// src/dom/scroll.ts
|
|
3
|
+
/**
|
|
4
|
+
* Where the window is scrolled, across an application's own navigations, as
|
|
5
|
+
* a stream. Left to itself, a browser keeps the scroll of the entry it
|
|
6
|
+
* leaves when a link pushes a new one, and on Back restores the old offset
|
|
7
|
+
* before the application has drawn the entry it returns to, so the offset is
|
|
8
|
+
* clamped to a page still loading. Here a pushed entry starts at the top,
|
|
9
|
+
* and Back, Forward or a reload return where that entry was, once the page
|
|
10
|
+
* is tall enough to hold it.
|
|
11
|
+
*
|
|
12
|
+
* Three rules, each found the slow way:
|
|
13
|
+
*
|
|
14
|
+
* 1. The offset is taken when the reader acts. The next screen is drawn
|
|
15
|
+
* before a Navigate Command pushes the address, so by the time the URL
|
|
16
|
+
* changes the window is already clamped to the new, shorter page. The
|
|
17
|
+
* scroll is recorded at the reader's click or key (capture phase), and at
|
|
18
|
+
* the start of Back and Forward, which begin in the browser before
|
|
19
|
+
* anything is drawn.
|
|
20
|
+
* 2. A restore holds its place while the next screen settles. A restore made
|
|
21
|
+
* when the entry changes is undone by the loading state drawn right after
|
|
22
|
+
* it, so the target is held on each frame for a moment, until the reader
|
|
23
|
+
* scrolls, touches or types, or another navigation starts.
|
|
24
|
+
* 3. Entries are keyed by the Navigation API's entry key, which a reload and
|
|
25
|
+
* a full navigation keep; offsets rest in `sessionStorage`, so Back into
|
|
26
|
+
* another document restores too. Where the browser has no Navigation API
|
|
27
|
+
* the stream attaches nothing and leaves the browser's own behaviour
|
|
28
|
+
* alone.
|
|
29
|
+
*
|
|
30
|
+
* Lift with `Subscription.persistentEntry`; the stream sends no Messages. Only
|
|
31
|
+
* the window scrolls: a nested container is the route graph's to know, when
|
|
32
|
+
* `Site.transition` arrives.
|
|
33
|
+
*/
|
|
34
|
+
const navigationTypeOf = (event) => "navigationType" in event ? Option.some(event.navigationType) : Option.none();
|
|
35
|
+
const readSaved = (storageKey) => {
|
|
36
|
+
try {
|
|
37
|
+
const stored = JSON.parse(sessionStorage.getItem(storageKey) ?? "[]");
|
|
38
|
+
return new Map(Array.isArray(stored) ? stored.filter((pair) => Array.isArray(pair) && typeof pair[0] === "string" && typeof pair[1] === "number") : []);
|
|
39
|
+
} catch {
|
|
40
|
+
return /* @__PURE__ */ new Map();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/** Starts keeping the scroll; the release undoes everything it installed. */
|
|
44
|
+
const attach = (storageKey, kept, patience) => {
|
|
45
|
+
const navigation = window.navigation;
|
|
46
|
+
if (navigation === void 0) return () => {};
|
|
47
|
+
const restoration = window.history.scrollRestoration;
|
|
48
|
+
window.history.scrollRestoration = "manual";
|
|
49
|
+
const saved = readSaved(storageKey);
|
|
50
|
+
const detaches = [];
|
|
51
|
+
const on = (target, type, listener, capture) => {
|
|
52
|
+
target.addEventListener(type, listener, capture);
|
|
53
|
+
detaches.push(() => target.removeEventListener(type, listener, capture));
|
|
54
|
+
};
|
|
55
|
+
const keyOf = () => Option.fromNullOr(navigation.currentEntry).pipe(Option.map((entry) => entry.key));
|
|
56
|
+
/** Where the current entry was left, if it has been. */
|
|
57
|
+
const savedHere = () => Option.flatMap(keyOf(), (key) => Option.fromUndefinedOr(saved.get(key)));
|
|
58
|
+
const remember = () => {
|
|
59
|
+
const key = keyOf();
|
|
60
|
+
if (Option.isNone(key)) return;
|
|
61
|
+
saved.delete(key.value);
|
|
62
|
+
saved.set(key.value, window.scrollY);
|
|
63
|
+
for (const old of saved.keys()) {
|
|
64
|
+
if (saved.size <= kept) break;
|
|
65
|
+
saved.delete(old);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
let settling = new AbortController();
|
|
69
|
+
/**
|
|
70
|
+
* Holds the window at `top` while the next screen settles, whenever the page
|
|
71
|
+
* can hold it, until the reader scrolls, touches or types, or another
|
|
72
|
+
* navigation starts.
|
|
73
|
+
*/
|
|
74
|
+
const settle = (top) => {
|
|
75
|
+
settling.abort();
|
|
76
|
+
settling = new AbortController();
|
|
77
|
+
const { signal } = settling;
|
|
78
|
+
for (const input of [
|
|
79
|
+
"wheel",
|
|
80
|
+
"touchstart",
|
|
81
|
+
"keydown",
|
|
82
|
+
"pointerdown"
|
|
83
|
+
]) window.addEventListener(input, () => settling.abort(), {
|
|
84
|
+
passive: true,
|
|
85
|
+
signal
|
|
86
|
+
});
|
|
87
|
+
const until = performance.now() + patience;
|
|
88
|
+
const step = () => {
|
|
89
|
+
if (signal.aborted) return;
|
|
90
|
+
if (document.documentElement.scrollHeight - window.innerHeight >= top && Math.round(window.scrollY) !== top) window.scrollTo({
|
|
91
|
+
top,
|
|
92
|
+
behavior: "instant"
|
|
93
|
+
});
|
|
94
|
+
if (performance.now() < until) requestAnimationFrame(step);
|
|
95
|
+
else settling.abort();
|
|
96
|
+
};
|
|
97
|
+
step();
|
|
98
|
+
};
|
|
99
|
+
const acted = () => remember();
|
|
100
|
+
for (const input of ["click", "keydown"]) on(window, input, acted, true);
|
|
101
|
+
const traversing = (event) => {
|
|
102
|
+
if (Option.contains(navigationTypeOf(event), "traverse")) remember();
|
|
103
|
+
};
|
|
104
|
+
on(navigation, "navigate", traversing);
|
|
105
|
+
const changed = (event) => {
|
|
106
|
+
const type = navigationTypeOf(event);
|
|
107
|
+
if (Option.contains(type, "push")) settle(0);
|
|
108
|
+
else if (Option.contains(type, "traverse")) settle(Option.getOrElse(savedHere(), () => 0));
|
|
109
|
+
};
|
|
110
|
+
on(navigation, "currententrychange", changed);
|
|
111
|
+
const hidden = () => {
|
|
112
|
+
remember();
|
|
113
|
+
try {
|
|
114
|
+
sessionStorage.setItem(storageKey, JSON.stringify([...saved]));
|
|
115
|
+
} catch {}
|
|
116
|
+
};
|
|
117
|
+
on(window, "pagehide", hidden);
|
|
118
|
+
const here = savedHere();
|
|
119
|
+
if (Option.isSome(here)) settle(here.value);
|
|
120
|
+
return () => {
|
|
121
|
+
settling.abort();
|
|
122
|
+
for (const detach of detaches) detach();
|
|
123
|
+
window.history.scrollRestoration = restoration;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Keeps the window's scroll across same-document navigations: a pushed entry
|
|
128
|
+
* starts at the top, and Back, Forward or a reload return where that entry
|
|
129
|
+
* was. Without a window the stream is empty instead of throwing. Lift with
|
|
130
|
+
* `Subscription.persistentEntry`; the stream sends no Messages.
|
|
131
|
+
*/
|
|
132
|
+
const keepScroll = (options = {}) => {
|
|
133
|
+
if (typeof window === "undefined") return Stream.empty;
|
|
134
|
+
const storageKey = options.storageKey ?? "foldkit:scroll";
|
|
135
|
+
const kept = options.kept ?? 50;
|
|
136
|
+
const patience = options.patience ?? 2e3;
|
|
137
|
+
return Stream.callback(() => Effect.acquireRelease(Effect.sync(() => attach(storageKey, kept, patience)), (detach) => Effect.sync(detach)));
|
|
138
|
+
};
|
|
139
|
+
export { keepScroll };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=scroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scroll.js","names":[],"sources":["../../src/dom/scroll.ts"],"sourcesContent":["/**\n * Where the window is scrolled, across an application's own navigations, as\n * a stream. Left to itself, a browser keeps the scroll of the entry it\n * leaves when a link pushes a new one, and on Back restores the old offset\n * before the application has drawn the entry it returns to, so the offset is\n * clamped to a page still loading. Here a pushed entry starts at the top,\n * and Back, Forward or a reload return where that entry was, once the page\n * is tall enough to hold it.\n *\n * Three rules, each found the slow way:\n *\n * 1. The offset is taken when the reader acts. The next screen is drawn\n * before a Navigate Command pushes the address, so by the time the URL\n * changes the window is already clamped to the new, shorter page. The\n * scroll is recorded at the reader's click or key (capture phase), and at\n * the start of Back and Forward, which begin in the browser before\n * anything is drawn.\n * 2. A restore holds its place while the next screen settles. A restore made\n * when the entry changes is undone by the loading state drawn right after\n * it, so the target is held on each frame for a moment, until the reader\n * scrolls, touches or types, or another navigation starts.\n * 3. Entries are keyed by the Navigation API's entry key, which a reload and\n * a full navigation keep; offsets rest in `sessionStorage`, so Back into\n * another document restores too. Where the browser has no Navigation API\n * the stream attaches nothing and leaves the browser's own behaviour\n * alone.\n *\n * Lift with `Subscription.persistentEntry`; the stream sends no Messages. Only\n * the window scrolls: a nested container is the route graph's to know, when\n * `Site.transition` arrives.\n */\nimport { Effect, Option, Stream } from 'effect'\n\n/** How `keepScroll` remembers and restores each history entry's offset. */\nexport interface KeepScrollOptions {\n /** The `sessionStorage` key holding entry offsets. Default `'foldkit:scroll'`. */\n readonly storageKey?: string | undefined\n /** Entries remembered at most: the oldest are forgotten first. Default 50. */\n readonly kept?: number | undefined\n /**\n * How long a restore holds its place while the next screen settles, in\n * milliseconds. Default 2000.\n */\n readonly patience?: number | undefined\n}\n\nconst navigationTypeOf = (event: Event): Option.Option<unknown> =>\n 'navigationType' in event ? Option.some(event.navigationType) : Option.none()\n\nconst readSaved = (storageKey: string): Map<string, number> => {\n try {\n const stored: unknown = JSON.parse(sessionStorage.getItem(storageKey) ?? '[]')\n return new Map(\n Array.isArray(stored)\n ? stored.filter(\n (pair): pair is [string, number] =>\n Array.isArray(pair) && typeof pair[0] === 'string' && typeof pair[1] === 'number',\n )\n : [],\n )\n } catch {\n // Storage blocked, or something else wrote the key: nothing is remembered.\n return new Map()\n }\n}\n\n/** Starts keeping the scroll; the release undoes everything it installed. */\nconst attach = (storageKey: string, kept: number, patience: number): (() => void) => {\n // TypeScript's DOM library declares it on every window; a browser without\n // the Navigation API has none.\n const navigation: Navigation | undefined = window.navigation\n if (navigation === undefined) return () => {}\n const restoration = window.history.scrollRestoration\n window.history.scrollRestoration = 'manual'\n const saved = readSaved(storageKey)\n const detaches: Array<() => void> = []\n const on = (target: EventTarget, type: string, listener: EventListener, capture?: boolean) => {\n target.addEventListener(type, listener, capture)\n detaches.push(() => target.removeEventListener(type, listener, capture))\n }\n const keyOf = () =>\n Option.fromNullOr(navigation.currentEntry).pipe(Option.map(entry => entry.key))\n /** Where the current entry was left, if it has been. */\n const savedHere = () => Option.flatMap(keyOf(), key => Option.fromUndefinedOr(saved.get(key)))\n const remember = () => {\n const key = keyOf()\n if (Option.isNone(key)) return\n // Moved to the end, so it is the last to be forgotten.\n saved.delete(key.value)\n saved.set(key.value, window.scrollY)\n for (const old of saved.keys()) {\n if (saved.size <= kept) break\n saved.delete(old)\n }\n }\n\n let settling = new AbortController()\n /**\n * Holds the window at `top` while the next screen settles, whenever the page\n * can hold it, until the reader scrolls, touches or types, or another\n * navigation starts.\n */\n const settle = (top: number) => {\n settling.abort()\n settling = new AbortController()\n const { signal } = settling\n for (const input of ['wheel', 'touchstart', 'keydown', 'pointerdown'])\n window.addEventListener(input, () => settling.abort(), { passive: true, signal })\n const until = performance.now() + patience\n const step = () => {\n if (signal.aborted) return\n const room = document.documentElement.scrollHeight - window.innerHeight\n if (room >= top && Math.round(window.scrollY) !== top)\n window.scrollTo({ top, behavior: 'instant' })\n if (performance.now() < until) requestAnimationFrame(step)\n else settling.abort()\n }\n step()\n }\n\n // Remembered where the reader acts, before the application does: by the time\n // it pushes an address it has drawn the next screen, and the window is\n // already clamped to it. Back and Forward start in the browser, before\n // anything is drawn, so they are remembered as they begin.\n const acted = () => remember()\n for (const input of ['click', 'keydown']) on(window, input, acted, true)\n const traversing = (event: Event) => {\n if (Option.contains(navigationTypeOf(event), 'traverse')) remember()\n }\n on(navigation, 'navigate', traversing)\n const changed = (event: Event) => {\n const type = navigationTypeOf(event)\n if (Option.contains(type, 'push')) settle(0)\n else if (Option.contains(type, 'traverse')) settle(Option.getOrElse(savedHere(), () => 0))\n // A replace is the same entry, narrowed or selected in place: it stays where it is.\n }\n on(navigation, 'currententrychange', changed)\n const hidden = () => {\n remember()\n try {\n sessionStorage.setItem(storageKey, JSON.stringify([...saved]))\n } catch {\n // Storage blocked: the next document starts at the top.\n }\n }\n on(window, 'pagehide', hidden)\n // A reload, or Back into this document from another: where this entry was.\n const here = savedHere()\n if (Option.isSome(here)) settle(here.value)\n return () => {\n settling.abort()\n for (const detach of detaches) detach()\n window.history.scrollRestoration = restoration\n }\n}\n\n/**\n * Keeps the window's scroll across same-document navigations: a pushed entry\n * starts at the top, and Back, Forward or a reload return where that entry\n * was. Without a window the stream is empty instead of throwing. Lift with\n * `Subscription.persistentEntry`; the stream sends no Messages.\n */\nexport const keepScroll = (options: KeepScrollOptions = {}): Stream.Stream<never> => {\n if (typeof window === 'undefined') return Stream.empty\n const storageKey = options.storageKey ?? 'foldkit:scroll'\n const kept = options.kept ?? 50\n const patience = options.patience ?? 2000\n return Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.sync(() => attach(storageKey, kept, patience)),\n detach => Effect.sync(detach),\n ),\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,oBAAoB,UACxB,oBAAoB,QAAQ,OAAO,KAAK,MAAM,cAAc,IAAI,OAAO,KAAK;AAE9E,MAAM,aAAa,eAA4C;CAC7D,IAAI;EACF,MAAM,SAAkB,KAAK,MAAM,eAAe,QAAQ,UAAU,KAAK,IAAI;EAC7E,OAAO,IAAI,IACT,MAAM,QAAQ,MAAM,IAChB,OAAO,QACJ,SACC,MAAM,QAAQ,IAAI,KAAK,OAAO,KAAK,OAAO,YAAY,OAAO,KAAK,OAAO,QAC7E,IACA,CAAC,CACP;CACF,QAAQ;EAEN,uBAAO,IAAI,IAAI;CACjB;AACF;;AAGA,MAAM,UAAU,YAAoB,MAAc,aAAmC;CAGnF,MAAM,aAAqC,OAAO;CAClD,IAAI,eAAe,KAAA,GAAW,aAAa,CAAC;CAC5C,MAAM,cAAc,OAAO,QAAQ;CACnC,OAAO,QAAQ,oBAAoB;CACnC,MAAM,QAAQ,UAAU,UAAU;CAClC,MAAM,WAA8B,CAAC;CACrC,MAAM,MAAM,QAAqB,MAAc,UAAyB,YAAsB;EAC5F,OAAO,iBAAiB,MAAM,UAAU,OAAO;EAC/C,SAAS,WAAW,OAAO,oBAAoB,MAAM,UAAU,OAAO,CAAC;CACzE;CACA,MAAM,cACJ,OAAO,WAAW,WAAW,YAAY,CAAC,CAAC,KAAK,OAAO,KAAI,UAAS,MAAM,GAAG,CAAC;;CAEhF,MAAM,kBAAkB,OAAO,QAAQ,MAAM,IAAG,QAAO,OAAO,gBAAgB,MAAM,IAAI,GAAG,CAAC,CAAC;CAC7F,MAAM,iBAAiB;EACrB,MAAM,MAAM,MAAM;EAClB,IAAI,OAAO,OAAO,GAAG,GAAG;EAExB,MAAM,OAAO,IAAI,KAAK;EACtB,MAAM,IAAI,IAAI,OAAO,OAAO,OAAO;EACnC,KAAK,MAAM,OAAO,MAAM,KAAK,GAAG;GAC9B,IAAI,MAAM,QAAQ,MAAM;GACxB,MAAM,OAAO,GAAG;EAClB;CACF;CAEA,IAAI,WAAW,IAAI,gBAAgB;;;;;;CAMnC,MAAM,UAAU,QAAgB;EAC9B,SAAS,MAAM;EACf,WAAW,IAAI,gBAAgB;EAC/B,MAAM,EAAE,WAAW;EACnB,KAAK,MAAM,SAAS;GAAC;GAAS;GAAc;GAAW;EAAa,GAClE,OAAO,iBAAiB,aAAa,SAAS,MAAM,GAAG;GAAE,SAAS;GAAM;EAAO,CAAC;EAClF,MAAM,QAAQ,YAAY,IAAI,IAAI;EAClC,MAAM,aAAa;GACjB,IAAI,OAAO,SAAS;GAEpB,IADa,SAAS,gBAAgB,eAAe,OAAO,eAChD,OAAO,KAAK,MAAM,OAAO,OAAO,MAAM,KAChD,OAAO,SAAS;IAAE;IAAK,UAAU;GAAU,CAAC;GAC9C,IAAI,YAAY,IAAI,IAAI,OAAO,sBAAsB,IAAI;QACpD,SAAS,MAAM;EACtB;EACA,KAAK;CACP;CAMA,MAAM,cAAc,SAAS;CAC7B,KAAK,MAAM,SAAS,CAAC,SAAS,SAAS,GAAG,GAAG,QAAQ,OAAO,OAAO,IAAI;CACvE,MAAM,cAAc,UAAiB;EACnC,IAAI,OAAO,SAAS,iBAAiB,KAAK,GAAG,UAAU,GAAG,SAAS;CACrE;CACA,GAAG,YAAY,YAAY,UAAU;CACrC,MAAM,WAAW,UAAiB;EAChC,MAAM,OAAO,iBAAiB,KAAK;EACnC,IAAI,OAAO,SAAS,MAAM,MAAM,GAAG,OAAO,CAAC;OACtC,IAAI,OAAO,SAAS,MAAM,UAAU,GAAG,OAAO,OAAO,UAAU,UAAU,SAAS,CAAC,CAAC;CAE3F;CACA,GAAG,YAAY,sBAAsB,OAAO;CAC5C,MAAM,eAAe;EACnB,SAAS;EACT,IAAI;GACF,eAAe,QAAQ,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,CAAC,CAAC;EAC/D,QAAQ,CAER;CACF;CACA,GAAG,QAAQ,YAAY,MAAM;CAE7B,MAAM,OAAO,UAAU;CACvB,IAAI,OAAO,OAAO,IAAI,GAAG,OAAO,KAAK,KAAK;CAC1C,aAAa;EACX,SAAS,MAAM;EACf,KAAK,MAAM,UAAU,UAAU,OAAO;EACtC,OAAO,QAAQ,oBAAoB;CACrC;AACF;;;;;;;AAQA,MAAa,cAAc,UAA6B,CAAC,MAA4B;CACnF,IAAI,OAAO,WAAW,aAAa,OAAO,OAAO;CACjD,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,WAAW,QAAQ,YAAY;CACrC,OAAO,OAAO,eACZ,OAAO,eACL,OAAO,WAAW,OAAO,YAAY,MAAM,QAAQ,CAAC,IACpD,WAAU,OAAO,KAAK,MAAM,CAC9B,CACF;AACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { Command } from "foldkit/command";
|
|
3
|
+
export declare const ShareData: Schema.Struct<{
|
|
4
|
+
readonly title: Schema.optional<Schema.String>;
|
|
5
|
+
readonly text: Schema.optional<Schema.String>;
|
|
6
|
+
readonly url: Schema.optional<Schema.String>;
|
|
7
|
+
}>;
|
|
8
|
+
export type ShareData = typeof ShareData.Type;
|
|
9
|
+
export declare const ShareMessage: import("foldkit/message").MessageUnion<{
|
|
10
|
+
readonly Shared: {};
|
|
11
|
+
readonly Dismissed: {};
|
|
12
|
+
readonly ShareFailed: {
|
|
13
|
+
message: Schema.String;
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
export type ShareMessage = typeof ShareMessage.Type;
|
|
17
|
+
/** Shares data through the platform sheet. */
|
|
18
|
+
export declare const share: (data: ShareData) => Command<ShareMessage, never, never>;
|
|
19
|
+
//# sourceMappingURL=share.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share.d.ts","names":[],"sources":["../../src/dom/share.ts"],"mappings":";;qBAWa,WAAS,OAAA;;;;;YAKV,mBAAmB,UAAU;qBAE5B,wCAAY;;;;IAGR,SAAO,OAAA;;;YAEZ,sBAAsB,aAAa;;qBAUlC,QAAK,MAAU,cAAY,QAAQ"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { defineMessageUnion } from "foldkit/message";
|
|
3
|
+
// src/dom/share.ts
|
|
4
|
+
/**
|
|
5
|
+
* Web Share as a Command: runs in `update` beside any bundle, yields
|
|
6
|
+
* `Shared` on success. Dismissal is its own outcome, not a failure — the
|
|
7
|
+
* application tells a cancelled sheet apart from a broken one. Without a
|
|
8
|
+
* share API (desktop, insecure context) it yields `ShareFailed` instead of
|
|
9
|
+
* throwing, so `update` handles every outcome as a Message.
|
|
10
|
+
*/
|
|
11
|
+
const ShareData = Schema.Struct({
|
|
12
|
+
title: Schema.optional(Schema.String),
|
|
13
|
+
text: Schema.optional(Schema.String),
|
|
14
|
+
url: Schema.optional(Schema.String)
|
|
15
|
+
});
|
|
16
|
+
const ShareMessage = defineMessageUnion({
|
|
17
|
+
Shared: {},
|
|
18
|
+
Dismissed: {},
|
|
19
|
+
ShareFailed: { message: Schema.String }
|
|
20
|
+
});
|
|
21
|
+
const failMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
22
|
+
const isDismissal = (error) => typeof error?.name === "string" && error.name === "AbortError";
|
|
23
|
+
/** Shares data through the platform sheet. */
|
|
24
|
+
const share = (data) => ({
|
|
25
|
+
name: "Share.share",
|
|
26
|
+
args: { data },
|
|
27
|
+
effect: typeof navigator !== "undefined" && typeof navigator.share === "function" ? Effect.matchEffect(Effect.tryPromise({
|
|
28
|
+
try: () => navigator.share({
|
|
29
|
+
...data.title !== void 0 ? { title: data.title } : {},
|
|
30
|
+
...data.text !== void 0 ? { text: data.text } : {},
|
|
31
|
+
...data.url !== void 0 ? { url: data.url } : {}
|
|
32
|
+
}),
|
|
33
|
+
catch: (error) => error
|
|
34
|
+
}), {
|
|
35
|
+
onFailure: (error) => Effect.succeed(isDismissal(error) ? ShareMessage.Dismissed() : ShareMessage.ShareFailed({ message: failMessage(error) })),
|
|
36
|
+
onSuccess: () => Effect.succeed(ShareMessage.Shared())
|
|
37
|
+
}) : Effect.succeed(ShareMessage.ShareFailed({ message: "share is unavailable" }))
|
|
38
|
+
});
|
|
39
|
+
export { ShareData, ShareMessage, share };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=share.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share.js","names":[],"sources":["../../src/dom/share.ts"],"sourcesContent":["/**\n * Web Share as a Command: runs in `update` beside any bundle, yields\n * `Shared` on success. Dismissal is its own outcome, not a failure — the\n * application tells a cancelled sheet apart from a broken one. Without a\n * share API (desktop, insecure context) it yields `ShareFailed` instead of\n * throwing, so `update` handles every outcome as a Message.\n */\nimport { Effect, Schema } from 'effect'\nimport type { Command } from 'foldkit/command'\nimport { defineMessageUnion } from 'foldkit/message'\n\nexport const ShareData = Schema.Struct({\n title: Schema.optional(Schema.String),\n text: Schema.optional(Schema.String),\n url: Schema.optional(Schema.String),\n})\nexport type ShareData = typeof ShareData.Type\n\nexport const ShareMessage = defineMessageUnion({\n Shared: {},\n Dismissed: {},\n ShareFailed: { message: Schema.String },\n})\nexport type ShareMessage = typeof ShareMessage.Type\n\nconst failMessage = (error: unknown): string =>\n error instanceof Error ? error.message : String(error)\n\nconst isDismissal = (error: unknown): boolean =>\n typeof (error as { readonly name?: unknown } | null)?.name === 'string' &&\n (error as { readonly name: string }).name === 'AbortError'\n\n/** Shares data through the platform sheet. */\nexport const share = (data: ShareData): Command<ShareMessage, never, never> => ({\n name: 'Share.share',\n args: { data },\n effect:\n typeof navigator !== 'undefined' && typeof navigator.share === 'function'\n ? Effect.matchEffect(\n Effect.tryPromise({\n // Omit absent fields: the platform type rejects explicit\n // undefined under exactOptionalPropertyTypes.\n try: () =>\n navigator.share({\n ...(data.title !== undefined ? { title: data.title } : {}),\n ...(data.text !== undefined ? { text: data.text } : {}),\n ...(data.url !== undefined ? { url: data.url } : {}),\n }),\n catch: (error: unknown) => error,\n }),\n {\n onFailure: error =>\n Effect.succeed(\n isDismissal(error)\n ? ShareMessage.Dismissed()\n : ShareMessage.ShareFailed({ message: failMessage(error) }),\n ),\n onSuccess: () => Effect.succeed(ShareMessage.Shared()),\n },\n )\n : Effect.succeed(ShareMessage.ShareFailed({ message: 'share is unavailable' })),\n})\n"],"mappings":";;;;;;;;;;AAWA,MAAa,YAAY,OAAO,OAAO;CACrC,OAAO,OAAO,SAAS,OAAO,MAAM;CACpC,MAAM,OAAO,SAAS,OAAO,MAAM;CACnC,KAAK,OAAO,SAAS,OAAO,MAAM;AACpC,CAAC;AAGD,MAAa,eAAe,mBAAmB;CAC7C,QAAQ,CAAC;CACT,WAAW,CAAC;CACZ,aAAa,EAAE,SAAS,OAAO,OAAO;AACxC,CAAC;AAGD,MAAM,eAAe,UACnB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAEvD,MAAM,eAAe,UACnB,OAAQ,OAA8C,SAAS,YAC9D,MAAoC,SAAS;;AAGhD,MAAa,SAAS,UAA0D;CAC9E,MAAM;CACN,MAAM,EAAE,KAAK;CACb,QACE,OAAO,cAAc,eAAe,OAAO,UAAU,UAAU,aAC3D,OAAO,YACL,OAAO,WAAW;EAGhB,WACE,UAAU,MAAM;GACd,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GACxD,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;GACrD,GAAI,KAAK,QAAQ,KAAA,IAAY,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;EACpD,CAAC;EACH,QAAQ,UAAmB;CAC7B,CAAC,GACD;EACE,YAAW,UACT,OAAO,QACL,YAAY,KAAK,IACb,aAAa,UAAU,IACvB,aAAa,YAAY,EAAE,SAAS,YAAY,KAAK,EAAE,CAAC,CAC9D;EACF,iBAAiB,OAAO,QAAQ,aAAa,OAAO,CAAC;CACvD,CACF,IACA,OAAO,QAAQ,aAAa,YAAY,EAAE,SAAS,uBAAuB,CAAC,CAAC;AACpF"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import * as Mount from "foldkit/mount";
|
|
3
|
+
export declare const SwipeStarted: Schema.TaggedStruct<"SwipeStarted", {
|
|
4
|
+
readonly pointerId: Schema.Number;
|
|
5
|
+
readonly pointerType: Schema.String;
|
|
6
|
+
/** The border box of what `measure` names (the element itself by default), as the swipe starts. */
|
|
7
|
+
readonly width: Schema.Number;
|
|
8
|
+
readonly height: Schema.Number;
|
|
9
|
+
}>;
|
|
10
|
+
export type SwipeStarted = typeof SwipeStarted.Type;
|
|
11
|
+
export declare const Swiped: Schema.TaggedStruct<"Swiped", {
|
|
12
|
+
readonly pointerId: Schema.Number;
|
|
13
|
+
/** From where the pointer went down, in CSS pixels. */
|
|
14
|
+
readonly deltaX: Schema.Number;
|
|
15
|
+
readonly deltaY: Schema.Number;
|
|
16
|
+
}>;
|
|
17
|
+
export type Swiped = typeof Swiped.Type;
|
|
18
|
+
export declare const SwipeEnded: Schema.TaggedStruct<"SwipeEnded", {
|
|
19
|
+
readonly pointerId: Schema.Number;
|
|
20
|
+
/** From where the pointer went down to where it came up, in CSS pixels. */
|
|
21
|
+
readonly deltaX: Schema.Number;
|
|
22
|
+
readonly deltaY: Schema.Number;
|
|
23
|
+
/**
|
|
24
|
+
* How fast the pointer was moving as it came up, in pixels a millisecond,
|
|
25
|
+
* over the last `SWIPE_WINDOW` milliseconds: 0 when it rested there first.
|
|
26
|
+
*/
|
|
27
|
+
readonly velocityX: Schema.Number;
|
|
28
|
+
readonly velocityY: Schema.Number;
|
|
29
|
+
/** `false` when the pointer was cancelled or capture was lost. */
|
|
30
|
+
readonly completed: Schema.Boolean;
|
|
31
|
+
}>;
|
|
32
|
+
export type SwipeEnded = typeof SwipeEnded.Type;
|
|
33
|
+
export type SwipeFact = SwipeStarted | Swiped | SwipeEnded;
|
|
34
|
+
/** How far back, in milliseconds, the release velocity looks. */
|
|
35
|
+
export declare const SWIPE_WINDOW = 100;
|
|
36
|
+
/**
|
|
37
|
+
* What a swipe never starts on when its element `scrolls`: a field whose own
|
|
38
|
+
* drag selects text or moves a thumb, and anything marked `data-no-swipe`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const NO_SWIPE = "input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [data-no-swipe]";
|
|
41
|
+
interface Sample {
|
|
42
|
+
readonly at: number;
|
|
43
|
+
readonly x: number;
|
|
44
|
+
readonly y: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The velocity of the samples within `SWIPE_WINDOW` of the last: the way
|
|
48
|
+
* from the oldest of them to the last over the time between. A pointer that
|
|
49
|
+
* came to rest before the last sample has no recent way to measure, so 0.
|
|
50
|
+
*/
|
|
51
|
+
export declare const velocityOf: (samples: ReadonlyArray<Sample>) => {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Whether anything from `target` up to `root` can still scroll along `axis`
|
|
57
|
+
* the way a finger moving `along` (positive is down or right) pulls it: a
|
|
58
|
+
* finger going down scrolls content toward its start.
|
|
59
|
+
*/
|
|
60
|
+
export declare const canScroll: (target: Element, root: Element, axis: 'x' | 'y', along: number) => boolean;
|
|
61
|
+
/**
|
|
62
|
+
* `Move` with the speed of its release, for a gesture that a flick ends
|
|
63
|
+
* (a sheet dragged to dismiss, a card swiped away): a primary-button pointer
|
|
64
|
+
* down (or, given a `slop`, its first move past it) captures the pointer,
|
|
65
|
+
* each move reports the delta from where it was pressed, and up reports the
|
|
66
|
+
* last delta with the velocity over the last `SWIPE_WINDOW` milliseconds, by
|
|
67
|
+
* the events' own time stamps. Cancel or lost capture ends it incomplete.
|
|
68
|
+
* The start reports the size of what is moved, so a distance can be read as
|
|
69
|
+
* a share of it. What a delta or a speed means is the parent's `update`.
|
|
70
|
+
* Capture is released with the Mount.
|
|
71
|
+
*
|
|
72
|
+
* Given `scrolls`, the element holds content that scrolls (a sheet's panel),
|
|
73
|
+
* and a touch is followed by touch events, whose move can still refuse the
|
|
74
|
+
* browser's scroll once the touch is under way, where a pointer's cannot:
|
|
75
|
+
* past the slop, a touch that runs along the axis and finds nothing under it
|
|
76
|
+
* that can scroll further its way swipes, and the browser scrolls any other.
|
|
77
|
+
* A touch inside an element with a Swipe of its own (a handle in the panel)
|
|
78
|
+
* is that one's, and none starts on a field or on `data-no-swipe`
|
|
79
|
+
* (`NO_SWIPE`).
|
|
80
|
+
*/
|
|
81
|
+
export declare const Swipe: Mount.MountDefinitionWithArgs<"Swipe", {
|
|
82
|
+
/**
|
|
83
|
+
* The nearest ancestor matching this selector is measured as the swipe
|
|
84
|
+
* starts, for what the swipe moves (a sheet's panel, dragged by its
|
|
85
|
+
* handle). Default: the element itself.
|
|
86
|
+
*/
|
|
87
|
+
measure: Schema.optional<Schema.String>;
|
|
88
|
+
/**
|
|
89
|
+
* How far, in pixels, a press must move before it is a swipe. Until
|
|
90
|
+
* then nothing is captured or reported, so a press that stays put is
|
|
91
|
+
* still a click on whatever is under it (a tab inside a drag grip).
|
|
92
|
+
* Default 0: the press itself starts the swipe; with `scrolls`, the
|
|
93
|
+
* first move decides.
|
|
94
|
+
*/
|
|
95
|
+
slop: Schema.optional<Schema.Number>;
|
|
96
|
+
/** The axis the element's content scrolls along, which a touch yields to; see above. */
|
|
97
|
+
scrolls: Schema.optional<Schema.Literals<readonly ["x", "y"]>>;
|
|
98
|
+
/** Follows touches alone: a mouse or a pen is left to the page (and to a handle's own Swipe). */
|
|
99
|
+
touchOnly: Schema.optional<Schema.Boolean>;
|
|
100
|
+
}, {
|
|
101
|
+
readonly _tag: "SwipeStarted";
|
|
102
|
+
readonly pointerId: number;
|
|
103
|
+
readonly pointerType: string;
|
|
104
|
+
readonly width: number;
|
|
105
|
+
readonly height: number;
|
|
106
|
+
} | {
|
|
107
|
+
readonly _tag: "Swiped";
|
|
108
|
+
readonly pointerId: number;
|
|
109
|
+
readonly deltaX: number;
|
|
110
|
+
readonly deltaY: number;
|
|
111
|
+
} | {
|
|
112
|
+
readonly _tag: "SwipeEnded";
|
|
113
|
+
readonly pointerId: number;
|
|
114
|
+
readonly deltaX: number;
|
|
115
|
+
readonly deltaY: number;
|
|
116
|
+
readonly velocityX: number;
|
|
117
|
+
readonly velocityY: number;
|
|
118
|
+
readonly completed: boolean;
|
|
119
|
+
}>;
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=swipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swipe.d.ts","names":[],"sources":["../../src/dom/swipe.ts"],"mappings":";;qBAGa,cAAY,OAAA;;;;;;;YAOb,sBAAsB,aAAa;qBAElC,QAAM,OAAA;;;;;;YAMP,gBAAgB,OAAO;qBAEtB,YAAU,OAAA;;;;;;;;;;;;;;YAcX,oBAAoB,WAAW;YAE/B,YAAY,eAAe,SAAS;;qBAGnC;;;;;qBAMA;UAgBH;WACC;WACA;WACA;;;;;;;qBAmBE,aAAU,SAAa,cAAc;EAAY;EAAW;;;;;;;qBAe5D,YAAS,QACZ,SAAO,MACT,SAAO,iBACE;;;;;;;;;;;;;;;;;;;;;qBAoCJ,OAAK,MAAA"}
|