@mantine/hooks 9.4.3-alpha.0 → 9.5.1-alpha.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/cjs/use-collapse/use-collapse.cjs +1 -0
- package/cjs/use-collapse/use-horizontal-collapse.cjs +1 -0
- package/cjs/use-drag/use-drag.cjs +10 -5
- package/cjs/use-drag/use-drag.cjs.map +1 -1
- package/cjs/use-favicon/use-favicon.cjs +2 -1
- package/cjs/use-favicon/use-favicon.cjs.map +1 -1
- package/cjs/use-floating-window/use-floating-window.cjs +9 -12
- package/cjs/use-floating-window/use-floating-window.cjs.map +1 -1
- package/cjs/use-headroom/use-headroom.cjs +2 -0
- package/cjs/use-hotkeys/parse-hotkey.cjs +1 -0
- package/cjs/use-hotkeys/use-hotkeys.cjs +1 -0
- package/cjs/use-input-state/use-input-state.cjs +1 -0
- package/cjs/use-mask/use-mask.cjs +4 -2
- package/cjs/use-mask/use-mask.cjs.map +1 -1
- package/cjs/use-mouse/use-mouse.cjs +4 -2
- package/cjs/use-mouse/use-mouse.cjs.map +1 -1
- package/cjs/use-pagination/use-pagination.cjs +9 -5
- package/cjs/use-pagination/use-pagination.cjs.map +1 -1
- package/cjs/use-set/use-set.cjs +1 -0
- package/esm/use-collapse/use-collapse.mjs +1 -1
- package/esm/use-collapse/use-horizontal-collapse.mjs +1 -1
- package/esm/use-drag/use-drag.mjs +10 -5
- package/esm/use-drag/use-drag.mjs.map +1 -1
- package/esm/use-favicon/use-favicon.mjs +2 -1
- package/esm/use-favicon/use-favicon.mjs.map +1 -1
- package/esm/use-floating-window/use-floating-window.mjs +9 -12
- package/esm/use-floating-window/use-floating-window.mjs.map +1 -1
- package/esm/use-headroom/use-headroom.mjs +1 -1
- package/esm/use-hotkeys/parse-hotkey.mjs +1 -1
- package/esm/use-hotkeys/use-hotkeys.mjs +2 -2
- package/esm/use-input-state/use-input-state.mjs +1 -1
- package/esm/use-mask/use-mask.mjs +4 -2
- package/esm/use-mask/use-mask.mjs.map +1 -1
- package/esm/use-mouse/use-mouse.mjs +4 -2
- package/esm/use-mouse/use-mouse.mjs.map +1 -1
- package/esm/use-pagination/use-pagination.mjs +9 -6
- package/esm/use-pagination/use-pagination.mjs.map +1 -1
- package/esm/use-set/use-set.mjs +1 -1
- package/package.json +1 -1
|
@@ -96,6 +96,7 @@ function useHorizontalCollapse({ transitionDuration, transitionTimingFunction =
|
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
//#endregion
|
|
99
|
+
exports.getElementWidth = getElementWidth;
|
|
99
100
|
exports.useHorizontalCollapse = useHorizontalCollapse;
|
|
100
101
|
|
|
101
102
|
//# sourceMappingURL=use-horizontal-collapse.cjs.map
|
|
@@ -140,7 +140,8 @@ function useDrag(handler, options = {}) {
|
|
|
140
140
|
activateDrag();
|
|
141
141
|
}
|
|
142
142
|
const movement = applyAxisConstraint(rawMovement);
|
|
143
|
-
const
|
|
143
|
+
const rawDelta = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];
|
|
144
|
+
const delta = applyAxisConstraint(rawDelta);
|
|
144
145
|
const timeDelta = event.timeStamp - s.prevTimestamp;
|
|
145
146
|
const velocity = timeDelta > 0 ? [Math.abs(delta[0]) / timeDelta, Math.abs(delta[1]) / timeDelta] : s.lastVelocity;
|
|
146
147
|
s.lastVelocity = velocity;
|
|
@@ -172,7 +173,8 @@ function useDrag(handler, options = {}) {
|
|
|
172
173
|
const opts = optionsRef.current;
|
|
173
174
|
if (!s.thresholdMet) {
|
|
174
175
|
if (opts.filterTaps) {
|
|
175
|
-
const
|
|
176
|
+
const rawMov = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];
|
|
177
|
+
const mov = applyAxisConstraint(rawMov);
|
|
176
178
|
const dist = [Math.abs(mov[0]), Math.abs(mov[1])];
|
|
177
179
|
const isTap = Math.max(dist[0], dist[1]) < (opts.tapThreshold ?? 3);
|
|
178
180
|
handlerRef.current({
|
|
@@ -196,9 +198,11 @@ function useDrag(handler, options = {}) {
|
|
|
196
198
|
resetDrag();
|
|
197
199
|
return;
|
|
198
200
|
}
|
|
199
|
-
const
|
|
201
|
+
const rawMovement = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];
|
|
202
|
+
const movement = applyAxisConstraint(rawMovement);
|
|
200
203
|
const distance = [Math.abs(movement[0]), Math.abs(movement[1])];
|
|
201
|
-
const
|
|
204
|
+
const rawDelta = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];
|
|
205
|
+
const delta = applyAxisConstraint(rawDelta);
|
|
202
206
|
const velocity = event.timeStamp - s.prevTimestamp > VELOCITY_DECAY_MS ? [0, 0] : s.lastVelocity;
|
|
203
207
|
const maxDistance = Math.max(distance[0], distance[1]);
|
|
204
208
|
const tap = opts.filterTaps === true && maxDistance < (opts.tapThreshold ?? 3);
|
|
@@ -224,7 +228,8 @@ function useDrag(handler, options = {}) {
|
|
|
224
228
|
const onPointerCancel = (event) => {
|
|
225
229
|
const s = stateRef.current;
|
|
226
230
|
if (!s.isActive || event.pointerId !== s.pointerId) return;
|
|
227
|
-
const
|
|
231
|
+
const rawMovement = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];
|
|
232
|
+
const movement = applyAxisConstraint(rawMovement);
|
|
228
233
|
handlerRef.current({
|
|
229
234
|
xy: [event.clientX, event.clientY],
|
|
230
235
|
initial: [...s.startXY],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-drag.cjs","names":[],"sources":["../../src/use-drag/use-drag.ts"],"sourcesContent":["// Required to disable for webkit-user-select, although deprecated, it is still required for Safari support\n/* eslint-disable @typescript-eslint/no-deprecated */\nimport { useCallback, useRef, useState } from 'react';\n\ntype Vector2 = [number, number];\n\nexport interface UseDragState {\n /** Current pointer position [x, y] */\n xy: Vector2;\n\n /** Position where the gesture started [x, y] */\n initial: Vector2;\n\n /** Displacement from start [x, y], respects axis constraint */\n movement: Vector2;\n\n /** Change since previous event [x, y] */\n delta: Vector2;\n\n /** Absolute distance per axis [x, y] */\n distance: Vector2;\n\n /** Movement direction per axis: -1, 0, or 1 */\n direction: Vector2;\n\n /** Speed per axis in px/ms */\n velocity: Vector2;\n\n /** Time since drag started in ms */\n elapsedTime: number;\n\n /** `true` on the first handler call after the threshold is met */\n first: boolean;\n\n /** `true` on the last handler call (pointer released or canceled) */\n last: boolean;\n\n /** `true` while the gesture is ongoing */\n active: boolean;\n\n /** `true` when the gesture qualifies as a tap (requires `filterTaps: true`) */\n tap: boolean;\n\n /** `true` when the gesture was interrupted by a `pointercancel` event */\n canceled: boolean;\n\n /** Function to programmatically cancel the current gesture */\n cancel: () => void;\n\n /** The source `PointerEvent` */\n event: PointerEvent;\n}\n\nexport interface UseDragOptions {\n /** Constrain movement to a specific axis. `'lock'` locks to whichever axis has more movement after `axisThreshold` is exceeded. */\n axis?: 'x' | 'y' | 'lock';\n\n /** Movement in px required to determine axis when `axis` is `'lock'`, `1` by default */\n axisThreshold?: number;\n\n /** When `true`, the last state includes `tap: true` when total distance is below `tapThreshold`, `false` by default */\n filterTaps?: boolean;\n\n /** Max displacement in px to still be considered a tap, `3` by default */\n tapThreshold?: number;\n\n /** Minimum displacement in px before the drag activates. Can be a number (both axes) or `[x, y]`. `0` by default */\n threshold?: number | Vector2;\n\n /** Enable or disable the hook, `true` by default */\n enabled?: boolean;\n}\n\nexport interface UseDragReturnValue<T extends HTMLElement = any> {\n /** Ref callback to attach to the draggable element */\n ref: React.RefCallback<T | null>;\n\n /** `true` while the element is being dragged */\n active: boolean;\n}\n\nconst VELOCITY_DECAY_MS = 100;\n\nfunction sign(n: number): -1 | 0 | 1 {\n if (n > 0) {\n return 1;\n }\n if (n < 0) {\n return -1;\n }\n return 0;\n}\n\nfunction getThresholdVector(threshold: number | Vector2 | undefined): Vector2 {\n const t = threshold ?? 0;\n if (typeof t === 'number') {\n return [t, t];\n }\n return t;\n}\n\ninterface DragInternalState {\n isActive: boolean;\n pointerId: number;\n startXY: Vector2;\n prevXY: Vector2;\n startTimestamp: number;\n prevTimestamp: number;\n thresholdMet: boolean;\n firstFired: boolean;\n lockedAxis: 'x' | 'y' | null;\n canceled: boolean;\n lastVelocity: Vector2;\n}\n\nfunction createInitialState(): DragInternalState {\n return {\n isActive: false,\n pointerId: -1,\n startXY: [0, 0],\n prevXY: [0, 0],\n startTimestamp: 0,\n prevTimestamp: 0,\n thresholdMet: false,\n firstFired: false,\n lockedAxis: null,\n canceled: false,\n lastVelocity: [0, 0],\n };\n}\n\nexport function useDrag<T extends HTMLElement = any>(\n handler: (state: UseDragState) => void,\n options: UseDragOptions = {}\n): UseDragReturnValue<T> {\n const [active, setActive] = useState(false);\n\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const stateRef = useRef<DragInternalState>(createInitialState());\n const documentControllerRef = useRef<AbortController | null>(null);\n\n const refCallback: React.RefCallback<T | null> = useCallback((node) => {\n if (!node) {\n return undefined;\n }\n\n const elementController = new AbortController();\n\n const applyAxisConstraint = (v: Vector2): Vector2 => {\n const opts = optionsRef.current;\n const s = stateRef.current;\n\n if (opts.axis === 'x') {\n return [v[0], 0];\n }\n if (opts.axis === 'y') {\n return [0, v[1]];\n }\n if (opts.axis === 'lock') {\n if (s.lockedAxis === null) {\n const t = opts.axisThreshold ?? 1;\n if (Math.abs(v[0]) > t || Math.abs(v[1]) > t) {\n s.lockedAxis = Math.abs(v[0]) >= Math.abs(v[1]) ? 'x' : 'y';\n }\n }\n if (s.lockedAxis === 'x') {\n return [v[0], 0];\n }\n if (s.lockedAxis === 'y') {\n return [0, v[1]];\n }\n }\n return v;\n };\n\n const resetDrag = () => {\n const s = stateRef.current;\n s.isActive = false;\n s.pointerId = -1;\n s.thresholdMet = false;\n s.firstFired = false;\n s.lockedAxis = null;\n s.canceled = false;\n setActive(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n documentControllerRef.current?.abort();\n documentControllerRef.current = null;\n };\n\n const cancel = () => {\n if (stateRef.current.isActive) {\n stateRef.current.canceled = true;\n resetDrag();\n }\n };\n\n const activateDrag = () => {\n setActive(true);\n document.body.style.userSelect = 'none';\n document.body.style.webkitUserSelect = 'none';\n };\n\n const onPointerDown = (event: PointerEvent) => {\n if (optionsRef.current.enabled === false) {\n return;\n }\n if (event.button !== 0) {\n return;\n }\n if (stateRef.current.isActive) {\n return;\n }\n\n const s = stateRef.current;\n s.isActive = true;\n s.pointerId = event.pointerId;\n s.startXY = [event.clientX, event.clientY];\n s.prevXY = [event.clientX, event.clientY];\n s.startTimestamp = event.timeStamp;\n s.prevTimestamp = event.timeStamp;\n s.thresholdMet = false;\n s.firstFired = false;\n s.lockedAxis = null;\n s.canceled = false;\n s.lastVelocity = [0, 0];\n\n const [tx, ty] = getThresholdVector(optionsRef.current.threshold);\n if (tx === 0 && ty === 0) {\n s.thresholdMet = true;\n s.firstFired = true;\n activateDrag();\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [event.clientX, event.clientY],\n movement: [0, 0],\n delta: [0, 0],\n distance: [0, 0],\n direction: [0, 0],\n velocity: [0, 0],\n elapsedTime: 0,\n first: true,\n last: false,\n active: true,\n tap: false,\n canceled: false,\n cancel,\n event,\n });\n }\n\n documentControllerRef.current?.abort();\n documentControllerRef.current = new AbortController();\n const sig = documentControllerRef.current.signal;\n\n document.addEventListener('pointermove', onPointerMove, { signal: sig });\n document.addEventListener('pointerup', onPointerUp, { signal: sig });\n document.addEventListener('pointercancel', onPointerCancel, { signal: sig });\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n\n if (!s.thresholdMet) {\n const [tx, ty] = getThresholdVector(optionsRef.current.threshold);\n if (Math.abs(rawMovement[0]) < tx && Math.abs(rawMovement[1]) < ty) {\n s.prevXY = [event.clientX, event.clientY];\n s.prevTimestamp = event.timeStamp;\n return;\n }\n s.thresholdMet = true;\n activateDrag();\n }\n\n const movement = applyAxisConstraint(rawMovement);\n const rawDelta: Vector2 = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];\n const delta = applyAxisConstraint(rawDelta);\n const timeDelta = event.timeStamp - s.prevTimestamp;\n const velocity: Vector2 =\n timeDelta > 0\n ? [Math.abs(delta[0]) / timeDelta, Math.abs(delta[1]) / timeDelta]\n : s.lastVelocity;\n\n s.lastVelocity = velocity;\n const isFirst = !s.firstFired;\n s.firstFired = true;\n s.prevXY = [event.clientX, event.clientY];\n s.prevTimestamp = event.timeStamp;\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta,\n distance: [Math.abs(movement[0]), Math.abs(movement[1])],\n direction: [sign(delta[0]), sign(delta[1])],\n velocity,\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: isFirst,\n last: false,\n active: true,\n tap: false,\n canceled: false,\n cancel,\n event,\n });\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const opts = optionsRef.current;\n\n if (!s.thresholdMet) {\n if (opts.filterTaps) {\n const rawMov: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const mov = applyAxisConstraint(rawMov);\n const dist: Vector2 = [Math.abs(mov[0]), Math.abs(mov[1])];\n const maxDist = Math.max(dist[0], dist[1]);\n const isTap = maxDist < (opts.tapThreshold ?? 3);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement: mov,\n delta: mov,\n distance: dist,\n direction: [sign(mov[0]), sign(mov[1])],\n velocity: [0, 0],\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: true,\n last: true,\n active: false,\n tap: isTap,\n canceled: false,\n cancel,\n event,\n });\n }\n resetDrag();\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const movement = applyAxisConstraint(rawMovement);\n const distance: Vector2 = [Math.abs(movement[0]), Math.abs(movement[1])];\n const rawDelta: Vector2 = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];\n const delta = applyAxisConstraint(rawDelta);\n\n const timeSinceLastMove = event.timeStamp - s.prevTimestamp;\n const velocity: Vector2 = timeSinceLastMove > VELOCITY_DECAY_MS ? [0, 0] : s.lastVelocity;\n\n const maxDistance = Math.max(distance[0], distance[1]);\n const tap = opts.filterTaps === true && maxDistance < (opts.tapThreshold ?? 3);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta,\n distance,\n direction: [sign(delta[0]), sign(delta[1])],\n velocity,\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: !s.firstFired,\n last: true,\n active: false,\n tap,\n canceled: false,\n cancel,\n event,\n });\n\n resetDrag();\n };\n\n const onPointerCancel = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const movement = applyAxisConstraint(rawMovement);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta: [0, 0],\n distance: [Math.abs(movement[0]), Math.abs(movement[1])],\n direction: [0, 0],\n velocity: [0, 0],\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: !s.firstFired,\n last: true,\n active: false,\n tap: false,\n canceled: true,\n cancel,\n event,\n });\n\n resetDrag();\n };\n\n node.addEventListener('pointerdown', onPointerDown, {\n signal: elementController.signal,\n });\n\n return () => {\n elementController.abort();\n documentControllerRef.current?.abort();\n documentControllerRef.current = null;\n if (stateRef.current.isActive) {\n stateRef.current.isActive = false;\n setActive(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n }\n };\n }, []);\n\n return { ref: refCallback, active };\n}\n\nexport namespace useDrag {\n export type State = UseDragState;\n export type Options = UseDragOptions;\n export type ReturnValue<T extends HTMLElement = any> = UseDragReturnValue<T>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-drag.cjs","names":[],"sources":["../../src/use-drag/use-drag.ts"],"sourcesContent":["// Required to disable for webkit-user-select, although deprecated, it is still required for Safari support\n/* eslint-disable @typescript-eslint/no-deprecated */\nimport { useCallback, useRef, useState } from 'react';\n\ntype Vector2 = [number, number];\n\nexport interface UseDragState {\n /** Current pointer position [x, y] */\n xy: Vector2;\n\n /** Position where the gesture started [x, y] */\n initial: Vector2;\n\n /** Displacement from start [x, y], respects axis constraint */\n movement: Vector2;\n\n /** Change since previous event [x, y] */\n delta: Vector2;\n\n /** Absolute distance per axis [x, y] */\n distance: Vector2;\n\n /** Movement direction per axis: -1, 0, or 1 */\n direction: Vector2;\n\n /** Speed per axis in px/ms */\n velocity: Vector2;\n\n /** Time since drag started in ms */\n elapsedTime: number;\n\n /** `true` on the first handler call after the threshold is met */\n first: boolean;\n\n /** `true` on the last handler call (pointer released or canceled) */\n last: boolean;\n\n /** `true` while the gesture is ongoing */\n active: boolean;\n\n /** `true` when the gesture qualifies as a tap (requires `filterTaps: true`) */\n tap: boolean;\n\n /** `true` when the gesture was interrupted by a `pointercancel` event */\n canceled: boolean;\n\n /** Function to programmatically cancel the current gesture */\n cancel: () => void;\n\n /** The source `PointerEvent` */\n event: PointerEvent;\n}\n\nexport interface UseDragOptions {\n /** Constrain movement to a specific axis. `'lock'` locks to whichever axis has more movement after `axisThreshold` is exceeded. */\n axis?: 'x' | 'y' | 'lock';\n\n /** Movement in px required to determine axis when `axis` is `'lock'`, `1` by default */\n axisThreshold?: number;\n\n /** When `true`, the last state includes `tap: true` when total distance is below `tapThreshold`, `false` by default */\n filterTaps?: boolean;\n\n /** Max displacement in px to still be considered a tap, `3` by default */\n tapThreshold?: number;\n\n /** Minimum displacement in px before the drag activates. Can be a number (both axes) or `[x, y]`. `0` by default */\n threshold?: number | Vector2;\n\n /** Enable or disable the hook, `true` by default */\n enabled?: boolean;\n}\n\nexport interface UseDragReturnValue<T extends HTMLElement = any> {\n /** Ref callback to attach to the draggable element */\n ref: React.RefCallback<T | null>;\n\n /** `true` while the element is being dragged */\n active: boolean;\n}\n\nconst VELOCITY_DECAY_MS = 100;\n\nfunction sign(n: number): -1 | 0 | 1 {\n if (n > 0) {\n return 1;\n }\n if (n < 0) {\n return -1;\n }\n return 0;\n}\n\nfunction getThresholdVector(threshold: number | Vector2 | undefined): Vector2 {\n const t = threshold ?? 0;\n if (typeof t === 'number') {\n return [t, t];\n }\n return t;\n}\n\ninterface DragInternalState {\n isActive: boolean;\n pointerId: number;\n startXY: Vector2;\n prevXY: Vector2;\n startTimestamp: number;\n prevTimestamp: number;\n thresholdMet: boolean;\n firstFired: boolean;\n lockedAxis: 'x' | 'y' | null;\n canceled: boolean;\n lastVelocity: Vector2;\n}\n\nfunction createInitialState(): DragInternalState {\n return {\n isActive: false,\n pointerId: -1,\n startXY: [0, 0],\n prevXY: [0, 0],\n startTimestamp: 0,\n prevTimestamp: 0,\n thresholdMet: false,\n firstFired: false,\n lockedAxis: null,\n canceled: false,\n lastVelocity: [0, 0],\n };\n}\n\nexport function useDrag<T extends HTMLElement = any>(\n handler: (state: UseDragState) => void,\n options: UseDragOptions = {}\n): UseDragReturnValue<T> {\n const [active, setActive] = useState(false);\n\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const stateRef = useRef<DragInternalState>(createInitialState());\n const documentControllerRef = useRef<AbortController | null>(null);\n\n const refCallback: React.RefCallback<T | null> = useCallback((node) => {\n if (!node) {\n return undefined;\n }\n\n const elementController = new AbortController();\n\n const applyAxisConstraint = (v: Vector2): Vector2 => {\n const opts = optionsRef.current;\n const s = stateRef.current;\n\n if (opts.axis === 'x') {\n return [v[0], 0];\n }\n if (opts.axis === 'y') {\n return [0, v[1]];\n }\n if (opts.axis === 'lock') {\n if (s.lockedAxis === null) {\n const t = opts.axisThreshold ?? 1;\n if (Math.abs(v[0]) > t || Math.abs(v[1]) > t) {\n s.lockedAxis = Math.abs(v[0]) >= Math.abs(v[1]) ? 'x' : 'y';\n }\n }\n if (s.lockedAxis === 'x') {\n return [v[0], 0];\n }\n if (s.lockedAxis === 'y') {\n return [0, v[1]];\n }\n }\n return v;\n };\n\n const resetDrag = () => {\n const s = stateRef.current;\n s.isActive = false;\n s.pointerId = -1;\n s.thresholdMet = false;\n s.firstFired = false;\n s.lockedAxis = null;\n s.canceled = false;\n setActive(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n documentControllerRef.current?.abort();\n documentControllerRef.current = null;\n };\n\n const cancel = () => {\n if (stateRef.current.isActive) {\n stateRef.current.canceled = true;\n resetDrag();\n }\n };\n\n const activateDrag = () => {\n setActive(true);\n document.body.style.userSelect = 'none';\n document.body.style.webkitUserSelect = 'none';\n };\n\n const onPointerDown = (event: PointerEvent) => {\n if (optionsRef.current.enabled === false) {\n return;\n }\n if (event.button !== 0) {\n return;\n }\n if (stateRef.current.isActive) {\n return;\n }\n\n const s = stateRef.current;\n s.isActive = true;\n s.pointerId = event.pointerId;\n s.startXY = [event.clientX, event.clientY];\n s.prevXY = [event.clientX, event.clientY];\n s.startTimestamp = event.timeStamp;\n s.prevTimestamp = event.timeStamp;\n s.thresholdMet = false;\n s.firstFired = false;\n s.lockedAxis = null;\n s.canceled = false;\n s.lastVelocity = [0, 0];\n\n const [tx, ty] = getThresholdVector(optionsRef.current.threshold);\n if (tx === 0 && ty === 0) {\n s.thresholdMet = true;\n s.firstFired = true;\n activateDrag();\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [event.clientX, event.clientY],\n movement: [0, 0],\n delta: [0, 0],\n distance: [0, 0],\n direction: [0, 0],\n velocity: [0, 0],\n elapsedTime: 0,\n first: true,\n last: false,\n active: true,\n tap: false,\n canceled: false,\n cancel,\n event,\n });\n }\n\n documentControllerRef.current?.abort();\n documentControllerRef.current = new AbortController();\n const sig = documentControllerRef.current.signal;\n\n document.addEventListener('pointermove', onPointerMove, { signal: sig });\n document.addEventListener('pointerup', onPointerUp, { signal: sig });\n document.addEventListener('pointercancel', onPointerCancel, { signal: sig });\n };\n\n const onPointerMove = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n\n if (!s.thresholdMet) {\n const [tx, ty] = getThresholdVector(optionsRef.current.threshold);\n if (Math.abs(rawMovement[0]) < tx && Math.abs(rawMovement[1]) < ty) {\n s.prevXY = [event.clientX, event.clientY];\n s.prevTimestamp = event.timeStamp;\n return;\n }\n s.thresholdMet = true;\n activateDrag();\n }\n\n const movement = applyAxisConstraint(rawMovement);\n const rawDelta: Vector2 = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];\n const delta = applyAxisConstraint(rawDelta);\n const timeDelta = event.timeStamp - s.prevTimestamp;\n const velocity: Vector2 =\n timeDelta > 0\n ? [Math.abs(delta[0]) / timeDelta, Math.abs(delta[1]) / timeDelta]\n : s.lastVelocity;\n\n s.lastVelocity = velocity;\n const isFirst = !s.firstFired;\n s.firstFired = true;\n s.prevXY = [event.clientX, event.clientY];\n s.prevTimestamp = event.timeStamp;\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta,\n distance: [Math.abs(movement[0]), Math.abs(movement[1])],\n direction: [sign(delta[0]), sign(delta[1])],\n velocity,\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: isFirst,\n last: false,\n active: true,\n tap: false,\n canceled: false,\n cancel,\n event,\n });\n };\n\n const onPointerUp = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const opts = optionsRef.current;\n\n if (!s.thresholdMet) {\n if (opts.filterTaps) {\n const rawMov: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const mov = applyAxisConstraint(rawMov);\n const dist: Vector2 = [Math.abs(mov[0]), Math.abs(mov[1])];\n const maxDist = Math.max(dist[0], dist[1]);\n const isTap = maxDist < (opts.tapThreshold ?? 3);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement: mov,\n delta: mov,\n distance: dist,\n direction: [sign(mov[0]), sign(mov[1])],\n velocity: [0, 0],\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: true,\n last: true,\n active: false,\n tap: isTap,\n canceled: false,\n cancel,\n event,\n });\n }\n resetDrag();\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const movement = applyAxisConstraint(rawMovement);\n const distance: Vector2 = [Math.abs(movement[0]), Math.abs(movement[1])];\n const rawDelta: Vector2 = [event.clientX - s.prevXY[0], event.clientY - s.prevXY[1]];\n const delta = applyAxisConstraint(rawDelta);\n\n const timeSinceLastMove = event.timeStamp - s.prevTimestamp;\n const velocity: Vector2 = timeSinceLastMove > VELOCITY_DECAY_MS ? [0, 0] : s.lastVelocity;\n\n const maxDistance = Math.max(distance[0], distance[1]);\n const tap = opts.filterTaps === true && maxDistance < (opts.tapThreshold ?? 3);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta,\n distance,\n direction: [sign(delta[0]), sign(delta[1])],\n velocity,\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: !s.firstFired,\n last: true,\n active: false,\n tap,\n canceled: false,\n cancel,\n event,\n });\n\n resetDrag();\n };\n\n const onPointerCancel = (event: PointerEvent) => {\n const s = stateRef.current;\n if (!s.isActive || event.pointerId !== s.pointerId) {\n return;\n }\n\n const rawMovement: Vector2 = [event.clientX - s.startXY[0], event.clientY - s.startXY[1]];\n const movement = applyAxisConstraint(rawMovement);\n\n handlerRef.current({\n xy: [event.clientX, event.clientY],\n initial: [...s.startXY],\n movement,\n delta: [0, 0],\n distance: [Math.abs(movement[0]), Math.abs(movement[1])],\n direction: [0, 0],\n velocity: [0, 0],\n elapsedTime: event.timeStamp - s.startTimestamp,\n first: !s.firstFired,\n last: true,\n active: false,\n tap: false,\n canceled: true,\n cancel,\n event,\n });\n\n resetDrag();\n };\n\n node.addEventListener('pointerdown', onPointerDown, {\n signal: elementController.signal,\n });\n\n return () => {\n elementController.abort();\n documentControllerRef.current?.abort();\n documentControllerRef.current = null;\n if (stateRef.current.isActive) {\n stateRef.current.isActive = false;\n setActive(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n }\n };\n }, []);\n\n return { ref: refCallback, active };\n}\n\nexport namespace useDrag {\n export type State = UseDragState;\n export type Options = UseDragOptions;\n export type ReturnValue<T extends HTMLElement = any> = UseDragReturnValue<T>;\n}\n"],"mappings":"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"}
|
|
@@ -20,7 +20,8 @@ function useFavicon(url) {
|
|
|
20
20
|
document.querySelector("head").appendChild(element);
|
|
21
21
|
}
|
|
22
22
|
const splittedUrl = url.split(".");
|
|
23
|
-
const
|
|
23
|
+
const extension = splittedUrl[splittedUrl.length - 1].toLowerCase();
|
|
24
|
+
const mimeType = MIME_TYPES[extension];
|
|
24
25
|
if (mimeType) link.current.setAttribute("type", mimeType);
|
|
25
26
|
else link.current.removeAttribute("type");
|
|
26
27
|
link.current.setAttribute("href", url);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-favicon.cjs","names":[],"sources":["../../src/use-favicon/use-favicon.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\n\nconst MIME_TYPES: Record<string, string> = {\n ico: 'image/x-icon',\n png: 'image/png',\n svg: 'image/svg+xml',\n gif: 'image/gif',\n};\n\nexport function useFavicon(url: string) {\n const link = useRef<HTMLLinkElement>(null);\n\n useIsomorphicEffect(() => {\n if (!url) {\n return;\n }\n\n if (!link.current) {\n const existingElements = document.querySelectorAll<HTMLLinkElement>('link[rel*=\"icon\"]');\n existingElements.forEach((element) => document.head.removeChild(element));\n\n const element = document.createElement('link');\n element.rel = 'shortcut icon';\n link.current = element;\n document.querySelector('head')!.appendChild(element);\n }\n\n const splittedUrl = url.split('.');\n const extension = splittedUrl[splittedUrl.length - 1].toLowerCase();\n const mimeType = MIME_TYPES[extension];\n\n if (mimeType) {\n link.current.setAttribute('type', mimeType);\n } else {\n link.current.removeAttribute('type');\n }\n\n link.current.setAttribute('href', url);\n }, [url]);\n}\n"],"mappings":";;;;AAGA,MAAM,aAAqC;CACzC,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;AAEA,SAAgB,WAAW,KAAa;CACtC,MAAM,QAAA,GAAA,MAAA,OAAA,CAA+B,IAAI;CAEzC,8BAAA,0BAA0B;EACxB,IAAI,CAAC,KACH;EAGF,IAAI,CAAC,KAAK,SAAS;GAEjB,SADkC,iBAAkC,qBACrD,CAAC,CAAC,SAAS,YAAY,SAAS,KAAK,YAAY,OAAO,CAAC;GAExE,MAAM,UAAU,SAAS,cAAc,MAAM;GAC7C,QAAQ,MAAM;GACd,KAAK,UAAU;GACf,SAAS,cAAc,MAAM,CAAC,CAAE,YAAY,OAAO;EACrD;EAEA,MAAM,cAAc,IAAI,MAAM,GAAG;
|
|
1
|
+
{"version":3,"file":"use-favicon.cjs","names":[],"sources":["../../src/use-favicon/use-favicon.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\n\nconst MIME_TYPES: Record<string, string> = {\n ico: 'image/x-icon',\n png: 'image/png',\n svg: 'image/svg+xml',\n gif: 'image/gif',\n};\n\nexport function useFavicon(url: string) {\n const link = useRef<HTMLLinkElement>(null);\n\n useIsomorphicEffect(() => {\n if (!url) {\n return;\n }\n\n if (!link.current) {\n const existingElements = document.querySelectorAll<HTMLLinkElement>('link[rel*=\"icon\"]');\n existingElements.forEach((element) => document.head.removeChild(element));\n\n const element = document.createElement('link');\n element.rel = 'shortcut icon';\n link.current = element;\n document.querySelector('head')!.appendChild(element);\n }\n\n const splittedUrl = url.split('.');\n const extension = splittedUrl[splittedUrl.length - 1].toLowerCase();\n const mimeType = MIME_TYPES[extension];\n\n if (mimeType) {\n link.current.setAttribute('type', mimeType);\n } else {\n link.current.removeAttribute('type');\n }\n\n link.current.setAttribute('href', url);\n }, [url]);\n}\n"],"mappings":";;;;AAGA,MAAM,aAAqC;CACzC,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;AAEA,SAAgB,WAAW,KAAa;CACtC,MAAM,QAAA,GAAA,MAAA,OAAA,CAA+B,IAAI;CAEzC,8BAAA,0BAA0B;EACxB,IAAI,CAAC,KACH;EAGF,IAAI,CAAC,KAAK,SAAS;GAEjB,SADkC,iBAAkC,qBACrD,CAAC,CAAC,SAAS,YAAY,SAAS,KAAK,YAAY,OAAO,CAAC;GAExE,MAAM,UAAU,SAAS,cAAc,MAAM;GAC7C,QAAQ,MAAM;GACd,KAAK,UAAU;GACf,SAAS,cAAc,MAAM,CAAC,CAAE,YAAY,OAAO;EACrD;EAEA,MAAM,cAAc,IAAI,MAAM,GAAG;EACjC,MAAM,YAAY,YAAY,YAAY,SAAS,EAAE,CAAC,YAAY;EAClE,MAAM,WAAW,WAAW;EAE5B,IAAI,UACF,KAAK,QAAQ,aAAa,QAAQ,QAAQ;OAE1C,KAAK,QAAQ,gBAAgB,MAAM;EAGrC,KAAK,QAAQ,aAAa,QAAQ,GAAG;CACvC,GAAG,CAAC,GAAG,CAAC;AACV"}
|
|
@@ -21,6 +21,9 @@ function useFloatingWindow(options = {}) {
|
|
|
21
21
|
const isDraggingRef = (0, react.useRef)(false);
|
|
22
22
|
const initialized = (0, react.useRef)(false);
|
|
23
23
|
const enabledRef = useRefValue(options.enabled);
|
|
24
|
+
const onPositionChangeRef = useRefValue(options.onPositionChange);
|
|
25
|
+
const onDragStartRef = useRefValue(options.onDragStart);
|
|
26
|
+
const onDragEndRef = useRefValue(options.onDragEnd);
|
|
24
27
|
const setDragging = (0, react.useCallback)((value) => {
|
|
25
28
|
setIsDragging(value);
|
|
26
29
|
isDraggingRef.current = value;
|
|
@@ -74,7 +77,7 @@ function useFloatingWindow(options = {}) {
|
|
|
74
77
|
x: point.clientX - rect.left,
|
|
75
78
|
y: point.clientY - rect.top
|
|
76
79
|
};
|
|
77
|
-
|
|
80
|
+
onDragStartRef.current?.();
|
|
78
81
|
document.addEventListener("mousemove", onMove, { signal });
|
|
79
82
|
document.addEventListener("mouseup", onEnd, { signal });
|
|
80
83
|
document.addEventListener("touchmove", onMove, {
|
|
@@ -82,6 +85,7 @@ function useFloatingWindow(options = {}) {
|
|
|
82
85
|
passive: false
|
|
83
86
|
});
|
|
84
87
|
document.addEventListener("touchend", onEnd, { signal });
|
|
88
|
+
document.addEventListener("touchcancel", onEnd, { signal });
|
|
85
89
|
};
|
|
86
90
|
const onMove = (e) => {
|
|
87
91
|
if (!isDraggingRef.current) return;
|
|
@@ -111,7 +115,7 @@ function useFloatingWindow(options = {}) {
|
|
|
111
115
|
ref.current.style.left = `${x}px`;
|
|
112
116
|
ref.current.style.top = `${y}px`;
|
|
113
117
|
}
|
|
114
|
-
|
|
118
|
+
onPositionChangeRef.current?.({
|
|
115
119
|
x,
|
|
116
120
|
y
|
|
117
121
|
});
|
|
@@ -121,7 +125,7 @@ function useFloatingWindow(options = {}) {
|
|
|
121
125
|
setDragging(false);
|
|
122
126
|
document.body.style.userSelect = "";
|
|
123
127
|
document.body.style.webkitUserSelect = "";
|
|
124
|
-
|
|
128
|
+
onDragEndRef.current?.();
|
|
125
129
|
}
|
|
126
130
|
};
|
|
127
131
|
el.addEventListener("mousedown", onStart, { signal });
|
|
@@ -137,9 +141,6 @@ function useFloatingWindow(options = {}) {
|
|
|
137
141
|
options.constrainOffset,
|
|
138
142
|
options.dragHandleSelector,
|
|
139
143
|
options.axis,
|
|
140
|
-
options.onPositionChange,
|
|
141
|
-
options.onDragStart,
|
|
142
|
-
options.onDragEnd,
|
|
143
144
|
options.initialPosition?.top,
|
|
144
145
|
options.initialPosition?.left,
|
|
145
146
|
options.initialPosition?.right,
|
|
@@ -186,15 +187,11 @@ function useFloatingWindow(options = {}) {
|
|
|
186
187
|
};
|
|
187
188
|
el.style.left = `${x}px`;
|
|
188
189
|
el.style.top = `${y}px`;
|
|
189
|
-
|
|
190
|
+
onPositionChangeRef.current?.({
|
|
190
191
|
x,
|
|
191
192
|
y
|
|
192
193
|
});
|
|
193
|
-
}, [
|
|
194
|
-
options.constrainToViewport,
|
|
195
|
-
options.constrainOffset,
|
|
196
|
-
options.onPositionChange
|
|
197
|
-
]),
|
|
194
|
+
}, [options.constrainToViewport, options.constrainOffset]),
|
|
198
195
|
isDragging
|
|
199
196
|
};
|
|
200
197
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-floating-window.cjs","names":[],"sources":["../../src/use-floating-window/use-floating-window.ts"],"sourcesContent":["// Required to disable for webkit-user-select, although deprecated, it is still required for Safari support\nimport { RefCallback, useCallback, useEffect, useRef, useState } from 'react';\n\nfunction useRefValue<T>(value: T) {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n\ninterface FloatingWindowPositionConfig {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n}\n\ninterface FloatingWindowPosition {\n /** Element offset from the left side of the viewport */\n x: number;\n\n /** Element offset from the top side of the viewport */\n y: number;\n}\n\nexport interface UseFloatingWindowOptions {\n /** If `false`, the element can not be dragged. */\n enabled?: boolean;\n\n /** If `true`, the element can only move within the current viewport boundaries. */\n constrainToViewport?: boolean;\n\n /** The offset from the viewport edges when constraining the element. Requires `constrainToViewport: true`. */\n constrainOffset?: number;\n\n /** Selector of an element that should be used to drag floating window. If not specified, the entire root element is used as a drag target. */\n dragHandleSelector?: string;\n\n /** Selector of an element within `dragHandleSelector` that should be excluded from the drag event. */\n excludeDragHandleSelector?: string;\n\n /** If set, restricts movement to the specified axis */\n axis?: 'x' | 'y';\n\n /** Initial position. If not set, calculated from element styles. */\n initialPosition?: FloatingWindowPositionConfig;\n\n /** Called when the element position changes */\n onPositionChange?: (pos: FloatingWindowPosition) => void;\n\n /** Called when the drag starts */\n onDragStart?: () => void;\n\n /** Called when the drag stops */\n onDragEnd?: () => void;\n}\n\nexport type SetFloatingWindowPosition = (position: FloatingWindowPositionConfig) => void;\n\nexport interface UseFloatingWindowReturnValue<T extends HTMLElement> {\n /** Ref to the element that should be draggable */\n ref: RefCallback<T | null>;\n\n /** Function to set the position of the element */\n setPosition: SetFloatingWindowPosition;\n\n /** `true` if the element is currently being dragged */\n isDragging: boolean;\n}\n\nexport function useFloatingWindow<T extends HTMLElement>(\n options: UseFloatingWindowOptions = {}\n): UseFloatingWindowReturnValue<T> {\n const [element, setElement] = useState<T | null>(null);\n const ref = useRef<T>(null);\n const pos = useRef({ x: 0, y: 0 });\n const offset = useRef({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const isDraggingRef = useRef(false);\n const initialized = useRef(false);\n const enabledRef = useRefValue(options.enabled);\n\n const setDragging = useCallback((value: boolean) => {\n setIsDragging(value);\n isDraggingRef.current = value;\n }, []);\n\n const assignRef = useCallback((node: T | null) => {\n if (node) {\n ref.current = node;\n setElement(node);\n } else {\n ref.current = null;\n setElement(null);\n }\n }, []);\n\n useEffect(() => {\n const el = ref.current;\n if (!initialized.current && el) {\n initialized.current = true;\n pos.current = calculateInitialPosition(el, options);\n el.style.left = `${pos.current.x}px`;\n el.style.top = `${pos.current.y}px`;\n el.style.right = 'unset';\n el.style.bottom = 'unset';\n }\n\n return () => {\n initialized.current = false;\n };\n }, [\n element,\n options.constrainOffset,\n options.initialPosition?.top,\n options.initialPosition?.left,\n options.initialPosition?.right,\n options.initialPosition?.bottom,\n options.constrainToViewport,\n ]);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const controller = new AbortController();\n const signal = controller.signal;\n\n const onStart = (e: MouseEvent | TouchEvent) => {\n if (enabledRef.current === false) {\n return;\n }\n\n const point = 'touches' in e ? e.touches[0] : e;\n\n if ('button' in e && e.button !== 0) {\n return;\n }\n\n if (!getHandle(el, e.target, options)) {\n return;\n }\n\n setDragging(true);\n document.body.style.userSelect = 'none';\n document.body.style.webkitUserSelect = 'none';\n\n const rect = el.getBoundingClientRect();\n\n offset.current = {\n x: point.clientX - rect.left,\n y: point.clientY - rect.top,\n };\n\n options.onDragStart?.();\n\n document.addEventListener('mousemove', onMove, { signal });\n document.addEventListener('mouseup', onEnd, { signal });\n document.addEventListener('touchmove', onMove, { signal, passive: false });\n document.addEventListener('touchend', onEnd, { signal });\n };\n\n const onMove = (e: MouseEvent | TouchEvent) => {\n if (!isDraggingRef.current) {\n return;\n }\n\n const point = 'touches' in e ? e.touches[0] : e;\n e.preventDefault();\n\n let x = point.clientX - offset.current.x;\n let y = point.clientY - offset.current.y;\n\n const constrained = getConstrainedPosition(el, { x, y }, options);\n if (options.axis === 'x') {\n x = constrained.x;\n y = pos.current.y;\n } else if (options.axis === 'y') {\n x = pos.current.x;\n y = constrained.y;\n } else {\n x = constrained.x;\n y = constrained.y;\n }\n\n pos.current = { x, y };\n\n if (ref.current) {\n ref.current.style.left = `${x}px`;\n ref.current.style.top = `${y}px`;\n }\n\n options.onPositionChange?.({ x, y });\n };\n\n const onEnd = () => {\n if (isDraggingRef.current) {\n setDragging(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n options.onDragEnd?.();\n }\n };\n\n el.addEventListener('mousedown', onStart, { signal });\n el.addEventListener('touchstart', onStart, { signal, passive: false });\n\n return () => {\n controller.abort();\n };\n }, [\n options.constrainToViewport,\n options.constrainOffset,\n options.dragHandleSelector,\n options.axis,\n options.onPositionChange,\n options.onDragStart,\n options.onDragEnd,\n options.initialPosition?.top,\n options.initialPosition?.left,\n options.initialPosition?.right,\n options.initialPosition?.bottom,\n element,\n ]);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const observer = new ResizeObserver(() => {\n // Re-clamp current position if element size changes\n const constrained = getConstrainedPosition(el, pos.current, options);\n pos.current = constrained;\n el.style.left = `${constrained.x}px`;\n el.style.top = `${constrained.y}px`;\n });\n\n observer.observe(el);\n\n return () => {\n observer.disconnect();\n };\n }, [options.constrainToViewport, options.constrainOffset]);\n\n const setPosition = useCallback(\n (position: FloatingWindowPositionConfig) => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const offset = options.constrainOffset ?? 0;\n const rect = el.getBoundingClientRect();\n\n let x: number | undefined;\n let y: number | undefined;\n\n if (position.left != null) {\n x = position.left;\n } else if (position.right != null) {\n x = window.innerWidth - rect.width - position.right;\n }\n\n if (position.top != null) {\n y = position.top;\n } else if (position.bottom != null) {\n y = window.innerHeight - rect.height - position.bottom;\n }\n\n x = x ?? pos.current.x;\n y = y ?? pos.current.y;\n\n if (options.constrainToViewport) {\n const clamped = clampToViewport(x, y, el, offset);\n x = clamped.x;\n y = clamped.y;\n }\n\n pos.current = { x, y };\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n options.onPositionChange?.({ x, y });\n },\n [options.constrainToViewport, options.constrainOffset, options.onPositionChange]\n );\n\n return {\n ref: assignRef,\n setPosition,\n isDragging,\n };\n}\n\n// -------------------------------------------------------\n// Helper functions\n// -------------------------------------------------------\n\nfunction px(v: string) {\n return v.endsWith('px') ? parseFloat(v) : 0;\n}\n\nfunction calculateInitialPosition(\n el: HTMLElement,\n options: UseFloatingWindowOptions\n): { x: number; y: number } {\n const rect = el.getBoundingClientRect();\n const offset = options.constrainOffset ?? 0;\n const winW = window.innerWidth;\n const winH = window.innerHeight;\n const style = window.getComputedStyle(el);\n const top = options.initialPosition?.top;\n const left = options.initialPosition?.left;\n const right = options.initialPosition?.right;\n const bottom = options.initialPosition?.bottom;\n\n let x = offset;\n let y = offset;\n\n if (left != null) {\n x = left;\n } else if (right != null) {\n x = winW - rect.width - right;\n } else {\n x = px(style.left) || winW - rect.width - px(style.right) || offset;\n }\n\n if (top != null) {\n y = top;\n } else if (bottom != null) {\n y = winH - rect.height - bottom;\n } else {\n y = px(style.top) || winH - rect.height - px(style.bottom) || offset;\n }\n\n return options.constrainToViewport\n ? clampToViewport(x, y, el, options.constrainOffset)\n : { x, y };\n}\n\nfunction getConstrainedPosition(\n el: HTMLElement,\n pos: FloatingWindowPosition,\n options: UseFloatingWindowOptions\n) {\n if (!options.constrainToViewport || !el) {\n return pos;\n }\n\n const rect = el.getBoundingClientRect();\n const offset = options.constrainOffset ?? 0;\n const maxX = window.innerWidth - rect.width - offset;\n const maxY = window.innerHeight - rect.height - offset;\n\n return {\n x: Math.min(Math.max(offset, pos.x), maxX),\n y: Math.min(Math.max(offset, pos.y), maxY),\n };\n}\n\nfunction matchesExcludeSelector(target: Node, excludeSelector?: string): boolean {\n if (!excludeSelector) {\n return false;\n }\n if (!(target instanceof Element)) {\n return false;\n }\n\n return Boolean(target.closest(excludeSelector));\n}\n\nfunction getHandle(\n el: HTMLElement,\n target: EventTarget | null,\n options: UseFloatingWindowOptions\n): boolean {\n if (!(target instanceof Node)) {\n return false;\n }\n\n // If no drag handle selector, allow dragging from entire element\n if (!options.dragHandleSelector) {\n return !matchesExcludeSelector(target, options.excludeDragHandleSelector);\n }\n\n const handles = Array.from(el.querySelectorAll(options.dragHandleSelector));\n return handles.some(\n (handle) =>\n handle.contains(target) && !matchesExcludeSelector(target, options.excludeDragHandleSelector)\n );\n}\n\nfunction clampToViewport(\n x: number,\n y: number,\n el: HTMLElement,\n offset: number = 0\n): { x: number; y: number } {\n const rect = el.getBoundingClientRect();\n const maxX = window.innerWidth - rect.width - offset;\n const maxY = window.innerHeight - rect.height - offset;\n\n return {\n x: Math.min(Math.max(offset, x), maxX),\n y: Math.min(Math.max(offset, y), maxY),\n };\n}\n\nexport namespace useFloatingWindow {\n export type Options = UseFloatingWindowOptions;\n export type Position = FloatingWindowPosition;\n export type SetPosition = SetFloatingWindowPosition;\n export type ReturnValue<T extends HTMLElement> = UseFloatingWindowReturnValue<T>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-floating-window.cjs","names":[],"sources":["../../src/use-floating-window/use-floating-window.ts"],"sourcesContent":["// Required to disable for webkit-user-select, although deprecated, it is still required for Safari support\nimport { RefCallback, useCallback, useEffect, useRef, useState } from 'react';\n\nfunction useRefValue<T>(value: T) {\n const ref = useRef(value);\n ref.current = value;\n return ref;\n}\n\ninterface FloatingWindowPositionConfig {\n top?: number;\n left?: number;\n right?: number;\n bottom?: number;\n}\n\ninterface FloatingWindowPosition {\n /** Element offset from the left side of the viewport */\n x: number;\n\n /** Element offset from the top side of the viewport */\n y: number;\n}\n\nexport interface UseFloatingWindowOptions {\n /** If `false`, the element can not be dragged. */\n enabled?: boolean;\n\n /** If `true`, the element can only move within the current viewport boundaries. */\n constrainToViewport?: boolean;\n\n /** The offset from the viewport edges when constraining the element. Requires `constrainToViewport: true`. */\n constrainOffset?: number;\n\n /** Selector of an element that should be used to drag floating window. If not specified, the entire root element is used as a drag target. */\n dragHandleSelector?: string;\n\n /** Selector of an element within `dragHandleSelector` that should be excluded from the drag event. */\n excludeDragHandleSelector?: string;\n\n /** If set, restricts movement to the specified axis */\n axis?: 'x' | 'y';\n\n /** Initial position. If not set, calculated from element styles. */\n initialPosition?: FloatingWindowPositionConfig;\n\n /** Called when the element position changes */\n onPositionChange?: (pos: FloatingWindowPosition) => void;\n\n /** Called when the drag starts */\n onDragStart?: () => void;\n\n /** Called when the drag stops */\n onDragEnd?: () => void;\n}\n\nexport type SetFloatingWindowPosition = (position: FloatingWindowPositionConfig) => void;\n\nexport interface UseFloatingWindowReturnValue<T extends HTMLElement> {\n /** Ref to the element that should be draggable */\n ref: RefCallback<T | null>;\n\n /** Function to set the position of the element */\n setPosition: SetFloatingWindowPosition;\n\n /** `true` if the element is currently being dragged */\n isDragging: boolean;\n}\n\nexport function useFloatingWindow<T extends HTMLElement>(\n options: UseFloatingWindowOptions = {}\n): UseFloatingWindowReturnValue<T> {\n const [element, setElement] = useState<T | null>(null);\n const ref = useRef<T>(null);\n const pos = useRef({ x: 0, y: 0 });\n const offset = useRef({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const isDraggingRef = useRef(false);\n const initialized = useRef(false);\n const enabledRef = useRefValue(options.enabled);\n const onPositionChangeRef = useRefValue(options.onPositionChange);\n const onDragStartRef = useRefValue(options.onDragStart);\n const onDragEndRef = useRefValue(options.onDragEnd);\n\n const setDragging = useCallback((value: boolean) => {\n setIsDragging(value);\n isDraggingRef.current = value;\n }, []);\n\n const assignRef = useCallback((node: T | null) => {\n if (node) {\n ref.current = node;\n setElement(node);\n } else {\n ref.current = null;\n setElement(null);\n }\n }, []);\n\n useEffect(() => {\n const el = ref.current;\n if (!initialized.current && el) {\n initialized.current = true;\n pos.current = calculateInitialPosition(el, options);\n el.style.left = `${pos.current.x}px`;\n el.style.top = `${pos.current.y}px`;\n el.style.right = 'unset';\n el.style.bottom = 'unset';\n }\n\n return () => {\n initialized.current = false;\n };\n }, [\n element,\n options.constrainOffset,\n options.initialPosition?.top,\n options.initialPosition?.left,\n options.initialPosition?.right,\n options.initialPosition?.bottom,\n options.constrainToViewport,\n ]);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const controller = new AbortController();\n const signal = controller.signal;\n\n const onStart = (e: MouseEvent | TouchEvent) => {\n if (enabledRef.current === false) {\n return;\n }\n\n const point = 'touches' in e ? e.touches[0] : e;\n\n if ('button' in e && e.button !== 0) {\n return;\n }\n\n if (!getHandle(el, e.target, options)) {\n return;\n }\n\n setDragging(true);\n document.body.style.userSelect = 'none';\n document.body.style.webkitUserSelect = 'none';\n\n const rect = el.getBoundingClientRect();\n\n offset.current = {\n x: point.clientX - rect.left,\n y: point.clientY - rect.top,\n };\n\n onDragStartRef.current?.();\n\n document.addEventListener('mousemove', onMove, { signal });\n document.addEventListener('mouseup', onEnd, { signal });\n document.addEventListener('touchmove', onMove, { signal, passive: false });\n document.addEventListener('touchend', onEnd, { signal });\n document.addEventListener('touchcancel', onEnd, { signal });\n };\n\n const onMove = (e: MouseEvent | TouchEvent) => {\n if (!isDraggingRef.current) {\n return;\n }\n\n const point = 'touches' in e ? e.touches[0] : e;\n e.preventDefault();\n\n let x = point.clientX - offset.current.x;\n let y = point.clientY - offset.current.y;\n\n const constrained = getConstrainedPosition(el, { x, y }, options);\n if (options.axis === 'x') {\n x = constrained.x;\n y = pos.current.y;\n } else if (options.axis === 'y') {\n x = pos.current.x;\n y = constrained.y;\n } else {\n x = constrained.x;\n y = constrained.y;\n }\n\n pos.current = { x, y };\n\n if (ref.current) {\n ref.current.style.left = `${x}px`;\n ref.current.style.top = `${y}px`;\n }\n\n onPositionChangeRef.current?.({ x, y });\n };\n\n const onEnd = () => {\n if (isDraggingRef.current) {\n setDragging(false);\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n onDragEndRef.current?.();\n }\n };\n\n el.addEventListener('mousedown', onStart, { signal });\n el.addEventListener('touchstart', onStart, { signal, passive: false });\n\n return () => {\n controller.abort();\n };\n }, [\n options.constrainToViewport,\n options.constrainOffset,\n options.dragHandleSelector,\n options.axis,\n options.initialPosition?.top,\n options.initialPosition?.left,\n options.initialPosition?.right,\n options.initialPosition?.bottom,\n element,\n ]);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const observer = new ResizeObserver(() => {\n // Re-clamp current position if element size changes\n const constrained = getConstrainedPosition(el, pos.current, options);\n pos.current = constrained;\n el.style.left = `${constrained.x}px`;\n el.style.top = `${constrained.y}px`;\n });\n\n observer.observe(el);\n\n return () => {\n observer.disconnect();\n };\n }, [options.constrainToViewport, options.constrainOffset]);\n\n const setPosition = useCallback(\n (position: FloatingWindowPositionConfig) => {\n const el = ref.current;\n if (!el) {\n return;\n }\n\n const offset = options.constrainOffset ?? 0;\n const rect = el.getBoundingClientRect();\n\n let x: number | undefined;\n let y: number | undefined;\n\n if (position.left != null) {\n x = position.left;\n } else if (position.right != null) {\n x = window.innerWidth - rect.width - position.right;\n }\n\n if (position.top != null) {\n y = position.top;\n } else if (position.bottom != null) {\n y = window.innerHeight - rect.height - position.bottom;\n }\n\n x = x ?? pos.current.x;\n y = y ?? pos.current.y;\n\n if (options.constrainToViewport) {\n const clamped = clampToViewport(x, y, el, offset);\n x = clamped.x;\n y = clamped.y;\n }\n\n pos.current = { x, y };\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n onPositionChangeRef.current?.({ x, y });\n },\n [options.constrainToViewport, options.constrainOffset]\n );\n\n return {\n ref: assignRef,\n setPosition,\n isDragging,\n };\n}\n\n// -------------------------------------------------------\n// Helper functions\n// -------------------------------------------------------\n\nfunction px(v: string) {\n return v.endsWith('px') ? parseFloat(v) : 0;\n}\n\nfunction calculateInitialPosition(\n el: HTMLElement,\n options: UseFloatingWindowOptions\n): { x: number; y: number } {\n const rect = el.getBoundingClientRect();\n const offset = options.constrainOffset ?? 0;\n const winW = window.innerWidth;\n const winH = window.innerHeight;\n const style = window.getComputedStyle(el);\n const top = options.initialPosition?.top;\n const left = options.initialPosition?.left;\n const right = options.initialPosition?.right;\n const bottom = options.initialPosition?.bottom;\n\n let x = offset;\n let y = offset;\n\n if (left != null) {\n x = left;\n } else if (right != null) {\n x = winW - rect.width - right;\n } else {\n x = px(style.left) || winW - rect.width - px(style.right) || offset;\n }\n\n if (top != null) {\n y = top;\n } else if (bottom != null) {\n y = winH - rect.height - bottom;\n } else {\n y = px(style.top) || winH - rect.height - px(style.bottom) || offset;\n }\n\n return options.constrainToViewport\n ? clampToViewport(x, y, el, options.constrainOffset)\n : { x, y };\n}\n\nfunction getConstrainedPosition(\n el: HTMLElement,\n pos: FloatingWindowPosition,\n options: UseFloatingWindowOptions\n) {\n if (!options.constrainToViewport || !el) {\n return pos;\n }\n\n const rect = el.getBoundingClientRect();\n const offset = options.constrainOffset ?? 0;\n const maxX = window.innerWidth - rect.width - offset;\n const maxY = window.innerHeight - rect.height - offset;\n\n return {\n x: Math.min(Math.max(offset, pos.x), maxX),\n y: Math.min(Math.max(offset, pos.y), maxY),\n };\n}\n\nfunction matchesExcludeSelector(target: Node, excludeSelector?: string): boolean {\n if (!excludeSelector) {\n return false;\n }\n if (!(target instanceof Element)) {\n return false;\n }\n\n return Boolean(target.closest(excludeSelector));\n}\n\nfunction getHandle(\n el: HTMLElement,\n target: EventTarget | null,\n options: UseFloatingWindowOptions\n): boolean {\n if (!(target instanceof Node)) {\n return false;\n }\n\n // If no drag handle selector, allow dragging from entire element\n if (!options.dragHandleSelector) {\n return !matchesExcludeSelector(target, options.excludeDragHandleSelector);\n }\n\n const handles = Array.from(el.querySelectorAll(options.dragHandleSelector));\n return handles.some(\n (handle) =>\n handle.contains(target) && !matchesExcludeSelector(target, options.excludeDragHandleSelector)\n );\n}\n\nfunction clampToViewport(\n x: number,\n y: number,\n el: HTMLElement,\n offset: number = 0\n): { x: number; y: number } {\n const rect = el.getBoundingClientRect();\n const maxX = window.innerWidth - rect.width - offset;\n const maxY = window.innerHeight - rect.height - offset;\n\n return {\n x: Math.min(Math.max(offset, x), maxX),\n y: Math.min(Math.max(offset, y), maxY),\n };\n}\n\nexport namespace useFloatingWindow {\n export type Options = UseFloatingWindowOptions;\n export type Position = FloatingWindowPosition;\n export type SetPosition = SetFloatingWindowPosition;\n export type ReturnValue<T extends HTMLElement> = UseFloatingWindowReturnValue<T>;\n}\n"],"mappings":"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"}
|
|
@@ -74,6 +74,8 @@ function useHeadroom({ fixedAt = 0, scrollDistance = 100, onPin, onFix, onReleas
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
//#endregion
|
|
77
|
+
exports.isFixed = isFixed;
|
|
78
|
+
exports.isPinnedOrReleased = isPinnedOrReleased;
|
|
77
79
|
exports.useHeadroom = useHeadroom;
|
|
78
80
|
|
|
79
81
|
//# sourceMappingURL=use-headroom.cjs.map
|
|
@@ -250,10 +250,11 @@ function useMask(options) {
|
|
|
250
250
|
const newRaw = extractRaw(reprocessed, resolvedSlots);
|
|
251
251
|
const showSlots = opts.alwaysShowMask || isFocusedRef.current;
|
|
252
252
|
const showOnFocus = opts.showMaskOnFocus !== false;
|
|
253
|
+
const displayValue = buildDisplayValue(reprocessed, resolvedSlots, slotChar, showSlots && (showOnFocus || reprocessed.length > 0));
|
|
253
254
|
applyValue({
|
|
254
255
|
reprocessed,
|
|
255
256
|
newRaw,
|
|
256
|
-
displayValue
|
|
257
|
+
displayValue,
|
|
257
258
|
resolvedSlots,
|
|
258
259
|
notifyChange: false
|
|
259
260
|
});
|
|
@@ -275,7 +276,8 @@ function useMask(options) {
|
|
|
275
276
|
const applyHistoryState = (0, react.useCallback)((target) => {
|
|
276
277
|
const opts = optionsRef.current;
|
|
277
278
|
const { slots, slotChar, transform } = getResolvedOptions(opts, target.rawValue);
|
|
278
|
-
|
|
279
|
+
const newMasked = applyMaskToRaw(target.rawValue, slots, slotChar, transform);
|
|
280
|
+
updateValue(newMasked, target.selectionStart);
|
|
279
281
|
}, [updateValue]);
|
|
280
282
|
const handleInput = (0, react.useCallback)((e) => {
|
|
281
283
|
const input = e.target;
|