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 @@
|
|
|
1
|
+
{"version":3,"file":"move.d.ts","names":["Fact"],"sources":["../../src/interaction/move.ts"],"mappings":";;iBAYiB,gBAAgB,OAAO;WAC7B,cAAc;;WAEd,YAAY,MAAMA,WAAS;;qBAGzB,WACV,OAAK,OAAS,WACd,OAAO,eAAa,SACV,gBAAgB,OAAO,mBAC/B,SAAS,cAAc,OAAO,OAAO"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as Mount from "foldkit/mount";
|
|
2
|
+
import { Move, Move as mount, MoveEnded, MoveStarted, Moved } from "../dom/move.js";
|
|
3
|
+
import { Behavior, Capability } from "foldkit-mixins";
|
|
4
|
+
// src/interaction/move.ts
|
|
5
|
+
/**
|
|
6
|
+
* `Move` as a Behavior: attaches the `foldkit-primitives/dom` Mount to a
|
|
7
|
+
* draggable slot and maps its facts into the view's Messages. No Bundle: a
|
|
8
|
+
* drag's meaning (a threshold, a snap, a reorder) is the parent's `update`,
|
|
9
|
+
* and the deltas are already facts.
|
|
10
|
+
*/
|
|
11
|
+
const behavior = (slots) => (options) => Behavior.forSlots(slots)({ [options.handle]: Behavior.slot({
|
|
12
|
+
requires: { capability: Capability.Draggable },
|
|
13
|
+
mount: () => Mount.mapMessage(Move(), options.toMessage)
|
|
14
|
+
}) }, { name: "Move" });
|
|
15
|
+
export { MoveEnded, MoveStarted, Moved, behavior, mount };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=move.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move.js","names":["MoveMount"],"sources":["../../src/interaction/move.ts"],"sourcesContent":["/**\n * `Move` as a Behavior: attaches the `foldkit-primitives/dom` Mount to a\n * draggable slot and maps its facts into the view's Messages. No Bundle: a\n * drag's meaning (a threshold, a snap, a reorder) is the parent's `update`,\n * and the deltas are already facts.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { Move as MoveMount, type Fact } from '../dom/move.js'\n\nexport { Move as mount, MoveEnded, MoveStarted, Moved, type Fact } from '../dom/move.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n readonly handle: keyof Slots & string\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: Fact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.handle]: Behavior.slot({\n requires: { capability: Capability.Draggable },\n mount: () => Mount.mapMessage(MoveMount(), options.toMessage),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'Move' },\n )\n"],"mappings":";;;;;;;;;;AAkBA,MAAa,YACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,SAAS,SAAS,KAAK;CAC9B,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aAAa,MAAM,WAAWA,KAAU,GAAG,QAAQ,SAAS;AAC9D,CAAC,EAEH,GACA,EAAE,MAAM,OAAO,CACjB"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Declared } from "foldkit-bundle";
|
|
2
|
+
import { NamedBehavior } from "foldkit-mixins";
|
|
3
|
+
import { bundle } from "./dismiss-layer.js";
|
|
4
|
+
export interface DismissPolicy {
|
|
5
|
+
/** Dismiss on a press outside. Default `true`. */
|
|
6
|
+
readonly outside: boolean;
|
|
7
|
+
/** Dismiss on Escape when topmost. Default `true`. */
|
|
8
|
+
readonly escape: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface FocusPolicy {
|
|
11
|
+
/** Keep Tab, Shift+Tab, and stray focus inside. Default `true`. */
|
|
12
|
+
readonly contain: boolean;
|
|
13
|
+
/** Give focus back to what had it on unmount. Default `true`. */
|
|
14
|
+
readonly restore: boolean;
|
|
15
|
+
/** A selector inside the layer to focus first. */
|
|
16
|
+
readonly initialFocus?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Policy {
|
|
19
|
+
readonly dismiss: DismissPolicy;
|
|
20
|
+
readonly focus: FocusPolicy;
|
|
21
|
+
/** Lock the document's scroll while mounted. */
|
|
22
|
+
readonly scroll: {
|
|
23
|
+
readonly lock: boolean;
|
|
24
|
+
};
|
|
25
|
+
/** Mark everything outside inert while mounted. */
|
|
26
|
+
readonly inert: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** A modal overlay: dismissed by Escape and outside press, focused, locked, inert. */
|
|
29
|
+
export declare const modal: Policy;
|
|
30
|
+
/** A modeless overlay: dismissed by Escape and outside press, focus restored, page usable. */
|
|
31
|
+
export declare const nonModal: Policy;
|
|
32
|
+
/**
|
|
33
|
+
* The policy as behaviors, to spread into the view's pipe alongside the
|
|
34
|
+
* widget's own. Conditional pieces are included or left out when the list
|
|
35
|
+
* is built — a static policy per composition — so no slot carries a mount
|
|
36
|
+
* its policy never uses.
|
|
37
|
+
*/
|
|
38
|
+
export declare const behaviors: <Slots>(slots: Slots) => <Input, ParentMessage, StackField extends string>(options: {
|
|
39
|
+
readonly stack: Declared<typeof bundle, StackField>;
|
|
40
|
+
readonly layer: keyof Slots & string;
|
|
41
|
+
readonly trigger?: keyof Slots & string;
|
|
42
|
+
readonly id: (input: Input) => string;
|
|
43
|
+
readonly policy: Policy;
|
|
44
|
+
}) => ReadonlyArray<NamedBehavior<Slots, Input, ParentMessage>>;
|
|
45
|
+
//# sourceMappingURL=overlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.d.ts","names":["dismissLayerBundle"],"sources":["../../src/interaction/overlay.ts"],"mappings":";;;iBAwBiB;;WAEN;;WAEA;;iBAGM;;WAEN;;WAEA;;WAEA;;iBAGM;WACN,SAAS;WACT,OAAO;;WAEP;aAAmB;;;WAEnB;;;qBAIE,OAAO;;qBAQP,UAAU;;;;;;;qBAaV,YACV,OAAK,OAAS,WACd,OAAO,eAAe,2BAAyB;WACrC,OAAO,gBAAgBA,QAAoB;WAC3C,aAAa;WACb,gBAAgB;WAChB,KAAK,OAAO;WACZ,QAAQ;MACf,cAAc,cAAc,OAAO,OAAO"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import "foldkit-mixins";
|
|
2
|
+
import { behavior } from "./dismiss-layer.js";
|
|
3
|
+
import { behavior as behavior$1 } from "./focus-scope.js";
|
|
4
|
+
import { hideOutside, scrollLock } from "./layers.js";
|
|
5
|
+
// src/interaction/overlay.ts
|
|
6
|
+
/** A modal overlay: dismissed by Escape and outside press, focused, locked, inert. */
|
|
7
|
+
const modal = {
|
|
8
|
+
dismiss: {
|
|
9
|
+
outside: true,
|
|
10
|
+
escape: true
|
|
11
|
+
},
|
|
12
|
+
focus: {
|
|
13
|
+
contain: true,
|
|
14
|
+
restore: true
|
|
15
|
+
},
|
|
16
|
+
scroll: { lock: true },
|
|
17
|
+
inert: true
|
|
18
|
+
};
|
|
19
|
+
/** A modeless overlay: dismissed by Escape and outside press, focus restored, page usable. */
|
|
20
|
+
const nonModal = {
|
|
21
|
+
dismiss: {
|
|
22
|
+
outside: true,
|
|
23
|
+
escape: true
|
|
24
|
+
},
|
|
25
|
+
focus: {
|
|
26
|
+
contain: false,
|
|
27
|
+
restore: true
|
|
28
|
+
},
|
|
29
|
+
scroll: { lock: false },
|
|
30
|
+
inert: false
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The policy as behaviors, to spread into the view's pipe alongside the
|
|
34
|
+
* widget's own. Conditional pieces are included or left out when the list
|
|
35
|
+
* is built — a static policy per composition — so no slot carries a mount
|
|
36
|
+
* its policy never uses.
|
|
37
|
+
*/
|
|
38
|
+
const behaviors = (slots) => (options) => [
|
|
39
|
+
behavior(options.stack)(slots)({
|
|
40
|
+
layer: options.layer,
|
|
41
|
+
...options.trigger === void 0 ? {} : { trigger: options.trigger },
|
|
42
|
+
id: options.id,
|
|
43
|
+
outsidePress: options.policy.dismiss.outside,
|
|
44
|
+
escape: options.policy.dismiss.escape
|
|
45
|
+
}),
|
|
46
|
+
behavior$1(slots)({
|
|
47
|
+
container: options.layer,
|
|
48
|
+
contain: options.policy.focus.contain,
|
|
49
|
+
restore: options.policy.focus.restore,
|
|
50
|
+
...options.policy.focus.initialFocus === void 0 ? {} : { initialFocus: options.policy.focus.initialFocus }
|
|
51
|
+
}),
|
|
52
|
+
...options.policy.scroll.lock ? [scrollLock(slots)({ container: options.layer })] : [],
|
|
53
|
+
...options.policy.inert ? [hideOutside(slots)({ container: options.layer })] : []
|
|
54
|
+
];
|
|
55
|
+
export { behaviors, modal, nonModal };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","names":["dismissLayerBehavior","focusScopeBehavior"],"sources":["../../src/interaction/overlay.ts"],"sourcesContent":["/**\n * One overlay policy value instead of nine subtly different overlay\n * implementations. `modal` and `nonModal` cover the two shapes; anything\n * else is an explicit `Policy`. `behaviors` turns a policy into the\n * existing pieces — `DismissLayer` marking, `FocusScope`, `ScrollLock`,\n * `HideOutside` — attached to one layer slot, with nothing reimplemented:\n * the mounts are the shared implementation, and the data attributes are the\n * stack's protocol. Positioning stays per-widget (`Anchor.behavior`\n * directly): it binds a floating element to an external id, a different\n * shape than this layer policy. Presence stays CSS (`data-open`): it needs\n * a per-overlay placement, which is the Drawer's, not the policy's.\n *\n * The `DismissLayer` stack bundle itself is placed once per app, not per\n * overlay; its `Dismiss` outmessage reaches the app through the placement's\n * `onOut`, which closes the dismissed layers. The id `behaviors` writes is\n * the layer attribute (`data-foldkit-plus-layer`), not an element id:\n * `aria-controls` has to name an element that exists.\n */\nimport type { Declared } from 'foldkit-bundle'\nimport { Behavior, type NamedBehavior } from 'foldkit-mixins'\nimport { behavior as dismissLayerBehavior, bundle as dismissLayerBundle } from './dismiss-layer.js'\nimport { behavior as focusScopeBehavior } from './focus-scope.js'\nimport { hideOutside, scrollLock } from './layers.js'\n\nexport interface DismissPolicy {\n /** Dismiss on a press outside. Default `true`. */\n readonly outside: boolean\n /** Dismiss on Escape when topmost. Default `true`. */\n readonly escape: boolean\n}\n\nexport interface FocusPolicy {\n /** Keep Tab, Shift+Tab, and stray focus inside. Default `true`. */\n readonly contain: boolean\n /** Give focus back to what had it on unmount. Default `true`. */\n readonly restore: boolean\n /** A selector inside the layer to focus first. */\n readonly initialFocus?: string\n}\n\nexport interface Policy {\n readonly dismiss: DismissPolicy\n readonly focus: FocusPolicy\n /** Lock the document's scroll while mounted. */\n readonly scroll: { readonly lock: boolean }\n /** Mark everything outside inert while mounted. */\n readonly inert: boolean\n}\n\n/** A modal overlay: dismissed by Escape and outside press, focused, locked, inert. */\nexport const modal: Policy = {\n dismiss: { outside: true, escape: true },\n focus: { contain: true, restore: true },\n scroll: { lock: true },\n inert: true,\n}\n\n/** A modeless overlay: dismissed by Escape and outside press, focus restored, page usable. */\nexport const nonModal: Policy = {\n dismiss: { outside: true, escape: true },\n focus: { contain: false, restore: true },\n scroll: { lock: false },\n inert: false,\n}\n\n/**\n * The policy as behaviors, to spread into the view's pipe alongside the\n * widget's own. Conditional pieces are included or left out when the list\n * is built — a static policy per composition — so no slot carries a mount\n * its policy never uses.\n */\nexport const behaviors =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage, StackField extends string>(options: {\n readonly stack: Declared<typeof dismissLayerBundle, StackField>\n readonly layer: keyof Slots & string\n readonly trigger?: keyof Slots & string\n readonly id: (input: Input) => string\n readonly policy: Policy\n }): ReadonlyArray<NamedBehavior<Slots, Input, ParentMessage>> => [\n dismissLayerBehavior(options.stack)(slots)<Input, ParentMessage>({\n layer: options.layer,\n ...(options.trigger === undefined ? {} : { trigger: options.trigger }),\n id: options.id,\n outsidePress: options.policy.dismiss.outside,\n escape: options.policy.dismiss.escape,\n }),\n focusScopeBehavior(slots)<Input, ParentMessage>({\n container: options.layer,\n contain: options.policy.focus.contain,\n restore: options.policy.focus.restore,\n ...(options.policy.focus.initialFocus === undefined\n ? {}\n : { initialFocus: options.policy.focus.initialFocus }),\n }),\n ...(options.policy.scroll.lock\n ? [scrollLock(slots)<Input, ParentMessage>({ container: options.layer })]\n : []),\n ...(options.policy.inert\n ? [hideOutside(slots)<Input, ParentMessage>({ container: options.layer })]\n : []),\n ]\n"],"mappings":";;;;;;AAkDA,MAAa,QAAgB;CAC3B,SAAS;EAAE,SAAS;EAAM,QAAQ;CAAK;CACvC,OAAO;EAAE,SAAS;EAAM,SAAS;CAAK;CACtC,QAAQ,EAAE,MAAM,KAAK;CACrB,OAAO;AACT;;AAGA,MAAa,WAAmB;CAC9B,SAAS;EAAE,SAAS;EAAM,QAAQ;CAAK;CACvC,OAAO;EAAE,SAAS;EAAO,SAAS;CAAK;CACvC,QAAQ,EAAE,MAAM,MAAM;CACtB,OAAO;AACT;;;;;;;AAQA,MAAa,aACH,WAC0C,YAMe;CAC/DA,SAAqB,QAAQ,KAAK,CAAC,CAAC,KAAK,CAAC,CAAuB;EAC/D,OAAO,QAAQ;EACf,GAAI,QAAQ,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;EACpE,IAAI,QAAQ;EACZ,cAAc,QAAQ,OAAO,QAAQ;EACrC,QAAQ,QAAQ,OAAO,QAAQ;CACjC,CAAC;CACDC,WAAmB,KAAK,CAAC,CAAuB;EAC9C,WAAW,QAAQ;EACnB,SAAS,QAAQ,OAAO,MAAM;EAC9B,SAAS,QAAQ,OAAO,MAAM;EAC9B,GAAI,QAAQ,OAAO,MAAM,iBAAiB,KAAA,IACtC,CAAC,IACD,EAAE,cAAc,QAAQ,OAAO,MAAM,aAAa;CACxD,CAAC;CACD,GAAI,QAAQ,OAAO,OAAO,OACtB,CAAC,WAAW,KAAK,CAAC,CAAuB,EAAE,WAAW,QAAQ,MAAM,CAAC,CAAC,IACtE,CAAC;CACL,GAAI,QAAQ,OAAO,QACf,CAAC,YAAY,KAAK,CAAC,CAAuB,EAAE,WAAW,QAAQ,MAAM,CAAC,CAAC,IACvE,CAAC;AACP"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Option, Schema } from "effect";
|
|
2
|
+
import * as Mount from "foldkit/mount";
|
|
3
|
+
import { Behavior } from "foldkit-mixins";
|
|
4
|
+
export interface PanelRect {
|
|
5
|
+
readonly top: number;
|
|
6
|
+
readonly right: number;
|
|
7
|
+
readonly bottom: number;
|
|
8
|
+
readonly height: number;
|
|
9
|
+
}
|
|
10
|
+
export interface Viewport {
|
|
11
|
+
readonly width: number;
|
|
12
|
+
readonly height: number;
|
|
13
|
+
}
|
|
14
|
+
export interface Placed {
|
|
15
|
+
/** Pixels to move left; `0` when the panel fits. */
|
|
16
|
+
readonly dx: number;
|
|
17
|
+
/** Whether the panel stands above its trigger instead of below. */
|
|
18
|
+
readonly flip: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Where the panel goes so it fits: left by the overflow, above when the
|
|
21
|
+
* bottom clears the window and the room overhead fits the panel. */
|
|
22
|
+
export declare const placeFor: (rect: PanelRect, viewport: Viewport, margin?: number) => Placed;
|
|
23
|
+
/** Pixels to move a box up so its bottom sits `margin` inside the viewport.
|
|
24
|
+
* `0` when it already fits, or when its top is already at the margin. */
|
|
25
|
+
export declare const shiftIntoViewport: (rect: {
|
|
26
|
+
readonly top: number;
|
|
27
|
+
readonly bottom: number;
|
|
28
|
+
}, viewportHeight: number, margin?: number) => number;
|
|
29
|
+
/** Attribute `keepWithin` sets to `placedAbove` when the panel flips. */
|
|
30
|
+
export declare const placedSide = "data-fk-placed";
|
|
31
|
+
/** Value of `placedSide` while the panel stands above its anchor. */
|
|
32
|
+
export declare const placedAbove = "above";
|
|
33
|
+
export interface AnchorRect {
|
|
34
|
+
readonly left: number;
|
|
35
|
+
readonly top: number;
|
|
36
|
+
readonly bottom: number;
|
|
37
|
+
readonly width: number;
|
|
38
|
+
readonly height: number;
|
|
39
|
+
}
|
|
40
|
+
export interface OriginRect {
|
|
41
|
+
readonly left: number;
|
|
42
|
+
readonly top: number;
|
|
43
|
+
}
|
|
44
|
+
export interface PlacedAt {
|
|
45
|
+
readonly left: number;
|
|
46
|
+
readonly top: number;
|
|
47
|
+
}
|
|
48
|
+
/** Custom property `PlaceAt` writes. A panel reads it as `top` so a viewport
|
|
49
|
+
* flip, which sets the `top` property, still wins. */
|
|
50
|
+
export declare const placedTop = "--fk-placed-top";
|
|
51
|
+
/** Where a popup sits under its trigger's left edge, in the offset parent's
|
|
52
|
+
* coordinates. A zero-size trigger (an inert document) stays at the origin. */
|
|
53
|
+
export declare const placeAt: (trigger: AnchorRect, origin: OriginRect, gap?: number) => PlacedAt;
|
|
54
|
+
export interface ViewportPoint {
|
|
55
|
+
readonly x: number;
|
|
56
|
+
readonly y: number;
|
|
57
|
+
}
|
|
58
|
+
/** Where a popup's top-left sits on a viewport point, in the offset parent's
|
|
59
|
+
* coordinates. A context menu uses it: the right-click event carries the
|
|
60
|
+
* point, and `OnContextMenu` does not. */
|
|
61
|
+
export declare const placeAtPoint: (point: ViewportPoint, origin: OriginRect) => PlacedAt;
|
|
62
|
+
export declare const KeepWithin: Mount.MountDefinitionNoArgs<"KeepWithin", never>;
|
|
63
|
+
export declare const PlaceAt: Mount.MountDefinitionWithArgs<"PlaceAt", {
|
|
64
|
+
/** Element id of the trigger the popup opens under. */
|
|
65
|
+
triggerId: Schema.String;
|
|
66
|
+
/** Pixels between the trigger's bottom and the popup. */
|
|
67
|
+
gap: Schema.Number;
|
|
68
|
+
}, never>;
|
|
69
|
+
export declare const PlaceAtPoint: Mount.MountDefinitionWithArgs<"PlaceAtPoint", {
|
|
70
|
+
/** Viewport x of the popup's top-left. */
|
|
71
|
+
x: Schema.Number;
|
|
72
|
+
/** Viewport y of the popup's top-left. */
|
|
73
|
+
y: Schema.Number;
|
|
74
|
+
}, never>;
|
|
75
|
+
export declare const placeAtTrigger: <Slots>(slots: Slots) => <Input, ParentMessage>(options: {
|
|
76
|
+
readonly panel: keyof Slots & string;
|
|
77
|
+
/** The trigger this open belongs to. Read at insert, so key the panel by it. */
|
|
78
|
+
readonly triggerId: (input: Input) => string;
|
|
79
|
+
readonly gap?: number;
|
|
80
|
+
/** A viewport point wins over the trigger. None places under `triggerId`. */
|
|
81
|
+
readonly at?: (input: Input) => Option.Option<ViewportPoint>;
|
|
82
|
+
}) => Behavior.NamedBehavior<Slots, Input, ParentMessage>;
|
|
83
|
+
export declare const keepWithin: <Slots>(slots: Slots) => <Input, ParentMessage>(options: {
|
|
84
|
+
readonly panel: keyof Slots & string;
|
|
85
|
+
}) => Behavior.NamedBehavior<Slots, Input, ParentMessage>;
|
|
86
|
+
//# sourceMappingURL=placing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placing.d.ts","names":[],"sources":["../../src/interaction/placing.ts"],"mappings":";;;iBAuCiB;WACN;WACA;WACA;WACA;;iBAGM;WACN;WACA;;iBAGM;;WAEN;;WAEA;;;;qBAKE,WAAQ,MAAU,WAAS,UAAY,UAAQ,oBAAe;;;qBAU9D,oBAAiB;WACX;WAAsB;GAAgB,wBACjC;;qBAWX;;qBAGA;iBAEI;WACN;WACA;WACA;WACA;WACA;;iBAGM;WACN;WACA;;iBAGM;WACN;WACA;;;;qBAKE;;;qBAIA,UAAO,SAAa,YAAU,QAAU,YAAU,iBAAY;iBAQ1D;WACN;WACA;;;;;qBAME,eAAY,OAAW,eAAa,QAAU,eAAa;qBAyE3D,YAAU,MAAA;qBAkCV,SAAO,MAAA;;;;;;qBAyCP,cAAY,MAAA;;;;;;qBA0BZ,iBACV,OAAK,OAAS,WACd,OAAO,eAAa;WACV,aAAa;;WAEb,YAAY,OAAO;WACnB;;WAEA,MAAM,OAAO,UAAU,OAAO,OAAO;MAC5C,SAAS,cAAc,OAAO,OAAO;qBAiB9B,aACV,OAAK,OAAS,WACd,OAAO,eAAa;WACV,aAAa;MACpB,SAAS,cAAc,OAAO,OAAO"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { Effect, Option, Schema, Stream } from "effect";
|
|
2
|
+
import * as Mount from "foldkit/mount";
|
|
3
|
+
import { Behavior, Capability } from "foldkit-mixins";
|
|
4
|
+
// src/interaction/placing.ts
|
|
5
|
+
/**
|
|
6
|
+
* Keeps a floating panel inside the viewport: on insert it shifts left past
|
|
7
|
+
* the right edge and flips above its trigger when the bottom overflows and
|
|
8
|
+
* the room overhead fits; on release every inline prop goes. `placeFor` is
|
|
9
|
+
* pure geometry over rects, so the rule is unit-tested and the Mount only
|
|
10
|
+
* reads and writes. Inert without layout (zero rects never overflow), with
|
|
11
|
+
* no timers, observers, or reposition loops.
|
|
12
|
+
*
|
|
13
|
+
* `placeAt` is the other half, for a popup that must open under the trigger
|
|
14
|
+
* that opened it. It writes `left` and `--fk-placed-top` once, relative to
|
|
15
|
+
* the popup's offset parent; the panel's stylesheet reads the variable as
|
|
16
|
+
* `top`, so `keepWithin` can still replace `top` when it flips. Key the
|
|
17
|
+
* popup by the trigger: a Mount reads its args at insert and never again.
|
|
18
|
+
* `placeAtPoint` is the same write for a viewport point, when the open
|
|
19
|
+
* event carried coordinates the message builder dropped. The two mounts
|
|
20
|
+
* start together, so the fit may run before that write; the write measures
|
|
21
|
+
* again. A point that would hang past the bottom shifts up. A trigger still
|
|
22
|
+
* flips, and the panel is marked `data-fk-placed="above"` so a hover bridge
|
|
23
|
+
* can follow the side that opened.
|
|
24
|
+
* Zero-size rects stay at the origin, so an inert document writes nothing
|
|
25
|
+
* a layout pass would have to undo.
|
|
26
|
+
*
|
|
27
|
+
* Three related pieces this is not:
|
|
28
|
+
*
|
|
29
|
+
* - `Anchor.behavior` (`foldkit-mixins-ui`) binds a floating element to
|
|
30
|
+
* another element's id through floating-ui, with portals and continuous
|
|
31
|
+
* repositioning. It relocates nodes out from under the runtime (portal by
|
|
32
|
+
* default) and burns under zero geometry; reach for it when the panel must
|
|
33
|
+
* track a moving anchor, not for a popup placed once.
|
|
34
|
+
* - `KeepInView` (`foldkit-primitives/dom`) scrolls newly marked content
|
|
35
|
+
* into view. Same verb, opposite direction: that one moves the page to
|
|
36
|
+
* the panel, this one moves the panel into the page.
|
|
37
|
+
* - `Overlay.behaviors` owns dismissal, focus, scroll lock, and inertness,
|
|
38
|
+
* but no positioning; spread this alongside it for the full overlay.
|
|
39
|
+
*/
|
|
40
|
+
/** Where the panel goes so it fits: left by the overflow, above when the
|
|
41
|
+
* bottom clears the window and the room overhead fits the panel. */
|
|
42
|
+
const placeFor = (rect, viewport, margin = 8) => {
|
|
43
|
+
const over = rect.right - viewport.width + margin;
|
|
44
|
+
return {
|
|
45
|
+
dx: over > 0 ? -over : 0,
|
|
46
|
+
flip: rect.bottom > viewport.height && rect.top - margin >= rect.height
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** Pixels to move a box up so its bottom sits `margin` inside the viewport.
|
|
50
|
+
* `0` when it already fits, or when its top is already at the margin. */
|
|
51
|
+
const shiftIntoViewport = (rect, viewportHeight, margin = 8) => {
|
|
52
|
+
const overflow = rect.bottom - (viewportHeight - margin);
|
|
53
|
+
if (overflow <= 0) return 0;
|
|
54
|
+
const room = rect.top - margin;
|
|
55
|
+
if (room <= 0) return 0;
|
|
56
|
+
return Math.min(overflow, room);
|
|
57
|
+
};
|
|
58
|
+
/** Attribute `keepWithin` sets to `placedAbove` when the panel flips. */
|
|
59
|
+
const placedSide = "data-fk-placed";
|
|
60
|
+
/** Value of `placedSide` while the panel stands above its anchor. */
|
|
61
|
+
const placedAbove = "above";
|
|
62
|
+
/** Custom property `PlaceAt` writes. A panel reads it as `top` so a viewport
|
|
63
|
+
* flip, which sets the `top` property, still wins. */
|
|
64
|
+
const placedTop = "--fk-placed-top";
|
|
65
|
+
/** Where a popup sits under its trigger's left edge, in the offset parent's
|
|
66
|
+
* coordinates. A zero-size trigger (an inert document) stays at the origin. */
|
|
67
|
+
const placeAt = (trigger, origin, gap = 4) => {
|
|
68
|
+
if (trigger.width === 0 && trigger.height === 0) return {
|
|
69
|
+
left: 0,
|
|
70
|
+
top: 0
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
left: trigger.left - origin.left,
|
|
74
|
+
top: trigger.bottom - origin.top + gap
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
/** Where a popup's top-left sits on a viewport point, in the offset parent's
|
|
78
|
+
* coordinates. A context menu uses it: the right-click event carries the
|
|
79
|
+
* point, and `OnContextMenu` does not. */
|
|
80
|
+
const placeAtPoint = (point, origin) => ({
|
|
81
|
+
left: point.x - origin.left,
|
|
82
|
+
top: point.y - origin.top
|
|
83
|
+
});
|
|
84
|
+
const clearFit = (element) => {
|
|
85
|
+
element.style.translate = "";
|
|
86
|
+
element.style.top = "";
|
|
87
|
+
element.style.bottom = "";
|
|
88
|
+
element.removeAttribute(placedSide);
|
|
89
|
+
};
|
|
90
|
+
const fitWithin = (element) => {
|
|
91
|
+
clearFit(element);
|
|
92
|
+
const rect = element.getBoundingClientRect();
|
|
93
|
+
const placed = placeFor({
|
|
94
|
+
top: rect.top,
|
|
95
|
+
right: rect.right,
|
|
96
|
+
bottom: rect.bottom,
|
|
97
|
+
height: rect.height
|
|
98
|
+
}, {
|
|
99
|
+
width: document.documentElement.clientWidth,
|
|
100
|
+
height: window.innerHeight
|
|
101
|
+
});
|
|
102
|
+
if (placed.dx !== 0) element.style.translate = `${placed.dx}px 0`;
|
|
103
|
+
if (placed.flip) {
|
|
104
|
+
element.style.top = "auto";
|
|
105
|
+
element.style.bottom = "calc(100% + 4px)";
|
|
106
|
+
element.setAttribute(placedSide, placedAbove);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const refits = /* @__PURE__ */ new WeakMap();
|
|
110
|
+
const onPlaced = (element, refit) => {
|
|
111
|
+
const waiting = refits.get(element) ?? /* @__PURE__ */ new Set();
|
|
112
|
+
waiting.add(refit);
|
|
113
|
+
refits.set(element, waiting);
|
|
114
|
+
};
|
|
115
|
+
const offPlaced = (element, refit) => {
|
|
116
|
+
const waiting = refits.get(element);
|
|
117
|
+
if (waiting === void 0) return;
|
|
118
|
+
waiting.delete(refit);
|
|
119
|
+
if (waiting.size === 0) refits.delete(element);
|
|
120
|
+
};
|
|
121
|
+
const notifyPlaced = (element) => {
|
|
122
|
+
const waiting = refits.get(element);
|
|
123
|
+
if (waiting === void 0) return;
|
|
124
|
+
for (const refit of waiting) refit();
|
|
125
|
+
};
|
|
126
|
+
const applyPlaced = (element, placed) => {
|
|
127
|
+
element.style.left = `${placed.left}px`;
|
|
128
|
+
element.style.setProperty(placedTop, `${placed.top}px`);
|
|
129
|
+
};
|
|
130
|
+
const clearPlaced = (element) => {
|
|
131
|
+
element.style.left = "";
|
|
132
|
+
element.style.removeProperty(placedTop);
|
|
133
|
+
};
|
|
134
|
+
const writePlaced = (element, placed, shift) => {
|
|
135
|
+
clearFit(element);
|
|
136
|
+
applyPlaced(element, placed);
|
|
137
|
+
if (shift) {
|
|
138
|
+
const rect = element.getBoundingClientRect();
|
|
139
|
+
const dy = shiftIntoViewport({
|
|
140
|
+
top: rect.top,
|
|
141
|
+
bottom: rect.bottom
|
|
142
|
+
}, window.innerHeight);
|
|
143
|
+
if (dy !== 0) element.style.setProperty(placedTop, `${placed.top - dy}px`);
|
|
144
|
+
}
|
|
145
|
+
notifyPlaced(element);
|
|
146
|
+
};
|
|
147
|
+
const KeepWithin = Mount.defineStream("KeepWithin", {
|
|
148
|
+
messages: [Schema.Never],
|
|
149
|
+
execute: ({ element }) => Stream.callback(() => {
|
|
150
|
+
if (!(element instanceof HTMLElement)) return Effect.acquireRelease(Effect.void, () => Effect.void);
|
|
151
|
+
const node = element;
|
|
152
|
+
const refit = () => fitWithin(node);
|
|
153
|
+
return Effect.acquireRelease(Effect.sync(() => {
|
|
154
|
+
onPlaced(node, refit);
|
|
155
|
+
refit();
|
|
156
|
+
}), () => Effect.sync(() => {
|
|
157
|
+
offPlaced(node, refit);
|
|
158
|
+
clearFit(node);
|
|
159
|
+
}));
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
const paddingEdge = (node) => {
|
|
163
|
+
const rect = node.getBoundingClientRect();
|
|
164
|
+
return {
|
|
165
|
+
left: rect.left + node.clientLeft,
|
|
166
|
+
top: rect.top + node.clientTop
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
const originOf = (element) => {
|
|
170
|
+
const originNode = element.offsetParent;
|
|
171
|
+
return originNode instanceof HTMLElement ? paddingEdge(originNode) : {
|
|
172
|
+
left: 0,
|
|
173
|
+
top: 0
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
const PlaceAt = Mount.defineStream("PlaceAt", {
|
|
177
|
+
messages: [Schema.Never],
|
|
178
|
+
args: {
|
|
179
|
+
/** Element id of the trigger the popup opens under. */
|
|
180
|
+
triggerId: Schema.String,
|
|
181
|
+
/** Pixels between the trigger's bottom and the popup. */
|
|
182
|
+
gap: Schema.Number
|
|
183
|
+
},
|
|
184
|
+
execute: ({ element, triggerId, gap }) => Stream.callback(() => Effect.acquireRelease(Effect.sync(() => {
|
|
185
|
+
if (!(element instanceof HTMLElement)) return;
|
|
186
|
+
const trigger = document.getElementById(triggerId);
|
|
187
|
+
if (!(trigger instanceof HTMLElement)) return;
|
|
188
|
+
const rect = trigger.getBoundingClientRect();
|
|
189
|
+
writePlaced(element, placeAt({
|
|
190
|
+
left: rect.left,
|
|
191
|
+
top: rect.top,
|
|
192
|
+
bottom: rect.bottom,
|
|
193
|
+
width: rect.width,
|
|
194
|
+
height: rect.height
|
|
195
|
+
}, originOf(element), gap), false);
|
|
196
|
+
}), () => Effect.sync(() => {
|
|
197
|
+
if (!(element instanceof HTMLElement)) return;
|
|
198
|
+
clearPlaced(element);
|
|
199
|
+
})))
|
|
200
|
+
});
|
|
201
|
+
const PlaceAtPoint = Mount.defineStream("PlaceAtPoint", {
|
|
202
|
+
messages: [Schema.Never],
|
|
203
|
+
args: {
|
|
204
|
+
/** Viewport x of the popup's top-left. */
|
|
205
|
+
x: Schema.Number,
|
|
206
|
+
/** Viewport y of the popup's top-left. */
|
|
207
|
+
y: Schema.Number
|
|
208
|
+
},
|
|
209
|
+
execute: ({ element, x, y }) => Stream.callback(() => Effect.acquireRelease(Effect.sync(() => {
|
|
210
|
+
if (!(element instanceof HTMLElement)) return;
|
|
211
|
+
writePlaced(element, placeAtPoint({
|
|
212
|
+
x,
|
|
213
|
+
y
|
|
214
|
+
}, originOf(element)), true);
|
|
215
|
+
}), () => Effect.sync(() => {
|
|
216
|
+
if (!(element instanceof HTMLElement)) return;
|
|
217
|
+
clearPlaced(element);
|
|
218
|
+
})))
|
|
219
|
+
});
|
|
220
|
+
const placeAtTrigger = (slots) => (options) => Behavior.forSlots(slots)({ [options.panel]: Behavior.slot({
|
|
221
|
+
requires: { capability: Capability.Container },
|
|
222
|
+
mount: (input) => {
|
|
223
|
+
const at = options.at?.(input) ?? Option.none();
|
|
224
|
+
return Option.isSome(at) ? PlaceAtPoint({
|
|
225
|
+
x: at.value.x,
|
|
226
|
+
y: at.value.y
|
|
227
|
+
}) : PlaceAt({
|
|
228
|
+
triggerId: options.triggerId(input),
|
|
229
|
+
gap: options.gap ?? 4
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}) }, { name: "PlaceAt" });
|
|
233
|
+
const keepWithin = (slots) => (options) => Behavior.forSlots(slots)({ [options.panel]: Behavior.slot({
|
|
234
|
+
requires: { capability: Capability.Container },
|
|
235
|
+
mount: () => KeepWithin()
|
|
236
|
+
}) }, { name: "KeepWithin" });
|
|
237
|
+
export { KeepWithin, PlaceAt, PlaceAtPoint, keepWithin, placeAt, placeAtPoint, placeAtTrigger, placeFor, placedAbove, placedSide, placedTop, shiftIntoViewport };
|
|
238
|
+
|
|
239
|
+
//# sourceMappingURL=placing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placing.js","names":[],"sources":["../../src/interaction/placing.ts"],"sourcesContent":["/**\n * Keeps a floating panel inside the viewport: on insert it shifts left past\n * the right edge and flips above its trigger when the bottom overflows and\n * the room overhead fits; on release every inline prop goes. `placeFor` is\n * pure geometry over rects, so the rule is unit-tested and the Mount only\n * reads and writes. Inert without layout (zero rects never overflow), with\n * no timers, observers, or reposition loops.\n *\n * `placeAt` is the other half, for a popup that must open under the trigger\n * that opened it. It writes `left` and `--fk-placed-top` once, relative to\n * the popup's offset parent; the panel's stylesheet reads the variable as\n * `top`, so `keepWithin` can still replace `top` when it flips. Key the\n * popup by the trigger: a Mount reads its args at insert and never again.\n * `placeAtPoint` is the same write for a viewport point, when the open\n * event carried coordinates the message builder dropped. The two mounts\n * start together, so the fit may run before that write; the write measures\n * again. A point that would hang past the bottom shifts up. A trigger still\n * flips, and the panel is marked `data-fk-placed=\"above\"` so a hover bridge\n * can follow the side that opened.\n * Zero-size rects stay at the origin, so an inert document writes nothing\n * a layout pass would have to undo.\n *\n * Three related pieces this is not:\n *\n * - `Anchor.behavior` (`foldkit-mixins-ui`) binds a floating element to\n * another element's id through floating-ui, with portals and continuous\n * repositioning. It relocates nodes out from under the runtime (portal by\n * default) and burns under zero geometry; reach for it when the panel must\n * track a moving anchor, not for a popup placed once.\n * - `KeepInView` (`foldkit-primitives/dom`) scrolls newly marked content\n * into view. Same verb, opposite direction: that one moves the page to\n * the panel, this one moves the panel into the page.\n * - `Overlay.behaviors` owns dismissal, focus, scroll lock, and inertness,\n * but no positioning; spread this alongside it for the full overlay.\n */\nimport { Effect, Option, Schema, Stream } from 'effect'\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\n\nexport interface PanelRect {\n readonly top: number\n readonly right: number\n readonly bottom: number\n readonly height: number\n}\n\nexport interface Viewport {\n readonly width: number\n readonly height: number\n}\n\nexport interface Placed {\n /** Pixels to move left; `0` when the panel fits. */\n readonly dx: number\n /** Whether the panel stands above its trigger instead of below. */\n readonly flip: boolean\n}\n\n/** Where the panel goes so it fits: left by the overflow, above when the\n * bottom clears the window and the room overhead fits the panel. */\nexport const placeFor = (rect: PanelRect, viewport: Viewport, margin = 8): Placed => {\n const over = rect.right - viewport.width + margin\n return {\n dx: over > 0 ? -over : 0,\n flip: rect.bottom > viewport.height && rect.top - margin >= rect.height,\n }\n}\n\n/** Pixels to move a box up so its bottom sits `margin` inside the viewport.\n * `0` when it already fits, or when its top is already at the margin. */\nexport const shiftIntoViewport = (\n rect: { readonly top: number; readonly bottom: number },\n viewportHeight: number,\n margin = 8,\n): number => {\n const overflow = rect.bottom - (viewportHeight - margin)\n if (overflow <= 0) return 0\n const room = rect.top - margin\n if (room <= 0) return 0\n return Math.min(overflow, room)\n}\n\n/** Attribute `keepWithin` sets to `placedAbove` when the panel flips. */\nexport const placedSide = 'data-fk-placed'\n\n/** Value of `placedSide` while the panel stands above its anchor. */\nexport const placedAbove = 'above'\n\nexport interface AnchorRect {\n readonly left: number\n readonly top: number\n readonly bottom: number\n readonly width: number\n readonly height: number\n}\n\nexport interface OriginRect {\n readonly left: number\n readonly top: number\n}\n\nexport interface PlacedAt {\n readonly left: number\n readonly top: number\n}\n\n/** Custom property `PlaceAt` writes. A panel reads it as `top` so a viewport\n * flip, which sets the `top` property, still wins. */\nexport const placedTop = '--fk-placed-top'\n\n/** Where a popup sits under its trigger's left edge, in the offset parent's\n * coordinates. A zero-size trigger (an inert document) stays at the origin. */\nexport const placeAt = (trigger: AnchorRect, origin: OriginRect, gap = 4): PlacedAt => {\n if (trigger.width === 0 && trigger.height === 0) return { left: 0, top: 0 }\n return {\n left: trigger.left - origin.left,\n top: trigger.bottom - origin.top + gap,\n }\n}\n\nexport interface ViewportPoint {\n readonly x: number\n readonly y: number\n}\n\n/** Where a popup's top-left sits on a viewport point, in the offset parent's\n * coordinates. A context menu uses it: the right-click event carries the\n * point, and `OnContextMenu` does not. */\nexport const placeAtPoint = (point: ViewportPoint, origin: OriginRect): PlacedAt => ({\n left: point.x - origin.left,\n top: point.y - origin.top,\n})\n\nconst clearFit = (element: HTMLElement): void => {\n element.style.translate = ''\n element.style.top = ''\n element.style.bottom = ''\n element.removeAttribute(placedSide)\n}\n\nconst fitWithin = (element: HTMLElement): void => {\n // A previous fit may have flipped. Clear it before reading, or the next\n // decision would describe the flipped box.\n clearFit(element)\n const rect = element.getBoundingClientRect()\n const placed = placeFor(\n { top: rect.top, right: rect.right, bottom: rect.bottom, height: rect.height },\n { width: document.documentElement.clientWidth, height: window.innerHeight },\n )\n if (placed.dx !== 0) element.style.translate = `${placed.dx}px 0`\n if (placed.flip) {\n element.style.top = 'auto'\n element.style.bottom = 'calc(100% + 4px)'\n element.setAttribute(placedSide, placedAbove)\n }\n}\n\n// PlaceAt and KeepWithin start together (`Stream.mergeAll`), so the fit can\n// run before the placement write. The write calls whoever is waiting.\nconst refits = new WeakMap<HTMLElement, Set<() => void>>()\n\nconst onPlaced = (element: HTMLElement, refit: () => void): void => {\n const waiting = refits.get(element) ?? new Set()\n waiting.add(refit)\n refits.set(element, waiting)\n}\n\nconst offPlaced = (element: HTMLElement, refit: () => void): void => {\n const waiting = refits.get(element)\n if (waiting === undefined) return\n waiting.delete(refit)\n if (waiting.size === 0) refits.delete(element)\n}\n\nconst notifyPlaced = (element: HTMLElement): void => {\n const waiting = refits.get(element)\n if (waiting === undefined) return\n for (const refit of waiting) refit()\n}\n\nconst applyPlaced = (element: HTMLElement, placed: PlacedAt): void => {\n element.style.left = `${placed.left}px`\n element.style.setProperty(placedTop, `${placed.top}px`)\n}\n\nconst clearPlaced = (element: HTMLElement): void => {\n element.style.left = ''\n element.style.removeProperty(placedTop)\n}\n\nconst writePlaced = (element: HTMLElement, placed: PlacedAt, shift: boolean): void => {\n clearFit(element)\n applyPlaced(element, placed)\n if (shift) {\n const rect = element.getBoundingClientRect()\n const dy = shiftIntoViewport({ top: rect.top, bottom: rect.bottom }, window.innerHeight)\n if (dy !== 0) element.style.setProperty(placedTop, `${placed.top - dy}px`)\n }\n notifyPlaced(element)\n}\n\nexport const KeepWithin = Mount.defineStream('KeepWithin', {\n messages: [Schema.Never],\n execute: ({ element }) =>\n Stream.callback<never>(() => {\n if (!(element instanceof HTMLElement)) {\n return Effect.acquireRelease(Effect.void, () => Effect.void)\n }\n const node = element\n const refit = (): void => fitWithin(node)\n return Effect.acquireRelease(\n Effect.sync(() => {\n onPlaced(node, refit)\n refit()\n }),\n () =>\n Effect.sync(() => {\n offPlaced(node, refit)\n clearFit(node)\n }),\n )\n }),\n})\n\nconst paddingEdge = (node: HTMLElement): OriginRect => {\n const rect = node.getBoundingClientRect()\n // Absolute `left`/`top` start at the padding edge; the rect is the border box.\n return { left: rect.left + node.clientLeft, top: rect.top + node.clientTop }\n}\n\nconst originOf = (element: HTMLElement): OriginRect => {\n const originNode = element.offsetParent\n return originNode instanceof HTMLElement ? paddingEdge(originNode) : { left: 0, top: 0 }\n}\n\nexport const PlaceAt = Mount.defineStream('PlaceAt', {\n messages: [Schema.Never],\n args: {\n /** Element id of the trigger the popup opens under. */\n triggerId: Schema.String,\n /** Pixels between the trigger's bottom and the popup. */\n gap: Schema.Number,\n },\n execute: ({ element, triggerId, gap }) =>\n Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.sync(() => {\n if (!(element instanceof HTMLElement)) return\n const trigger = document.getElementById(triggerId)\n if (!(trigger instanceof HTMLElement)) return\n const rect = trigger.getBoundingClientRect()\n writePlaced(\n element,\n placeAt(\n {\n left: rect.left,\n top: rect.top,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n },\n originOf(element),\n gap,\n ),\n false,\n )\n }),\n () =>\n Effect.sync(() => {\n if (!(element instanceof HTMLElement)) return\n clearPlaced(element)\n }),\n ),\n ),\n})\n\nexport const PlaceAtPoint = Mount.defineStream('PlaceAtPoint', {\n messages: [Schema.Never],\n args: {\n /** Viewport x of the popup's top-left. */\n x: Schema.Number,\n /** Viewport y of the popup's top-left. */\n y: Schema.Number,\n },\n execute: ({ element, x, y }) =>\n Stream.callback<never>(() =>\n Effect.acquireRelease(\n Effect.sync(() => {\n if (!(element instanceof HTMLElement)) return\n // The offset parent is not the point. Shifting keeps the menu beside\n // it; flipping would send the menu above that parent.\n writePlaced(element, placeAtPoint({ x, y }, originOf(element)), true)\n }),\n () =>\n Effect.sync(() => {\n if (!(element instanceof HTMLElement)) return\n clearPlaced(element)\n }),\n ),\n ),\n})\n\nexport const placeAtTrigger =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(options: {\n readonly panel: keyof Slots & string\n /** The trigger this open belongs to. Read at insert, so key the panel by it. */\n readonly triggerId: (input: Input) => string\n readonly gap?: number\n /** A viewport point wins over the trigger. None places under `triggerId`. */\n readonly at?: (input: Input) => Option.Option<ViewportPoint>\n }): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.panel]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: input => {\n const at = options.at?.(input) ?? Option.none()\n return Option.isSome(at)\n ? PlaceAtPoint({ x: at.value.x, y: at.value.y })\n : PlaceAt({ triggerId: options.triggerId(input), gap: options.gap ?? 4 })\n },\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'PlaceAt' },\n )\n\nexport const keepWithin =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(options: {\n readonly panel: keyof Slots & string\n }): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.panel]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () => KeepWithin(),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'KeepWithin' },\n )\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DRAG_THRESHOLD, DragCancelled, DragDropped, DragFact, DragFact as DragFact$1, DragPlace, DragStarted, DragZone, DraggedOver, PointerDrag as mount, boxOf, zoneOf } from "../dom/pointer-drag.js";
|
|
2
|
+
import { Behavior } from "foldkit-mixins";
|
|
3
|
+
export interface BehaviorOptions<Slots, ParentMessage> {
|
|
4
|
+
/** The slot holding the marked descendants. */
|
|
5
|
+
readonly container: keyof Slots & string;
|
|
6
|
+
/** The attribute that marks a descendant, holding its id. */
|
|
7
|
+
readonly attribute: string;
|
|
8
|
+
/**
|
|
9
|
+
* Where a drag may land when not among the container's own: elements marked
|
|
10
|
+
* by `attribute` inside the one `within` selects, such as a page for a palette.
|
|
11
|
+
*/
|
|
12
|
+
readonly targets?: {
|
|
13
|
+
readonly attribute: string;
|
|
14
|
+
readonly within: string;
|
|
15
|
+
};
|
|
16
|
+
/** An attribute naming a part of what a drop lands on, which the place then carries. */
|
|
17
|
+
readonly part?: string;
|
|
18
|
+
/** Turns each fact into the view's Message. */
|
|
19
|
+
readonly toMessage: (fact: DragFact$1) => ParentMessage;
|
|
20
|
+
}
|
|
21
|
+
export declare const behavior: <Slots>(slots: Slots) => <Input, ParentMessage>(options: BehaviorOptions<Slots, ParentMessage>) => Behavior.NamedBehavior<Slots, Input, ParentMessage>;
|
|
22
|
+
export { DRAG_THRESHOLD, DragCancelled, DragDropped, type DragFact, DragPlace, DragStarted, DragZone, DraggedOver, boxOf, mount, zoneOf };
|
|
23
|
+
//# sourceMappingURL=pointer-drag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointer-drag.d.ts","names":["DragFact"],"sources":["../../src/interaction/pointer-drag.ts"],"mappings":";;iBAwBiB,gBAAgB,OAAO;;WAE7B,iBAAiB;;WAEjB;;;;;WAKA;aAAqB;aAA4B;;;WAEjD;;WAEA,YAAY,MAAMA,eAAa;;qBAG7B,WACV,OAAK,OAAS,WACd,OAAO,eAAa,SACV,gBAAgB,OAAO,mBAC/B,SAAS,cAAc,OAAO,OAAO"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as Mount from "foldkit/mount";
|
|
2
|
+
import { DRAG_THRESHOLD, DragCancelled, DragDropped, DragPlace, DragStarted, DragZone, DraggedOver, PointerDrag, PointerDrag as mount, boxOf, zoneOf } from "../dom/pointer-drag.js";
|
|
3
|
+
import { Behavior, Capability } from "foldkit-mixins";
|
|
4
|
+
// src/interaction/pointer-drag.ts
|
|
5
|
+
/**
|
|
6
|
+
* `PointerDrag` as a Behavior: attaches the `foldkit-primitives/dom` Mount to
|
|
7
|
+
* a container slot and maps what it reports into the view's Messages. No
|
|
8
|
+
* Bundle: what is dragged and where the pointer is are facts, and what a drop
|
|
9
|
+
* means, and whether it is allowed, is the parent's `update`.
|
|
10
|
+
*/
|
|
11
|
+
const behavior = (slots) => (options) => Behavior.forSlots(slots)({ [options.container]: Behavior.slot({
|
|
12
|
+
requires: { capability: Capability.Container },
|
|
13
|
+
mount: () => Mount.mapMessage(PointerDrag({
|
|
14
|
+
attribute: options.attribute,
|
|
15
|
+
...options.targets === void 0 ? {} : { targets: options.targets },
|
|
16
|
+
...options.part === void 0 ? {} : { part: options.part }
|
|
17
|
+
}), options.toMessage)
|
|
18
|
+
}) }, { name: "PointerDrag" });
|
|
19
|
+
export { DRAG_THRESHOLD, DragCancelled, DragDropped, DragPlace, DragStarted, DragZone, DraggedOver, behavior, boxOf, mount, zoneOf };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=pointer-drag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointer-drag.js","names":["PointerDragMount"],"sources":["../../src/interaction/pointer-drag.ts"],"sourcesContent":["/**\n * `PointerDrag` as a Behavior: attaches the `foldkit-primitives/dom` Mount to\n * a container slot and maps what it reports into the view's Messages. No\n * Bundle: what is dragged and where the pointer is are facts, and what a drop\n * means, and whether it is allowed, is the parent's `update`.\n */\nimport * as Mount from 'foldkit/mount'\nimport { Behavior, Capability } from 'foldkit-mixins'\nimport { PointerDrag as PointerDragMount, type DragFact } from '../dom/pointer-drag.js'\n\nexport {\n DRAG_THRESHOLD,\n DragCancelled,\n DragDropped,\n DragPlace,\n DragStarted,\n DragZone,\n DraggedOver,\n PointerDrag as mount,\n boxOf,\n zoneOf,\n type DragFact,\n} from '../dom/pointer-drag.js'\n\nexport interface BehaviorOptions<Slots, ParentMessage> {\n /** The slot holding the marked descendants. */\n readonly container: keyof Slots & string\n /** The attribute that marks a descendant, holding its id. */\n readonly attribute: string\n /**\n * Where a drag may land when not among the container's own: elements marked\n * by `attribute` inside the one `within` selects, such as a page for a palette.\n */\n readonly targets?: { readonly attribute: string; readonly within: string }\n /** An attribute naming a part of what a drop lands on, which the place then carries. */\n readonly part?: string\n /** Turns each fact into the view's Message. */\n readonly toMessage: (fact: DragFact) => ParentMessage\n}\n\nexport const behavior =\n <Slots>(slots: Slots) =>\n <Input, ParentMessage>(\n options: BehaviorOptions<Slots, ParentMessage>,\n ): Behavior.NamedBehavior<Slots, Input, ParentMessage> =>\n Behavior.forSlots(slots)<Input, ParentMessage>(\n {\n [options.container]: Behavior.slot({\n requires: { capability: Capability.Container },\n mount: () =>\n Mount.mapMessage(\n PointerDragMount({\n attribute: options.attribute,\n ...(options.targets === undefined ? {} : { targets: options.targets }),\n ...(options.part === undefined ? {} : { part: options.part }),\n }),\n options.toMessage,\n ),\n }),\n // Keyed by a value the caller chose; `forSlots` checks the key exists.\n } as unknown as Behavior.BehaviorSpec<Slots, Input, ParentMessage>,\n { name: 'PointerDrag' },\n )\n"],"mappings":";;;;;;;;;;AAwCA,MAAa,YACH,WAEN,YAEA,SAAS,SAAS,KAAK,CAAC,CACtB,GACG,QAAQ,YAAY,SAAS,KAAK;CACjC,UAAU,EAAE,YAAY,WAAW,UAAU;CAC7C,aACE,MAAM,WACJA,YAAiB;EACf,WAAW,QAAQ;EACnB,GAAI,QAAQ,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;EACpE,GAAI,QAAQ,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,QAAQ,KAAK;CAC7D,CAAC,GACD,QAAQ,SACV;AACJ,CAAC,EAEH,GACA,EAAE,MAAM,cAAc,CACxB"}
|