@mantine/hooks 9.0.1 → 9.1.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/index.cjs +8 -0
- package/cjs/use-click-outside/use-click-outside.cjs +11 -8
- package/cjs/use-click-outside/use-click-outside.cjs.map +1 -1
- package/cjs/use-clipboard/use-clipboard.cjs +13 -6
- package/cjs/use-clipboard/use-clipboard.cjs.map +1 -1
- package/cjs/use-collapse/use-collapse.cjs +1 -1
- package/cjs/use-collapse/use-collapse.cjs.map +1 -1
- package/cjs/use-collapse/use-horizontal-collapse.cjs +4 -3
- package/cjs/use-collapse/use-horizontal-collapse.cjs.map +1 -1
- package/cjs/use-counter/use-counter.cjs +12 -3
- package/cjs/use-counter/use-counter.cjs.map +1 -1
- package/cjs/use-debounced-callback/use-debounced-callback.cjs +28 -4
- package/cjs/use-debounced-callback/use-debounced-callback.cjs.map +1 -1
- package/cjs/use-debounced-state/use-debounced-state.cjs +1 -1
- package/cjs/use-debounced-state/use-debounced-state.cjs.map +1 -1
- package/cjs/use-debounced-value/use-debounced-value.cjs +22 -2
- package/cjs/use-debounced-value/use-debounced-value.cjs.map +1 -1
- package/cjs/use-event-listener/use-event-listener.cjs.map +1 -1
- package/cjs/use-favicon/use-favicon.cjs +3 -1
- package/cjs/use-favicon/use-favicon.cjs.map +1 -1
- package/cjs/use-fetch/use-fetch.cjs +7 -4
- package/cjs/use-fetch/use-fetch.cjs.map +1 -1
- package/cjs/use-file-dialog/use-file-dialog.cjs +1 -0
- package/cjs/use-file-dialog/use-file-dialog.cjs.map +1 -1
- package/cjs/use-floating-window/use-floating-window.cjs +33 -36
- package/cjs/use-floating-window/use-floating-window.cjs.map +1 -1
- package/cjs/use-focus-trap/use-focus-trap.cjs +12 -9
- package/cjs/use-focus-trap/use-focus-trap.cjs.map +1 -1
- package/cjs/use-fullscreen/use-fullscreen.cjs +3 -1
- package/cjs/use-fullscreen/use-fullscreen.cjs.map +1 -1
- package/cjs/use-headroom/use-headroom.cjs +4 -1
- package/cjs/use-headroom/use-headroom.cjs.map +1 -1
- package/cjs/use-hotkeys/parse-hotkey.cjs +1 -2
- package/cjs/use-hotkeys/parse-hotkey.cjs.map +1 -1
- package/cjs/use-hover/use-hover.cjs +1 -0
- package/cjs/use-hover/use-hover.cjs.map +1 -1
- package/cjs/use-in-viewport/use-in-viewport.cjs +11 -7
- package/cjs/use-in-viewport/use-in-viewport.cjs.map +1 -1
- package/cjs/use-interval/use-interval.cjs +15 -6
- package/cjs/use-interval/use-interval.cjs.map +1 -1
- package/cjs/use-local-storage/create-storage.cjs +1 -1
- package/cjs/use-local-storage/create-storage.cjs.map +1 -1
- package/cjs/use-long-press/use-long-press.cjs +6 -2
- package/cjs/use-long-press/use-long-press.cjs.map +1 -1
- package/cjs/use-mask/use-mask.cjs +457 -0
- package/cjs/use-mask/use-mask.cjs.map +1 -0
- package/cjs/use-mouse/use-mouse.cjs +2 -2
- package/cjs/use-mouse/use-mouse.cjs.map +1 -1
- package/cjs/use-move/use-move.cjs +8 -0
- package/cjs/use-move/use-move.cjs.map +1 -1
- package/cjs/use-orientation/use-orientation.cjs +8 -2
- package/cjs/use-orientation/use-orientation.cjs.map +1 -1
- package/cjs/use-os/use-os.cjs +1 -1
- package/cjs/use-os/use-os.cjs.map +1 -1
- package/cjs/use-radial-move/use-radial-move.cjs +4 -4
- package/cjs/use-radial-move/use-radial-move.cjs.map +1 -1
- package/cjs/use-roving-index/use-roving-index.cjs +200 -0
- package/cjs/use-roving-index/use-roving-index.cjs.map +1 -0
- package/cjs/use-scroll-direction/use-scroll-direction.cjs +7 -7
- package/cjs/use-scroll-direction/use-scroll-direction.cjs.map +1 -1
- package/cjs/use-scroll-into-view/use-scroll-into-view.cjs +14 -4
- package/cjs/use-scroll-into-view/use-scroll-into-view.cjs.map +1 -1
- package/cjs/use-scroll-spy/use-scroll-spy.cjs +7 -3
- package/cjs/use-scroll-spy/use-scroll-spy.cjs.map +1 -1
- package/cjs/use-scroller/use-scroller.cjs +3 -3
- package/cjs/use-scroller/use-scroller.cjs.map +1 -1
- package/cjs/use-set/use-set.cjs +6 -1
- package/cjs/use-set/use-set.cjs.map +1 -1
- package/cjs/use-throttled-callback/use-throttled-callback.cjs +3 -1
- package/cjs/use-throttled-callback/use-throttled-callback.cjs.map +1 -1
- package/cjs/use-timeout/use-timeout.cjs +3 -1
- package/cjs/use-timeout/use-timeout.cjs.map +1 -1
- package/cjs/use-viewport-size/use-viewport-size.cjs +3 -3
- package/cjs/use-viewport-size/use-viewport-size.cjs.map +1 -1
- package/cjs/use-window-scroll/use-window-scroll.cjs +2 -2
- package/cjs/use-window-scroll/use-window-scroll.cjs.map +1 -1
- package/esm/index.mjs +3 -1
- package/esm/use-click-outside/use-click-outside.mjs +11 -8
- package/esm/use-click-outside/use-click-outside.mjs.map +1 -1
- package/esm/use-clipboard/use-clipboard.mjs +14 -7
- package/esm/use-clipboard/use-clipboard.mjs.map +1 -1
- package/esm/use-collapse/use-collapse.mjs +1 -1
- package/esm/use-collapse/use-collapse.mjs.map +1 -1
- package/esm/use-collapse/use-horizontal-collapse.mjs +5 -4
- package/esm/use-collapse/use-horizontal-collapse.mjs.map +1 -1
- package/esm/use-counter/use-counter.mjs +12 -3
- package/esm/use-counter/use-counter.mjs.map +1 -1
- package/esm/use-debounced-callback/use-debounced-callback.mjs +28 -4
- package/esm/use-debounced-callback/use-debounced-callback.mjs.map +1 -1
- package/esm/use-debounced-state/use-debounced-state.mjs +1 -1
- package/esm/use-debounced-state/use-debounced-state.mjs.map +1 -1
- package/esm/use-debounced-value/use-debounced-value.mjs +22 -2
- package/esm/use-debounced-value/use-debounced-value.mjs.map +1 -1
- package/esm/use-event-listener/use-event-listener.mjs.map +1 -1
- package/esm/use-favicon/use-favicon.mjs +3 -1
- package/esm/use-favicon/use-favicon.mjs.map +1 -1
- package/esm/use-fetch/use-fetch.mjs +7 -4
- package/esm/use-fetch/use-fetch.mjs.map +1 -1
- package/esm/use-file-dialog/use-file-dialog.mjs +1 -0
- package/esm/use-file-dialog/use-file-dialog.mjs.map +1 -1
- package/esm/use-floating-window/use-floating-window.mjs +33 -36
- package/esm/use-floating-window/use-floating-window.mjs.map +1 -1
- package/esm/use-focus-trap/use-focus-trap.mjs +12 -9
- package/esm/use-focus-trap/use-focus-trap.mjs.map +1 -1
- package/esm/use-fullscreen/use-fullscreen.mjs +3 -1
- package/esm/use-fullscreen/use-fullscreen.mjs.map +1 -1
- package/esm/use-headroom/use-headroom.mjs +4 -1
- package/esm/use-headroom/use-headroom.mjs.map +1 -1
- package/esm/use-hotkeys/parse-hotkey.mjs +1 -2
- package/esm/use-hotkeys/parse-hotkey.mjs.map +1 -1
- package/esm/use-hover/use-hover.mjs +1 -0
- package/esm/use-hover/use-hover.mjs.map +1 -1
- package/esm/use-in-viewport/use-in-viewport.mjs +11 -7
- package/esm/use-in-viewport/use-in-viewport.mjs.map +1 -1
- package/esm/use-interval/use-interval.mjs +15 -6
- package/esm/use-interval/use-interval.mjs.map +1 -1
- package/esm/use-local-storage/create-storage.mjs +1 -1
- package/esm/use-local-storage/create-storage.mjs.map +1 -1
- package/esm/use-long-press/use-long-press.mjs +6 -2
- package/esm/use-long-press/use-long-press.mjs.map +1 -1
- package/esm/use-mask/use-mask.mjs +453 -0
- package/esm/use-mask/use-mask.mjs.map +1 -0
- package/esm/use-mouse/use-mouse.mjs +2 -2
- package/esm/use-mouse/use-mouse.mjs.map +1 -1
- package/esm/use-move/use-move.mjs +8 -0
- package/esm/use-move/use-move.mjs.map +1 -1
- package/esm/use-orientation/use-orientation.mjs +8 -2
- package/esm/use-orientation/use-orientation.mjs.map +1 -1
- package/esm/use-os/use-os.mjs +1 -1
- package/esm/use-os/use-os.mjs.map +1 -1
- package/esm/use-radial-move/use-radial-move.mjs +5 -5
- package/esm/use-radial-move/use-radial-move.mjs.map +1 -1
- package/esm/use-roving-index/use-roving-index.mjs +200 -0
- package/esm/use-roving-index/use-roving-index.mjs.map +1 -0
- package/esm/use-scroll-direction/use-scroll-direction.mjs +7 -7
- package/esm/use-scroll-direction/use-scroll-direction.mjs.map +1 -1
- package/esm/use-scroll-into-view/use-scroll-into-view.mjs +15 -5
- package/esm/use-scroll-into-view/use-scroll-into-view.mjs.map +1 -1
- package/esm/use-scroll-spy/use-scroll-spy.mjs +8 -4
- package/esm/use-scroll-spy/use-scroll-spy.mjs.map +1 -1
- package/esm/use-scroller/use-scroller.mjs +3 -3
- package/esm/use-scroller/use-scroller.mjs.map +1 -1
- package/esm/use-set/use-set.mjs +6 -1
- package/esm/use-set/use-set.mjs.map +1 -1
- package/esm/use-throttled-callback/use-throttled-callback.mjs +3 -1
- package/esm/use-throttled-callback/use-throttled-callback.mjs.map +1 -1
- package/esm/use-timeout/use-timeout.mjs +3 -1
- package/esm/use-timeout/use-timeout.mjs.map +1 -1
- package/esm/use-viewport-size/use-viewport-size.mjs +3 -3
- package/esm/use-viewport-size/use-viewport-size.mjs.map +1 -1
- package/esm/use-window-scroll/use-window-scroll.mjs +2 -2
- package/esm/use-window-scroll/use-window-scroll.mjs.map +1 -1
- package/lib/index.d.mts +5 -1
- package/lib/index.d.ts +5 -1
- package/lib/use-click-outside/use-click-outside.d.ts +1 -1
- package/lib/use-collapse/use-horizontal-collapse.d.ts +5 -0
- package/lib/use-counter/use-counter.d.ts +1 -0
- package/lib/use-debounced-callback/use-debounced-callback.d.ts +4 -0
- package/lib/use-debounced-value/use-debounced-value.d.ts +6 -1
- package/lib/use-event-listener/use-event-listener.d.ts +1 -1
- package/lib/use-hotkeys/parse-hotkey.d.ts +4 -5
- package/lib/use-long-press/use-long-press.d.ts +1 -0
- package/lib/use-mask/use-mask.d.ts +60 -0
- package/lib/use-roving-index/use-roving-index.d.ts +49 -0
- package/lib/use-scroll-into-view/use-scroll-into-view.d.ts +4 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-file-dialog.cjs","names":[],"sources":["../../src/use-file-dialog/use-file-dialog.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\n\nexport interface UseFileDialogOptions {\n /** Determines whether multiple files are allowed, `true` by default */\n multiple?: boolean;\n\n /** `accept` attribute of the file input, '*' by default */\n accept?: string;\n\n /** `capture` attribute of the file input */\n capture?: string;\n\n /** Determines whether the user can pick a directory instead of file, `false` by default */\n directory?: boolean;\n\n /** Determines whether the file input state should be reset when the file dialog is opened, `false` by default */\n resetOnOpen?: boolean;\n\n /** Initial selected files */\n initialFiles?: FileList | File[];\n\n /** Called when files are selected */\n onChange?: (files: FileList | null) => void;\n\n /** Called when file dialog is canceled */\n onCancel?: () => void;\n}\n\nconst defaultOptions: UseFileDialogOptions = {\n multiple: true,\n accept: '*',\n};\n\nfunction getInitialFilesList(files: UseFileDialogOptions['initialFiles']): FileList | null {\n if (!files) {\n return null;\n }\n\n if (files instanceof FileList) {\n return files;\n }\n\n const result = new DataTransfer();\n for (const file of files) {\n result.items.add(file);\n }\n\n return result.files;\n}\n\nfunction createInput(options: UseFileDialogOptions) {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n\n if (options.accept) {\n input.accept = options.accept;\n }\n\n if (options.multiple) {\n input.multiple = options.multiple;\n }\n\n if (options.capture) {\n input.capture = options.capture;\n }\n\n if (options.directory) {\n input.webkitdirectory = options.directory;\n }\n\n input.style.display = 'none';\n return input;\n}\n\nexport interface UseFileDialogReturnValue {\n files: FileList | null;\n open: () => void;\n reset: () => void;\n}\n\nexport function useFileDialog(input: UseFileDialogOptions = {}): UseFileDialogReturnValue {\n const options: UseFileDialogOptions = { ...defaultOptions, ...input };\n const [files, setFiles] = useState<FileList | null>(getInitialFilesList(options.initialFiles));\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n const handleChange = useCallback(\n (event: Event) => {\n const target = event.target as HTMLInputElement;\n if (target?.files) {\n setFiles(target.files);\n options.onChange?.(target.files);\n }\n },\n [options.onChange]\n );\n\n const createAndSetupInput = useCallback(() => {\n inputRef.current?.remove();\n inputRef.current = createInput(options);\n\n if (inputRef.current) {\n inputRef.current.addEventListener('change', handleChange, { once: true });\n document.body.appendChild(inputRef.current);\n }\n }, [options, handleChange]);\n\n useIsomorphicEffect(() => {\n createAndSetupInput();\n return () => inputRef.current?.remove();\n }, []);\n\n const reset = useCallback(() => {\n setFiles(null);\n options.onChange?.(null);\n }, [options.onChange]);\n\n const open = useCallback(() => {\n if (options.resetOnOpen) {\n reset();\n }\n\n createAndSetupInput();\n inputRef.current?.click();\n }, [options.resetOnOpen, reset, createAndSetupInput]);\n\n return { files, open, reset };\n}\n\nexport namespace useFileDialog {\n export type Options = UseFileDialogOptions;\n export type ReturnValue = UseFileDialogReturnValue;\n}\n"],"mappings":";;;;AA6BA,MAAM,iBAAuC;CAC3C,UAAU;CACV,QAAQ;CACT;AAED,SAAS,oBAAoB,OAA8D;AACzF,KAAI,CAAC,MACH,QAAO;AAGT,KAAI,iBAAiB,SACnB,QAAO;CAGT,MAAM,SAAS,IAAI,cAAc;AACjC,MAAK,MAAM,QAAQ,MACjB,QAAO,MAAM,IAAI,KAAK;AAGxB,QAAO,OAAO;;AAGhB,SAAS,YAAY,SAA+B;AAClD,KAAI,OAAO,aAAa,YACtB,QAAO;CAGT,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,OAAO;AAEb,KAAI,QAAQ,OACV,OAAM,SAAS,QAAQ;AAGzB,KAAI,QAAQ,SACV,OAAM,WAAW,QAAQ;AAG3B,KAAI,QAAQ,QACV,OAAM,UAAU,QAAQ;AAG1B,KAAI,QAAQ,UACV,OAAM,kBAAkB,QAAQ;AAGlC,OAAM,MAAM,UAAU;AACtB,QAAO;;AAST,SAAgB,cAAc,QAA8B,EAAE,EAA4B;CACxF,MAAM,UAAgC;EAAE,GAAG;EAAgB,GAAG;EAAO;CACrE,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,UAAsC,oBAAoB,QAAQ,aAAa,CAAC;CAC9F,MAAM,YAAA,GAAA,MAAA,QAA2C,KAAK;CAEtD,MAAM,gBAAA,GAAA,MAAA,cACH,UAAiB;EAChB,MAAM,SAAS,MAAM;AACrB,MAAI,QAAQ,OAAO;AACjB,YAAS,OAAO,MAAM;AACtB,WAAQ,WAAW,OAAO,MAAM;;IAGpC,CAAC,QAAQ,SAAS,CACnB;CAED,MAAM,uBAAA,GAAA,MAAA,mBAAwC;AAC5C,WAAS,SAAS,QAAQ;AAC1B,WAAS,UAAU,YAAY,QAAQ;AAEvC,MAAI,SAAS,SAAS;AACpB,YAAS,QAAQ,iBAAiB,UAAU,cAAc,EAAE,MAAM,MAAM,CAAC;AACzE,YAAS,KAAK,YAAY,SAAS,QAAQ;;IAE5C,CAAC,SAAS,aAAa,CAAC;AAE3B,+BAAA,0BAA0B;AACxB,uBAAqB;AACrB,eAAa,SAAS,SAAS,QAAQ;IACtC,EAAE,CAAC;CAEN,MAAM,SAAA,GAAA,MAAA,mBAA0B;AAC9B,WAAS,KAAK;AACd,UAAQ,WAAW,KAAK;IACvB,CAAC,QAAQ,SAAS,CAAC;AAWtB,QAAO;EAAE;EAAO,OAAA,GAAA,MAAA,mBATe;AAC7B,OAAI,QAAQ,YACV,QAAO;AAGT,wBAAqB;AACrB,YAAS,SAAS,OAAO;KACxB;GAAC,QAAQ;GAAa;GAAO;GAAoB,CAAC;EAE/B;EAAO"}
|
|
1
|
+
{"version":3,"file":"use-file-dialog.cjs","names":[],"sources":["../../src/use-file-dialog/use-file-dialog.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\n\nexport interface UseFileDialogOptions {\n /** Determines whether multiple files are allowed, `true` by default */\n multiple?: boolean;\n\n /** `accept` attribute of the file input, '*' by default */\n accept?: string;\n\n /** `capture` attribute of the file input */\n capture?: string;\n\n /** Determines whether the user can pick a directory instead of file, `false` by default */\n directory?: boolean;\n\n /** Determines whether the file input state should be reset when the file dialog is opened, `false` by default */\n resetOnOpen?: boolean;\n\n /** Initial selected files */\n initialFiles?: FileList | File[];\n\n /** Called when files are selected */\n onChange?: (files: FileList | null) => void;\n\n /** Called when file dialog is canceled */\n onCancel?: () => void;\n}\n\nconst defaultOptions: UseFileDialogOptions = {\n multiple: true,\n accept: '*',\n};\n\nfunction getInitialFilesList(files: UseFileDialogOptions['initialFiles']): FileList | null {\n if (!files) {\n return null;\n }\n\n if (files instanceof FileList) {\n return files;\n }\n\n const result = new DataTransfer();\n for (const file of files) {\n result.items.add(file);\n }\n\n return result.files;\n}\n\nfunction createInput(options: UseFileDialogOptions) {\n if (typeof document === 'undefined') {\n return null;\n }\n\n const input = document.createElement('input');\n input.type = 'file';\n\n if (options.accept) {\n input.accept = options.accept;\n }\n\n if (options.multiple) {\n input.multiple = options.multiple;\n }\n\n if (options.capture) {\n input.capture = options.capture;\n }\n\n if (options.directory) {\n input.webkitdirectory = options.directory;\n }\n\n input.style.display = 'none';\n return input;\n}\n\nexport interface UseFileDialogReturnValue {\n files: FileList | null;\n open: () => void;\n reset: () => void;\n}\n\nexport function useFileDialog(input: UseFileDialogOptions = {}): UseFileDialogReturnValue {\n const options: UseFileDialogOptions = { ...defaultOptions, ...input };\n const [files, setFiles] = useState<FileList | null>(getInitialFilesList(options.initialFiles));\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n const handleChange = useCallback(\n (event: Event) => {\n const target = event.target as HTMLInputElement;\n if (target?.files) {\n setFiles(target.files);\n options.onChange?.(target.files);\n }\n },\n [options.onChange]\n );\n\n const createAndSetupInput = useCallback(() => {\n inputRef.current?.remove();\n inputRef.current = createInput(options);\n\n if (inputRef.current) {\n inputRef.current.addEventListener('change', handleChange, { once: true });\n if (options.onCancel) {\n inputRef.current.addEventListener('cancel', options.onCancel, { once: true });\n }\n document.body.appendChild(inputRef.current);\n }\n }, [options, handleChange]);\n\n useIsomorphicEffect(() => {\n createAndSetupInput();\n return () => inputRef.current?.remove();\n }, []);\n\n const reset = useCallback(() => {\n setFiles(null);\n options.onChange?.(null);\n }, [options.onChange]);\n\n const open = useCallback(() => {\n if (options.resetOnOpen) {\n reset();\n }\n\n createAndSetupInput();\n inputRef.current?.click();\n }, [options.resetOnOpen, reset, createAndSetupInput]);\n\n return { files, open, reset };\n}\n\nexport namespace useFileDialog {\n export type Options = UseFileDialogOptions;\n export type ReturnValue = UseFileDialogReturnValue;\n}\n"],"mappings":";;;;AA6BA,MAAM,iBAAuC;CAC3C,UAAU;CACV,QAAQ;CACT;AAED,SAAS,oBAAoB,OAA8D;AACzF,KAAI,CAAC,MACH,QAAO;AAGT,KAAI,iBAAiB,SACnB,QAAO;CAGT,MAAM,SAAS,IAAI,cAAc;AACjC,MAAK,MAAM,QAAQ,MACjB,QAAO,MAAM,IAAI,KAAK;AAGxB,QAAO,OAAO;;AAGhB,SAAS,YAAY,SAA+B;AAClD,KAAI,OAAO,aAAa,YACtB,QAAO;CAGT,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,OAAM,OAAO;AAEb,KAAI,QAAQ,OACV,OAAM,SAAS,QAAQ;AAGzB,KAAI,QAAQ,SACV,OAAM,WAAW,QAAQ;AAG3B,KAAI,QAAQ,QACV,OAAM,UAAU,QAAQ;AAG1B,KAAI,QAAQ,UACV,OAAM,kBAAkB,QAAQ;AAGlC,OAAM,MAAM,UAAU;AACtB,QAAO;;AAST,SAAgB,cAAc,QAA8B,EAAE,EAA4B;CACxF,MAAM,UAAgC;EAAE,GAAG;EAAgB,GAAG;EAAO;CACrE,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,UAAsC,oBAAoB,QAAQ,aAAa,CAAC;CAC9F,MAAM,YAAA,GAAA,MAAA,QAA2C,KAAK;CAEtD,MAAM,gBAAA,GAAA,MAAA,cACH,UAAiB;EAChB,MAAM,SAAS,MAAM;AACrB,MAAI,QAAQ,OAAO;AACjB,YAAS,OAAO,MAAM;AACtB,WAAQ,WAAW,OAAO,MAAM;;IAGpC,CAAC,QAAQ,SAAS,CACnB;CAED,MAAM,uBAAA,GAAA,MAAA,mBAAwC;AAC5C,WAAS,SAAS,QAAQ;AAC1B,WAAS,UAAU,YAAY,QAAQ;AAEvC,MAAI,SAAS,SAAS;AACpB,YAAS,QAAQ,iBAAiB,UAAU,cAAc,EAAE,MAAM,MAAM,CAAC;AACzE,OAAI,QAAQ,SACV,UAAS,QAAQ,iBAAiB,UAAU,QAAQ,UAAU,EAAE,MAAM,MAAM,CAAC;AAE/E,YAAS,KAAK,YAAY,SAAS,QAAQ;;IAE5C,CAAC,SAAS,aAAa,CAAC;AAE3B,+BAAA,0BAA0B;AACxB,uBAAqB;AACrB,eAAa,SAAS,SAAS,QAAQ;IACtC,EAAE,CAAC;CAEN,MAAM,SAAA,GAAA,MAAA,mBAA0B;AAC9B,WAAS,KAAK;AACd,UAAQ,WAAW,KAAK;IACvB,CAAC,QAAQ,SAAS,CAAC;AAWtB,QAAO;EAAE;EAAO,OAAA,GAAA,MAAA,mBATe;AAC7B,OAAI,QAAQ,YACV,QAAO;AAGT,wBAAqB;AACrB,YAAS,SAAS,OAAO;KACxB;GAAC,QAAQ;GAAa;GAAO;GAAoB,CAAC;EAE/B;EAAO"}
|
|
@@ -162,7 +162,39 @@ function useFloatingWindow(options = {}) {
|
|
|
162
162
|
}, [options.constrainToViewport, options.constrainOffset]);
|
|
163
163
|
return {
|
|
164
164
|
ref: assignRef,
|
|
165
|
-
setPosition:
|
|
165
|
+
setPosition: (0, react.useCallback)((position) => {
|
|
166
|
+
const el = ref.current;
|
|
167
|
+
if (!el) return;
|
|
168
|
+
const offset = options.constrainOffset ?? 0;
|
|
169
|
+
const rect = el.getBoundingClientRect();
|
|
170
|
+
let x;
|
|
171
|
+
let y;
|
|
172
|
+
if (position.left != null) x = position.left;
|
|
173
|
+
else if (position.right != null) x = window.innerWidth - rect.width - position.right;
|
|
174
|
+
if (position.top != null) y = position.top;
|
|
175
|
+
else if (position.bottom != null) y = window.innerHeight - rect.height - position.bottom;
|
|
176
|
+
x = x ?? pos.current.x;
|
|
177
|
+
y = y ?? pos.current.y;
|
|
178
|
+
if (options.constrainToViewport) {
|
|
179
|
+
const clamped = clampToViewport(x, y, el, offset);
|
|
180
|
+
x = clamped.x;
|
|
181
|
+
y = clamped.y;
|
|
182
|
+
}
|
|
183
|
+
pos.current = {
|
|
184
|
+
x,
|
|
185
|
+
y
|
|
186
|
+
};
|
|
187
|
+
el.style.left = `${x}px`;
|
|
188
|
+
el.style.top = `${y}px`;
|
|
189
|
+
options.onPositionChange?.({
|
|
190
|
+
x,
|
|
191
|
+
y
|
|
192
|
+
});
|
|
193
|
+
}, [
|
|
194
|
+
options.constrainToViewport,
|
|
195
|
+
options.constrainOffset,
|
|
196
|
+
options.onPositionChange
|
|
197
|
+
]),
|
|
166
198
|
isDragging
|
|
167
199
|
};
|
|
168
200
|
}
|
|
@@ -222,41 +254,6 @@ function clampToViewport(x, y, el, offset = 0) {
|
|
|
222
254
|
y: Math.min(Math.max(offset, y), maxY)
|
|
223
255
|
};
|
|
224
256
|
}
|
|
225
|
-
function createSetPosition(elRef, posRef, options) {
|
|
226
|
-
return (0, react.useCallback)((position) => {
|
|
227
|
-
const el = elRef.current;
|
|
228
|
-
if (!el) return;
|
|
229
|
-
const offset = options.constrainOffset ?? 0;
|
|
230
|
-
const rect = el.getBoundingClientRect();
|
|
231
|
-
let x;
|
|
232
|
-
let y;
|
|
233
|
-
if (position.left != null) x = position.left;
|
|
234
|
-
else if (position.right != null) x = window.innerWidth - rect.width - position.right;
|
|
235
|
-
if (position.top != null) y = position.top;
|
|
236
|
-
else if (position.bottom != null) y = window.innerHeight - rect.height - position.bottom;
|
|
237
|
-
x = x ?? posRef.current.x;
|
|
238
|
-
y = y ?? posRef.current.y;
|
|
239
|
-
if (options.constrainToViewport) {
|
|
240
|
-
const clamped = clampToViewport(x, y, el, offset);
|
|
241
|
-
x = clamped.x;
|
|
242
|
-
y = clamped.y;
|
|
243
|
-
}
|
|
244
|
-
posRef.current = {
|
|
245
|
-
x,
|
|
246
|
-
y
|
|
247
|
-
};
|
|
248
|
-
el.style.left = `${x}px`;
|
|
249
|
-
el.style.top = `${y}px`;
|
|
250
|
-
options.onPositionChange?.({
|
|
251
|
-
x,
|
|
252
|
-
y
|
|
253
|
-
});
|
|
254
|
-
}, [
|
|
255
|
-
options.constrainToViewport,
|
|
256
|
-
options.constrainOffset,
|
|
257
|
-
options.onPositionChange
|
|
258
|
-
]);
|
|
259
|
-
}
|
|
260
257
|
//#endregion
|
|
261
258
|
exports.useFloatingWindow = useFloatingWindow;
|
|
262
259
|
|
|
@@ -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\n/* oxlint-disable typescript/no-deprecated */\nimport { RefCallback, RefObject, 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 return {\n ref: assignRef,\n setPosition: createSetPosition(ref, pos, options),\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\nfunction createSetPosition(\n elRef: RefObject<HTMLElement | null>,\n posRef: React.RefObject<{ x: number; y: number }>,\n options: UseFloatingWindowOptions\n) {\n return useCallback(\n (position: FloatingWindowPositionConfig) => {\n const el = elRef.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 ?? posRef.current.x;\n y = y ?? posRef.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 posRef.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\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\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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"}
|
|
@@ -17,19 +17,22 @@ function useFocusTrap(active = true) {
|
|
|
17
17
|
};
|
|
18
18
|
const setRef = (0, react.useCallback)((node) => {
|
|
19
19
|
if (!active) return;
|
|
20
|
-
if (node === null)
|
|
20
|
+
if (node === null) {
|
|
21
|
+
ref.current = null;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
21
24
|
if (ref.current === node) return;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ref.current = node;
|
|
28
|
-
} else ref.current = null;
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
if (node.getRootNode()) focusNode(node);
|
|
27
|
+
else if (process.env.NODE_ENV === "development") console.warn("[@mantine/hooks/use-focus-trap] Ref node is not part of the dom", node);
|
|
28
|
+
});
|
|
29
|
+
ref.current = node;
|
|
29
30
|
}, [active]);
|
|
30
31
|
(0, react.useEffect)(() => {
|
|
31
32
|
if (!active) return;
|
|
32
|
-
ref.current
|
|
33
|
+
if (ref.current) setTimeout(() => {
|
|
34
|
+
if (ref.current) focusNode(ref.current);
|
|
35
|
+
});
|
|
33
36
|
const handleKeyDown = (event) => {
|
|
34
37
|
if (event.key === "Tab" && ref.current) require_scope_tab.scopeTab(ref.current, event);
|
|
35
38
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-focus-trap.cjs","names":["FOCUS_SELECTOR","tabbable","focusable"],"sources":["../../src/use-focus-trap/use-focus-trap.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { scopeTab } from './scope-tab';\nimport { FOCUS_SELECTOR, focusable, tabbable } from './tabbable';\n\nexport function useFocusTrap(active = true): React.RefCallback<HTMLElement | null> {\n const ref = useRef<HTMLElement>(null);\n\n const focusNode = (node: HTMLElement) => {\n let focusElement: HTMLElement | null = node.querySelector('[data-autofocus]');\n\n if (!focusElement) {\n const children = Array.from<HTMLElement>(node.querySelectorAll(FOCUS_SELECTOR));\n focusElement = children.find(tabbable) || children.find(focusable) || null;\n if (!focusElement && focusable(node)) {\n focusElement = node;\n }\n }\n\n if (focusElement) {\n focusElement.focus({ preventScroll: true });\n } else if (process.env.NODE_ENV === 'development') {\n // oxlint-disable-next-line no-console\n console.warn(\n '[@mantine/hooks/use-focus-trap] Failed to find focusable element within provided node',\n node\n );\n }\n };\n\n const setRef = useCallback(\n (node: HTMLElement | null) => {\n if (!active) {\n return;\n }\n\n if (node === null) {\n return;\n }\n\n if (ref.current === node) {\n return;\n }\n\n
|
|
1
|
+
{"version":3,"file":"use-focus-trap.cjs","names":["FOCUS_SELECTOR","tabbable","focusable"],"sources":["../../src/use-focus-trap/use-focus-trap.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { scopeTab } from './scope-tab';\nimport { FOCUS_SELECTOR, focusable, tabbable } from './tabbable';\n\nexport function useFocusTrap(active = true): React.RefCallback<HTMLElement | null> {\n const ref = useRef<HTMLElement>(null);\n\n const focusNode = (node: HTMLElement) => {\n let focusElement: HTMLElement | null = node.querySelector('[data-autofocus]');\n\n if (!focusElement) {\n const children = Array.from<HTMLElement>(node.querySelectorAll(FOCUS_SELECTOR));\n focusElement = children.find(tabbable) || children.find(focusable) || null;\n if (!focusElement && focusable(node)) {\n focusElement = node;\n }\n }\n\n if (focusElement) {\n focusElement.focus({ preventScroll: true });\n } else if (process.env.NODE_ENV === 'development') {\n // oxlint-disable-next-line no-console\n console.warn(\n '[@mantine/hooks/use-focus-trap] Failed to find focusable element within provided node',\n node\n );\n }\n };\n\n const setRef = useCallback(\n (node: HTMLElement | null) => {\n if (!active) {\n return;\n }\n\n if (node === null) {\n ref.current = null;\n return;\n }\n\n if (ref.current === node) {\n return;\n }\n\n // Delay processing the HTML node by a frame. This ensures focus is assigned correctly.\n setTimeout(() => {\n if (node.getRootNode()) {\n focusNode(node);\n } else if (process.env.NODE_ENV === 'development') {\n // oxlint-disable-next-line no-console\n console.warn('[@mantine/hooks/use-focus-trap] Ref node is not part of the dom', node);\n }\n });\n\n ref.current = node;\n },\n [active]\n );\n\n useEffect(() => {\n if (!active) {\n return undefined;\n }\n\n if (ref.current) {\n setTimeout(() => {\n if (ref.current) {\n focusNode(ref.current);\n }\n });\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Tab' && ref.current) {\n scopeTab(ref.current, event);\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [active]);\n\n return setRef;\n}\n"],"mappings":";;;;;AAIA,SAAgB,aAAa,SAAS,MAA6C;CACjF,MAAM,OAAA,GAAA,MAAA,QAA0B,KAAK;CAErC,MAAM,aAAa,SAAsB;EACvC,IAAI,eAAmC,KAAK,cAAc,mBAAmB;AAE7E,MAAI,CAAC,cAAc;GACjB,MAAM,WAAW,MAAM,KAAkB,KAAK,iBAAiBA,iBAAAA,eAAe,CAAC;AAC/E,kBAAe,SAAS,KAAKC,iBAAAA,SAAS,IAAI,SAAS,KAAKC,iBAAAA,UAAU,IAAI;AACtE,OAAI,CAAC,gBAAgBA,iBAAAA,UAAU,KAAK,CAClC,gBAAe;;AAInB,MAAI,aACF,cAAa,MAAM,EAAE,eAAe,MAAM,CAAC;WAClC,QAAQ,IAAI,aAAa,cAElC,SAAQ,KACN,yFACA,KACD;;CAIL,MAAM,UAAA,GAAA,MAAA,cACH,SAA6B;AAC5B,MAAI,CAAC,OACH;AAGF,MAAI,SAAS,MAAM;AACjB,OAAI,UAAU;AACd;;AAGF,MAAI,IAAI,YAAY,KAClB;AAIF,mBAAiB;AACf,OAAI,KAAK,aAAa,CACpB,WAAU,KAAK;YACN,QAAQ,IAAI,aAAa,cAElC,SAAQ,KAAK,mEAAmE,KAAK;IAEvF;AAEF,MAAI,UAAU;IAEhB,CAAC,OAAO,CACT;AAED,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,CAAC,OACH;AAGF,MAAI,IAAI,QACN,kBAAiB;AACf,OAAI,IAAI,QACN,WAAU,IAAI,QAAQ;IAExB;EAGJ,MAAM,iBAAiB,UAAyB;AAC9C,OAAI,MAAM,QAAQ,SAAS,IAAI,QAC7B,mBAAA,SAAS,IAAI,SAAS,MAAM;;AAIhC,WAAS,iBAAiB,WAAW,cAAc;AACnD,eAAa,SAAS,oBAAoB,WAAW,cAAc;IAClE,CAAC,OAAO,CAAC;AAEZ,QAAO"}
|
|
@@ -23,11 +23,13 @@ const prefixes = [
|
|
|
23
23
|
"moz",
|
|
24
24
|
"ms"
|
|
25
25
|
];
|
|
26
|
-
function addEvents(element,
|
|
26
|
+
function addEvents(element, events) {
|
|
27
|
+
const { onFullScreen, onError } = events;
|
|
27
28
|
prefixes.forEach((prefix) => {
|
|
28
29
|
element.addEventListener(`${prefix}fullscreenchange`, onFullScreen);
|
|
29
30
|
element.addEventListener(`${prefix}fullscreenerror`, onError);
|
|
30
31
|
});
|
|
32
|
+
return () => removeEvents(element, events);
|
|
31
33
|
}
|
|
32
34
|
function removeEvents(element, { onFullScreen, onError }) {
|
|
33
35
|
prefixes.forEach((prefix) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-fullscreen.cjs","names":[],"sources":["../../src/use-fullscreen/use-fullscreen.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nfunction getFullscreenElement(): HTMLElement | null {\n const _document = window.document as any;\n\n const fullscreenElement =\n _document.fullscreenElement ||\n _document.webkitFullscreenElement ||\n _document.mozFullScreenElement ||\n _document.msFullscreenElement;\n\n return fullscreenElement;\n}\n\nfunction exitFullscreen() {\n const _document = window.document as any;\n\n if (typeof _document.exitFullscreen === 'function') {\n return _document.exitFullscreen();\n }\n if (typeof _document.msExitFullscreen === 'function') {\n return _document.msExitFullscreen();\n }\n if (typeof _document.webkitExitFullscreen === 'function') {\n return _document.webkitExitFullscreen();\n }\n if (typeof _document.mozCancelFullScreen === 'function') {\n return _document.mozCancelFullScreen();\n }\n\n return null;\n}\n\nfunction enterFullScreen(element: HTMLElement) {\n const _element = element as any;\n\n return (\n _element.requestFullscreen?.() ||\n _element.msRequestFullscreen?.() ||\n _element.webkitEnterFullscreen?.() ||\n _element.webkitRequestFullscreen?.() ||\n _element.mozRequestFullscreen?.()\n );\n}\n\nconst prefixes = ['', 'webkit', 'moz', 'ms'];\n\ninterface FullscreenEvents {\n onFullScreen: (event: Event) => void;\n onError: (event: Event) => void;\n}\n\nfunction addEvents(element: HTMLElement, { onFullScreen, onError }
|
|
1
|
+
{"version":3,"file":"use-fullscreen.cjs","names":[],"sources":["../../src/use-fullscreen/use-fullscreen.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nfunction getFullscreenElement(): HTMLElement | null {\n const _document = window.document as any;\n\n const fullscreenElement =\n _document.fullscreenElement ||\n _document.webkitFullscreenElement ||\n _document.mozFullScreenElement ||\n _document.msFullscreenElement;\n\n return fullscreenElement;\n}\n\nfunction exitFullscreen() {\n const _document = window.document as any;\n\n if (typeof _document.exitFullscreen === 'function') {\n return _document.exitFullscreen();\n }\n if (typeof _document.msExitFullscreen === 'function') {\n return _document.msExitFullscreen();\n }\n if (typeof _document.webkitExitFullscreen === 'function') {\n return _document.webkitExitFullscreen();\n }\n if (typeof _document.mozCancelFullScreen === 'function') {\n return _document.mozCancelFullScreen();\n }\n\n return null;\n}\n\nfunction enterFullScreen(element: HTMLElement) {\n const _element = element as any;\n\n return (\n _element.requestFullscreen?.() ||\n _element.msRequestFullscreen?.() ||\n _element.webkitEnterFullscreen?.() ||\n _element.webkitRequestFullscreen?.() ||\n _element.mozRequestFullscreen?.()\n );\n}\n\nconst prefixes = ['', 'webkit', 'moz', 'ms'];\n\ninterface FullscreenEvents {\n onFullScreen: (event: Event) => void;\n onError: (event: Event) => void;\n}\n\nfunction addEvents(element: HTMLElement, events: FullscreenEvents) {\n const { onFullScreen, onError } = events;\n prefixes.forEach((prefix) => {\n element.addEventListener(`${prefix}fullscreenchange`, onFullScreen);\n element.addEventListener(`${prefix}fullscreenerror`, onError);\n });\n\n return () => removeEvents(element, events);\n}\n\nfunction removeEvents(element: HTMLElement, { onFullScreen, onError }: FullscreenEvents) {\n prefixes.forEach((prefix) => {\n element.removeEventListener(`${prefix}fullscreenchange`, onFullScreen);\n element.removeEventListener(`${prefix}fullscreenerror`, onError);\n });\n}\n\nexport interface UseFullscreenElementReturnValue<T extends HTMLElement = any> {\n ref: React.RefCallback<T | null>;\n toggle: () => Promise<void>;\n fullscreen: boolean;\n}\n\nexport function useFullscreenElement<\n T extends HTMLElement = any,\n>(): UseFullscreenElementReturnValue<T> {\n const [fullscreen, setFullscreen] = useState<boolean>(false);\n const refElement = useRef<T | null>(null);\n const prevNodeRef = useRef<T | null>(null);\n\n const handleFullscreenChange = useCallback(() => {\n setFullscreen(refElement.current === getFullscreenElement());\n }, []);\n\n const handleFullscreenError = useCallback(() => {\n setFullscreen(false);\n }, []);\n\n const toggle = useCallback(async () => {\n if (!getFullscreenElement() && refElement.current) {\n await enterFullScreen(refElement.current);\n } else {\n await exitFullscreen();\n }\n }, []);\n\n const refCallback: React.RefCallback<T | null> = useCallback((node) => {\n if (prevNodeRef.current && prevNodeRef.current !== node) {\n removeEvents(prevNodeRef.current, {\n onFullScreen: handleFullscreenChange,\n onError: handleFullscreenError,\n });\n }\n\n if (node) {\n addEvents(node, {\n onFullScreen: handleFullscreenChange,\n onError: handleFullscreenError,\n });\n }\n\n refElement.current = node;\n prevNodeRef.current = node;\n }, []);\n\n return { ref: refCallback, toggle, fullscreen };\n}\n\nexport interface UseFullscreenDocumentReturnValue {\n toggle: () => Promise<void>;\n fullscreen: boolean;\n}\n\nexport function useFullscreenDocument(): UseFullscreenDocumentReturnValue {\n const [fullscreen, setFullscreen] = useState<boolean>(false);\n\n const handleFullscreenChange = useCallback(() => {\n setFullscreen(getFullscreenElement() === window.document.documentElement);\n }, []);\n\n const handleFullscreenError = useCallback(() => {\n setFullscreen(false);\n }, []);\n\n const toggle = useCallback(async () => {\n if (!getFullscreenElement()) {\n await enterFullScreen(window.document.documentElement);\n } else {\n await exitFullscreen();\n }\n }, []);\n\n useEffect(() => {\n return addEvents(window.document.documentElement, {\n onFullScreen: handleFullscreenChange,\n onError: handleFullscreenError,\n });\n }, []);\n\n return { toggle, fullscreen };\n}\n"],"mappings":"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"}
|
|
@@ -32,8 +32,11 @@ function useHeadroom({ fixedAt = 0, scrollDistance = 100, onPin, onFix, onReleas
|
|
|
32
32
|
fixedAt,
|
|
33
33
|
isScrollingUp
|
|
34
34
|
]);
|
|
35
|
+
const wasFixedRef = (0, react.useRef)(false);
|
|
35
36
|
require_use_isomorphic_effect.useIsomorphicEffect(() => {
|
|
36
|
-
|
|
37
|
+
const currentlyInFixedZone = isFixed(scrollPosition, fixedAt);
|
|
38
|
+
if (currentlyInFixedZone && !wasFixedRef.current) onFixEvent();
|
|
39
|
+
wasFixedRef.current = currentlyInFixedZone;
|
|
37
40
|
}, [scrollPosition, fixedAt]);
|
|
38
41
|
const currentlyFixed = isFixed(scrollPosition, fixedAt);
|
|
39
42
|
const prevIsFixedRef = (0, react.useRef)(currentlyFixed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-headroom.cjs","names":["useScrollDirection","useWindowScroll"],"sources":["../../src/use-headroom/use-headroom.ts"],"sourcesContent":["import { useEffectEvent, useRef } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\nimport { useScrollDirection } from '../use-scroll-direction/use-scroll-direction';\nimport { useWindowScroll } from '../use-window-scroll/use-window-scroll';\n\nexport { useScrollDirection } from '../use-scroll-direction/use-scroll-direction';\n\nexport const isFixed = (current: number, fixedAt: number) => current <= fixedAt;\nexport const isPinned = (current: number, previous: number) => current <= previous;\nexport const isReleased = (current: number, previous: number, fixedAt: number) =>\n !isPinned(current, previous) && !isFixed(current, fixedAt);\n\nexport const isPinnedOrReleased = (\n current: number,\n fixedAt: number,\n isCurrentlyPinnedRef: React.RefObject<boolean>,\n isScrollingUp: boolean,\n onPin?: () => void,\n onRelease?: () => void\n) => {\n const isInFixedPosition = isFixed(current, fixedAt);\n if (isInFixedPosition && !isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = true;\n onPin?.();\n } else if (!isInFixedPosition && isScrollingUp && !isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = true;\n onPin?.();\n } else if (!isInFixedPosition && !isScrollingUp && isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = false;\n onRelease?.();\n }\n};\n\nexport interface UseHeadroomInput {\n /** Number in px at which element should be fixed */\n fixedAt?: number;\n\n /** Number of px to scroll to fully reveal or hide the element, 100 by default */\n scrollDistance?: number;\n\n /** Called when element is pinned */\n onPin?: () => void;\n\n /** Called when element is at fixed position */\n onFix?: () => void;\n\n /** Called when element is unpinned */\n onRelease?: () => void;\n}\n\nexport interface UseHeadroomReturnValue {\n /** True when the element is at least partially visible */\n pinned: boolean;\n\n /** Reveal progress: 0 = fully hidden, 1 = fully visible */\n scrollProgress: number;\n}\n\nexport function useHeadroom({\n fixedAt = 0,\n scrollDistance = 100,\n onPin,\n onFix,\n onRelease,\n}: UseHeadroomInput = {}): UseHeadroomReturnValue {\n const isCurrentlyPinnedRef = useRef(false);\n const scrollDirection = useScrollDirection();\n const isScrollingUp = scrollDirection === 'up';\n const [{ y: scrollPosition }] = useWindowScroll();\n\n const onPinEvent = useEffectEvent(() => onPin?.());\n const onReleaseEvent = useEffectEvent(() => onRelease?.());\n const onFixEvent = useEffectEvent(() => onFix?.());\n\n useIsomorphicEffect(() => {\n isPinnedOrReleased(\n scrollPosition,\n fixedAt,\n isCurrentlyPinnedRef,\n isScrollingUp,\n onPinEvent,\n onReleaseEvent\n );\n }, [scrollPosition, fixedAt, isScrollingUp]);\n\n useIsomorphicEffect(() => {\n
|
|
1
|
+
{"version":3,"file":"use-headroom.cjs","names":["useScrollDirection","useWindowScroll"],"sources":["../../src/use-headroom/use-headroom.ts"],"sourcesContent":["import { useEffectEvent, useRef } from 'react';\nimport { useIsomorphicEffect } from '../use-isomorphic-effect/use-isomorphic-effect';\nimport { useScrollDirection } from '../use-scroll-direction/use-scroll-direction';\nimport { useWindowScroll } from '../use-window-scroll/use-window-scroll';\n\nexport { useScrollDirection } from '../use-scroll-direction/use-scroll-direction';\n\nexport const isFixed = (current: number, fixedAt: number) => current <= fixedAt;\nexport const isPinned = (current: number, previous: number) => current <= previous;\nexport const isReleased = (current: number, previous: number, fixedAt: number) =>\n !isPinned(current, previous) && !isFixed(current, fixedAt);\n\nexport const isPinnedOrReleased = (\n current: number,\n fixedAt: number,\n isCurrentlyPinnedRef: React.RefObject<boolean>,\n isScrollingUp: boolean,\n onPin?: () => void,\n onRelease?: () => void\n) => {\n const isInFixedPosition = isFixed(current, fixedAt);\n if (isInFixedPosition && !isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = true;\n onPin?.();\n } else if (!isInFixedPosition && isScrollingUp && !isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = true;\n onPin?.();\n } else if (!isInFixedPosition && !isScrollingUp && isCurrentlyPinnedRef.current) {\n isCurrentlyPinnedRef.current = false;\n onRelease?.();\n }\n};\n\nexport interface UseHeadroomInput {\n /** Number in px at which element should be fixed */\n fixedAt?: number;\n\n /** Number of px to scroll to fully reveal or hide the element, 100 by default */\n scrollDistance?: number;\n\n /** Called when element is pinned */\n onPin?: () => void;\n\n /** Called when element is at fixed position */\n onFix?: () => void;\n\n /** Called when element is unpinned */\n onRelease?: () => void;\n}\n\nexport interface UseHeadroomReturnValue {\n /** True when the element is at least partially visible */\n pinned: boolean;\n\n /** Reveal progress: 0 = fully hidden, 1 = fully visible */\n scrollProgress: number;\n}\n\nexport function useHeadroom({\n fixedAt = 0,\n scrollDistance = 100,\n onPin,\n onFix,\n onRelease,\n}: UseHeadroomInput = {}): UseHeadroomReturnValue {\n const isCurrentlyPinnedRef = useRef(false);\n const scrollDirection = useScrollDirection();\n const isScrollingUp = scrollDirection === 'up';\n const [{ y: scrollPosition }] = useWindowScroll();\n\n const onPinEvent = useEffectEvent(() => onPin?.());\n const onReleaseEvent = useEffectEvent(() => onRelease?.());\n const onFixEvent = useEffectEvent(() => onFix?.());\n\n useIsomorphicEffect(() => {\n isPinnedOrReleased(\n scrollPosition,\n fixedAt,\n isCurrentlyPinnedRef,\n isScrollingUp,\n onPinEvent,\n onReleaseEvent\n );\n }, [scrollPosition, fixedAt, isScrollingUp]);\n\n const wasFixedRef = useRef(false);\n\n useIsomorphicEffect(() => {\n const currentlyInFixedZone = isFixed(scrollPosition, fixedAt);\n if (currentlyInFixedZone && !wasFixedRef.current) {\n onFixEvent();\n }\n wasFixedRef.current = currentlyInFixedZone;\n }, [scrollPosition, fixedAt]);\n\n // Refs for scroll-progress tracking. Mutated during render (safe for refs).\n const currentlyFixed = isFixed(scrollPosition, fixedAt);\n const prevIsFixedRef = useRef(currentlyFixed);\n const directionChangeScrollYRef = useRef(scrollPosition);\n const progressAtDirectionChangeRef = useRef(currentlyFixed ? 1 : 0);\n const prevIsScrollingUpRef = useRef(isScrollingUp);\n\n // Detect fixed-zone transitions first. When leaving the fixed zone the baseline\n // is anchored at fixedAt (not the current scroll position) so the delta is measured\n // from where the element was last fully visible, regardless of how scroll position\n // was initialised on the first render.\n if (prevIsFixedRef.current !== currentlyFixed) {\n prevIsFixedRef.current = currentlyFixed;\n\n if (!currentlyFixed) {\n directionChangeScrollYRef.current = fixedAt;\n progressAtDirectionChangeRef.current = 1;\n } else {\n directionChangeScrollYRef.current = scrollPosition;\n progressAtDirectionChangeRef.current = 1;\n }\n\n prevIsScrollingUpRef.current = isScrollingUp;\n }\n\n // When scroll direction changes outside the fixed zone, save the current progress\n // so the next direction accumulates from that point (handles partial reveals).\n if (!currentlyFixed && prevIsScrollingUpRef.current !== isScrollingUp) {\n const transitionDelta = Math.abs(scrollPosition - directionChangeScrollYRef.current);\n const transitionProgress = prevIsScrollingUpRef.current\n ? Math.min(progressAtDirectionChangeRef.current + transitionDelta / scrollDistance, 1)\n : Math.max(progressAtDirectionChangeRef.current - transitionDelta / scrollDistance, 0);\n\n prevIsScrollingUpRef.current = isScrollingUp;\n directionChangeScrollYRef.current = scrollPosition;\n progressAtDirectionChangeRef.current = transitionProgress;\n }\n\n let scrollProgress: number;\n\n if (currentlyFixed) {\n scrollProgress = 1;\n } else {\n const scrollDelta = Math.abs(scrollPosition - directionChangeScrollYRef.current);\n\n if (isScrollingUp) {\n scrollProgress = Math.min(\n progressAtDirectionChangeRef.current + scrollDelta / scrollDistance,\n 1\n );\n } else {\n scrollProgress = Math.max(\n progressAtDirectionChangeRef.current - scrollDelta / scrollDistance,\n 0\n );\n }\n }\n\n return { pinned: scrollProgress > 0, scrollProgress };\n}\n\nexport namespace useHeadroom {\n export type Input = UseHeadroomInput;\n export type ReturnValue = UseHeadroomReturnValue;\n}\n"],"mappings":";;;;;;AAOA,MAAa,WAAW,SAAiB,YAAoB,WAAW;AAKxE,MAAa,sBACX,SACA,SACA,sBACA,eACA,OACA,cACG;CACH,MAAM,oBAAoB,QAAQ,SAAS,QAAQ;AACnD,KAAI,qBAAqB,CAAC,qBAAqB,SAAS;AACtD,uBAAqB,UAAU;AAC/B,WAAS;YACA,CAAC,qBAAqB,iBAAiB,CAAC,qBAAqB,SAAS;AAC/E,uBAAqB,UAAU;AAC/B,WAAS;YACA,CAAC,qBAAqB,CAAC,iBAAiB,qBAAqB,SAAS;AAC/E,uBAAqB,UAAU;AAC/B,eAAa;;;AA6BjB,SAAgB,YAAY,EAC1B,UAAU,GACV,iBAAiB,KACjB,OACA,OACA,cACoB,EAAE,EAA0B;CAChD,MAAM,wBAAA,GAAA,MAAA,QAA8B,MAAM;CAE1C,MAAM,gBADkBA,6BAAAA,oBAAoB,KACF;CAC1C,MAAM,CAAC,EAAE,GAAG,oBAAoBC,0BAAAA,iBAAiB;CAEjD,MAAM,cAAA,GAAA,MAAA,sBAAkC,SAAS,CAAC;CAClD,MAAM,kBAAA,GAAA,MAAA,sBAAsC,aAAa,CAAC;CAC1D,MAAM,cAAA,GAAA,MAAA,sBAAkC,SAAS,CAAC;AAElD,+BAAA,0BAA0B;AACxB,qBACE,gBACA,SACA,sBACA,eACA,YACA,eACD;IACA;EAAC;EAAgB;EAAS;EAAc,CAAC;CAE5C,MAAM,eAAA,GAAA,MAAA,QAAqB,MAAM;AAEjC,+BAAA,0BAA0B;EACxB,MAAM,uBAAuB,QAAQ,gBAAgB,QAAQ;AAC7D,MAAI,wBAAwB,CAAC,YAAY,QACvC,aAAY;AAEd,cAAY,UAAU;IACrB,CAAC,gBAAgB,QAAQ,CAAC;CAG7B,MAAM,iBAAiB,QAAQ,gBAAgB,QAAQ;CACvD,MAAM,kBAAA,GAAA,MAAA,QAAwB,eAAe;CAC7C,MAAM,6BAAA,GAAA,MAAA,QAAmC,eAAe;CACxD,MAAM,gCAAA,GAAA,MAAA,QAAsC,iBAAiB,IAAI,EAAE;CACnE,MAAM,wBAAA,GAAA,MAAA,QAA8B,cAAc;AAMlD,KAAI,eAAe,YAAY,gBAAgB;AAC7C,iBAAe,UAAU;AAEzB,MAAI,CAAC,gBAAgB;AACnB,6BAA0B,UAAU;AACpC,gCAA6B,UAAU;SAClC;AACL,6BAA0B,UAAU;AACpC,gCAA6B,UAAU;;AAGzC,uBAAqB,UAAU;;AAKjC,KAAI,CAAC,kBAAkB,qBAAqB,YAAY,eAAe;EACrE,MAAM,kBAAkB,KAAK,IAAI,iBAAiB,0BAA0B,QAAQ;EACpF,MAAM,qBAAqB,qBAAqB,UAC5C,KAAK,IAAI,6BAA6B,UAAU,kBAAkB,gBAAgB,EAAE,GACpF,KAAK,IAAI,6BAA6B,UAAU,kBAAkB,gBAAgB,EAAE;AAExF,uBAAqB,UAAU;AAC/B,4BAA0B,UAAU;AACpC,+BAA6B,UAAU;;CAGzC,IAAI;AAEJ,KAAI,eACF,kBAAiB;MACZ;EACL,MAAM,cAAc,KAAK,IAAI,iBAAiB,0BAA0B,QAAQ;AAEhF,MAAI,cACF,kBAAiB,KAAK,IACpB,6BAA6B,UAAU,cAAc,gBACrD,EACD;MAED,kBAAiB,KAAK,IACpB,6BAA6B,UAAU,cAAc,gBACrD,EACD;;AAIL,QAAO;EAAE,QAAQ,iBAAiB;EAAG;EAAgB"}
|
|
@@ -34,8 +34,7 @@ function parseHotkey(hotkey) {
|
|
|
34
34
|
ctrl: keys.includes("ctrl"),
|
|
35
35
|
meta: keys.includes("meta"),
|
|
36
36
|
mod: keys.includes("mod"),
|
|
37
|
-
shift: keys.includes("shift")
|
|
38
|
-
plus: keys.includes("[plus]")
|
|
37
|
+
shift: keys.includes("shift")
|
|
39
38
|
};
|
|
40
39
|
const reservedKeys = [
|
|
41
40
|
"alt",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-hotkey.cjs","names":[],"sources":["../../src/use-hotkeys/parse-hotkey.ts"],"sourcesContent":["export
|
|
1
|
+
{"version":3,"file":"parse-hotkey.cjs","names":[],"sources":["../../src/use-hotkeys/parse-hotkey.ts"],"sourcesContent":["export interface KeyboardModifiers {\n alt: boolean;\n ctrl: boolean;\n meta: boolean;\n mod: boolean;\n shift: boolean;\n}\n\nexport interface Hotkey extends KeyboardModifiers {\n key?: string;\n}\n\ntype CheckHotkeyMatch = (event: KeyboardEvent) => boolean;\n\nconst keyNameMap: Record<string, string> = {\n ' ': 'space',\n ArrowLeft: 'arrowleft',\n ArrowRight: 'arrowright',\n ArrowUp: 'arrowup',\n ArrowDown: 'arrowdown',\n Escape: 'escape',\n Esc: 'escape',\n esc: 'escape',\n Enter: 'enter',\n Tab: 'tab',\n Backspace: 'backspace',\n Delete: 'delete',\n Insert: 'insert',\n Home: 'home',\n End: 'end',\n PageUp: 'pageup',\n PageDown: 'pagedown',\n '+': 'plus',\n '-': 'minus',\n '*': 'asterisk',\n '/': 'slash',\n};\n\nfunction normalizeKey(key: string): string {\n const lowerKey = key.replace('Key', '').toLowerCase();\n return keyNameMap[key] || lowerKey;\n}\n\nexport function parseHotkey(hotkey: string): Hotkey {\n const keys = hotkey\n .toLowerCase()\n .split('+')\n .map((part) => part.trim());\n\n const modifiers: KeyboardModifiers = {\n alt: keys.includes('alt'),\n ctrl: keys.includes('ctrl'),\n meta: keys.includes('meta'),\n mod: keys.includes('mod'),\n shift: keys.includes('shift'),\n };\n\n const reservedKeys = ['alt', 'ctrl', 'meta', 'shift', 'mod'];\n\n const freeKey = keys.find((key) => !reservedKeys.includes(key));\n\n return {\n ...modifiers,\n key: freeKey === '[plus]' ? '+' : freeKey,\n };\n}\n\nfunction isExactHotkey(hotkey: Hotkey, event: KeyboardEvent, usePhysicalKeys?: boolean): boolean {\n const { alt, ctrl, meta, mod, shift, key } = hotkey;\n const { altKey, ctrlKey, metaKey, shiftKey, key: pressedKey, code: pressedCode } = event;\n\n if (alt !== altKey) {\n return false;\n }\n\n if (mod) {\n if (!ctrlKey && !metaKey) {\n return false;\n }\n } else {\n if (ctrl !== ctrlKey) {\n return false;\n }\n if (meta !== metaKey) {\n return false;\n }\n }\n if (shift !== shiftKey) {\n return false;\n }\n\n if (\n key &&\n (usePhysicalKeys\n ? normalizeKey(pressedCode) === normalizeKey(key)\n : normalizeKey(pressedKey ?? pressedCode) === normalizeKey(key))\n ) {\n return true;\n }\n\n return false;\n}\n\nexport function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch {\n return (event) => isExactHotkey(parseHotkey(hotkey), event, usePhysicalKeys);\n}\n\nexport interface HotkeyItemOptions {\n preventDefault?: boolean;\n usePhysicalKeys?: boolean;\n}\n\ntype HotkeyItem = [string, (event: any) => void, HotkeyItemOptions?];\n\nexport function getHotkeyHandler(hotkeys: HotkeyItem[]) {\n return (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => {\n const _event = 'nativeEvent' in event ? event.nativeEvent : event;\n hotkeys.forEach(\n ([hotkey, handler, options = { preventDefault: true, usePhysicalKeys: false }]) => {\n if (getHotkeyMatcher(hotkey, options.usePhysicalKeys)(_event)) {\n if (options.preventDefault) {\n event.preventDefault();\n }\n\n handler(_event);\n }\n }\n );\n };\n}\n"],"mappings":";;AAcA,MAAM,aAAqC;CACzC,KAAK;CACL,WAAW;CACX,YAAY;CACZ,SAAS;CACT,WAAW;CACX,QAAQ;CACR,KAAK;CACL,KAAK;CACL,OAAO;CACP,KAAK;CACL,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,MAAM;CACN,KAAK;CACL,QAAQ;CACR,UAAU;CACV,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACN;AAED,SAAS,aAAa,KAAqB;CACzC,MAAM,WAAW,IAAI,QAAQ,OAAO,GAAG,CAAC,aAAa;AACrD,QAAO,WAAW,QAAQ;;AAG5B,SAAgB,YAAY,QAAwB;CAClD,MAAM,OAAO,OACV,aAAa,CACb,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC;CAE7B,MAAM,YAA+B;EACnC,KAAK,KAAK,SAAS,MAAM;EACzB,MAAM,KAAK,SAAS,OAAO;EAC3B,MAAM,KAAK,SAAS,OAAO;EAC3B,KAAK,KAAK,SAAS,MAAM;EACzB,OAAO,KAAK,SAAS,QAAQ;EAC9B;CAED,MAAM,eAAe;EAAC;EAAO;EAAQ;EAAQ;EAAS;EAAM;CAE5D,MAAM,UAAU,KAAK,MAAM,QAAQ,CAAC,aAAa,SAAS,IAAI,CAAC;AAE/D,QAAO;EACL,GAAG;EACH,KAAK,YAAY,WAAW,MAAM;EACnC;;AAGH,SAAS,cAAc,QAAgB,OAAsB,iBAAoC;CAC/F,MAAM,EAAE,KAAK,MAAM,MAAM,KAAK,OAAO,QAAQ;CAC7C,MAAM,EAAE,QAAQ,SAAS,SAAS,UAAU,KAAK,YAAY,MAAM,gBAAgB;AAEnF,KAAI,QAAQ,OACV,QAAO;AAGT,KAAI;MACE,CAAC,WAAW,CAAC,QACf,QAAO;QAEJ;AACL,MAAI,SAAS,QACX,QAAO;AAET,MAAI,SAAS,QACX,QAAO;;AAGX,KAAI,UAAU,SACZ,QAAO;AAGT,KACE,QACC,kBACG,aAAa,YAAY,KAAK,aAAa,IAAI,GAC/C,aAAa,cAAc,YAAY,KAAK,aAAa,IAAI,EAEjE,QAAO;AAGT,QAAO;;AAGT,SAAgB,iBAAiB,QAAgB,iBAA6C;AAC5F,SAAQ,UAAU,cAAc,YAAY,OAAO,EAAE,OAAO,gBAAgB;;AAU9E,SAAgB,iBAAiB,SAAuB;AACtD,SAAQ,UAA4D;EAClE,MAAM,SAAS,iBAAiB,QAAQ,MAAM,cAAc;AAC5D,UAAQ,SACL,CAAC,QAAQ,SAAS,UAAU;GAAE,gBAAgB;GAAM,iBAAiB;GAAO,MAAM;AACjF,OAAI,iBAAiB,QAAQ,QAAQ,gBAAgB,CAAC,OAAO,EAAE;AAC7D,QAAI,QAAQ,eACV,OAAM,gBAAgB;AAGxB,YAAQ,OAAO;;IAGpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-hover.cjs","names":[],"sources":["../../src/use-hover/use-hover.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nexport interface UseHoverReturnValue<T extends HTMLElement = any> {\n hovered: boolean;\n ref: React.RefCallback<T | null>;\n}\n\nexport function useHover<T extends HTMLElement = any>(): UseHoverReturnValue<T> {\n const [hovered, setHovered] = useState(false);\n const previousNode = useRef<HTMLElement>(null);\n\n const handleMouseEnter = useCallback(() => {\n setHovered(true);\n }, []);\n\n const handleMouseLeave = useCallback(() => {\n setHovered(false);\n }, []);\n\n const ref: React.RefCallback<T | null> = useCallback(\n (node) => {\n if (previousNode.current) {\n previousNode.current.removeEventListener('mouseenter', handleMouseEnter);\n previousNode.current.removeEventListener('mouseleave', handleMouseLeave);\n }\n\n if (node) {\n node.addEventListener('mouseenter', handleMouseEnter);\n node.addEventListener('mouseleave', handleMouseLeave);\n }\n\n previousNode.current = node;\n\n return () => {\n previousNode.current = null;\n };\n },\n [handleMouseEnter, handleMouseLeave]\n );\n\n return { ref, hovered };\n}\n\nexport namespace useHover {\n export type ReturnValue<T extends HTMLElement> = UseHoverReturnValue<T>;\n}\n"],"mappings":";;;AAOA,SAAgB,WAAgE;CAC9E,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAuB,MAAM;CAC7C,MAAM,gBAAA,GAAA,MAAA,QAAmC,KAAK;CAE9C,MAAM,oBAAA,GAAA,MAAA,mBAAqC;AACzC,aAAW,KAAK;IACf,EAAE,CAAC;CAEN,MAAM,oBAAA,GAAA,MAAA,mBAAqC;AACzC,aAAW,MAAM;IAChB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"use-hover.cjs","names":[],"sources":["../../src/use-hover/use-hover.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nexport interface UseHoverReturnValue<T extends HTMLElement = any> {\n hovered: boolean;\n ref: React.RefCallback<T | null>;\n}\n\nexport function useHover<T extends HTMLElement = any>(): UseHoverReturnValue<T> {\n const [hovered, setHovered] = useState(false);\n const previousNode = useRef<HTMLElement>(null);\n\n const handleMouseEnter = useCallback(() => {\n setHovered(true);\n }, []);\n\n const handleMouseLeave = useCallback(() => {\n setHovered(false);\n }, []);\n\n const ref: React.RefCallback<T | null> = useCallback(\n (node) => {\n if (previousNode.current) {\n previousNode.current.removeEventListener('mouseenter', handleMouseEnter);\n previousNode.current.removeEventListener('mouseleave', handleMouseLeave);\n }\n\n if (node) {\n node.addEventListener('mouseenter', handleMouseEnter);\n node.addEventListener('mouseleave', handleMouseLeave);\n }\n\n previousNode.current = node;\n\n return () => {\n previousNode.current = null;\n setHovered(false);\n };\n },\n [handleMouseEnter, handleMouseLeave]\n );\n\n return { ref, hovered };\n}\n\nexport namespace useHover {\n export type ReturnValue<T extends HTMLElement> = UseHoverReturnValue<T>;\n}\n"],"mappings":";;;AAOA,SAAgB,WAAgE;CAC9E,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAuB,MAAM;CAC7C,MAAM,gBAAA,GAAA,MAAA,QAAmC,KAAK;CAE9C,MAAM,oBAAA,GAAA,MAAA,mBAAqC;AACzC,aAAW,KAAK;IACf,EAAE,CAAC;CAEN,MAAM,oBAAA,GAAA,MAAA,mBAAqC;AACzC,aAAW,MAAM;IAChB,EAAE,CAAC;AAwBN,QAAO;EAAE,MAAA,GAAA,MAAA,cArBN,SAAS;AACR,OAAI,aAAa,SAAS;AACxB,iBAAa,QAAQ,oBAAoB,cAAc,iBAAiB;AACxE,iBAAa,QAAQ,oBAAoB,cAAc,iBAAiB;;AAG1E,OAAI,MAAM;AACR,SAAK,iBAAiB,cAAc,iBAAiB;AACrD,SAAK,iBAAiB,cAAc,iBAAiB;;AAGvD,gBAAa,UAAU;AAEvB,gBAAa;AACX,iBAAa,UAAU;AACvB,eAAW,MAAM;;KAGrB,CAAC,kBAAkB,iBAAiB,CACrC;EAEa;EAAS"}
|
|
@@ -7,13 +7,17 @@ function useInViewport() {
|
|
|
7
7
|
return {
|
|
8
8
|
ref: (0, react.useCallback)((node) => {
|
|
9
9
|
if (typeof IntersectionObserver !== "undefined") {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
observer.current?.disconnect();
|
|
11
|
+
if (node) {
|
|
12
|
+
observer.current = new IntersectionObserver((entries) => {
|
|
13
|
+
const lastEntry = entries[entries.length - 1];
|
|
14
|
+
setInViewport(lastEntry.isIntersecting);
|
|
15
|
+
});
|
|
16
|
+
observer.current.observe(node);
|
|
17
|
+
} else {
|
|
18
|
+
observer.current = null;
|
|
19
|
+
setInViewport(false);
|
|
20
|
+
}
|
|
17
21
|
}
|
|
18
22
|
}, []),
|
|
19
23
|
inViewport
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-in-viewport.cjs","names":[],"sources":["../../src/use-in-viewport/use-in-viewport.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nexport interface UseInViewportReturnValue<T extends HTMLElement = any> {\n inViewport: boolean;\n ref: React.RefCallback<T | null>;\n}\n\nexport function useInViewport<T extends HTMLElement = any>(): UseInViewportReturnValue<T> {\n const observer = useRef<IntersectionObserver | null>(null);\n const [inViewport, setInViewport] = useState(false);\n\n const ref: React.RefCallback<T | null> = useCallback((node) => {\n if (typeof IntersectionObserver !== 'undefined') {\n if (node
|
|
1
|
+
{"version":3,"file":"use-in-viewport.cjs","names":[],"sources":["../../src/use-in-viewport/use-in-viewport.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nexport interface UseInViewportReturnValue<T extends HTMLElement = any> {\n inViewport: boolean;\n ref: React.RefCallback<T | null>;\n}\n\nexport function useInViewport<T extends HTMLElement = any>(): UseInViewportReturnValue<T> {\n const observer = useRef<IntersectionObserver | null>(null);\n const [inViewport, setInViewport] = useState(false);\n\n const ref: React.RefCallback<T | null> = useCallback((node) => {\n if (typeof IntersectionObserver !== 'undefined') {\n observer.current?.disconnect();\n\n if (node) {\n observer.current = new IntersectionObserver((entries) => {\n const lastEntry = entries[entries.length - 1];\n setInViewport(lastEntry.isIntersecting);\n });\n observer.current.observe(node);\n } else {\n observer.current = null;\n setInViewport(false);\n }\n }\n }, []);\n\n return { ref, inViewport };\n}\n\nexport namespace useInViewport {\n export type ReturnValue<T extends HTMLElement> = UseInViewportReturnValue<T>;\n}\n"],"mappings":";;;AAOA,SAAgB,gBAA0E;CACxF,MAAM,YAAA,GAAA,MAAA,QAA+C,KAAK;CAC1D,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,UAA0B,MAAM;AAmBnD,QAAO;EAAE,MAAA,GAAA,MAAA,cAjB6C,SAAS;AAC7D,OAAI,OAAO,yBAAyB,aAAa;AAC/C,aAAS,SAAS,YAAY;AAE9B,QAAI,MAAM;AACR,cAAS,UAAU,IAAI,sBAAsB,YAAY;MACvD,MAAM,YAAY,QAAQ,QAAQ,SAAS;AAC3C,oBAAc,UAAU,eAAe;OACvC;AACF,cAAS,QAAQ,QAAQ,KAAK;WACzB;AACL,cAAS,UAAU;AACnB,mBAAc,MAAM;;;KAGvB,EAAE,CAAC;EAEQ;EAAY"}
|
|
@@ -5,21 +5,30 @@ function useInterval(fn, interval, { autoInvoke = false } = {}) {
|
|
|
5
5
|
const [active, setActive] = (0, react.useState)(false);
|
|
6
6
|
const intervalRef = (0, react.useRef)(null);
|
|
7
7
|
const fnRef = (0, react.useRef)(null);
|
|
8
|
+
const intervalValueRef = (0, react.useRef)(interval);
|
|
9
|
+
intervalValueRef.current = interval;
|
|
8
10
|
const start = (0, react.useCallback)(() => {
|
|
9
11
|
setActive((old) => {
|
|
10
|
-
if (!old &&
|
|
12
|
+
if (!old && !intervalRef.current) intervalRef.current = window.setInterval(fnRef.current, intervalValueRef.current);
|
|
11
13
|
return true;
|
|
12
14
|
});
|
|
13
15
|
}, []);
|
|
14
16
|
const stop = (0, react.useCallback)(() => {
|
|
15
17
|
setActive(false);
|
|
16
|
-
window.clearInterval(intervalRef.current
|
|
17
|
-
intervalRef.current =
|
|
18
|
+
if (intervalRef.current) window.clearInterval(intervalRef.current);
|
|
19
|
+
intervalRef.current = null;
|
|
18
20
|
}, []);
|
|
19
21
|
const toggle = (0, react.useCallback)(() => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
setActive((current) => {
|
|
23
|
+
if (current) {
|
|
24
|
+
if (intervalRef.current) window.clearInterval(intervalRef.current);
|
|
25
|
+
intervalRef.current = null;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (!intervalRef.current) intervalRef.current = window.setInterval(fnRef.current, intervalValueRef.current);
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
}, []);
|
|
23
32
|
(0, react.useEffect)(() => {
|
|
24
33
|
fnRef.current = fn;
|
|
25
34
|
active && start();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-interval.cjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const fnRef = useRef<() => void>(null);\n\n const start = useCallback(() => {\n setActive((old) => {\n if (!old &&
|
|
1
|
+
{"version":3,"file":"use-interval.cjs","names":[],"sources":["../../src/use-interval/use-interval.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseIntervalOptions {\n /** If set, the interval will start automatically when the component is mounted, `false` by default */\n autoInvoke?: boolean;\n}\n\nexport interface UseIntervalReturnValue {\n /** Starts the interval */\n start: () => void;\n\n /** Stops the interval */\n stop: () => void;\n\n /** Toggles the interval */\n toggle: () => void;\n\n /** Indicates if the interval is active */\n active: boolean;\n}\n\nexport function useInterval(\n fn: () => void,\n interval: number,\n { autoInvoke = false }: UseIntervalOptions = {}\n): UseIntervalReturnValue {\n const [active, setActive] = useState(false);\n const intervalRef = useRef<number | null>(null);\n const fnRef = useRef<() => void>(null);\n const intervalValueRef = useRef(interval);\n intervalValueRef.current = interval;\n\n const start = useCallback(() => {\n setActive((old) => {\n if (!old && !intervalRef.current) {\n intervalRef.current = window.setInterval(fnRef.current!, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n const stop = useCallback(() => {\n setActive(false);\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n }, []);\n\n const toggle = useCallback(() => {\n setActive((current) => {\n if (current) {\n if (intervalRef.current) {\n window.clearInterval(intervalRef.current);\n }\n intervalRef.current = null;\n return false;\n }\n if (!intervalRef.current) {\n intervalRef.current = window.setInterval(fnRef.current!, intervalValueRef.current);\n }\n return true;\n });\n }, []);\n\n useEffect(() => {\n fnRef.current = fn;\n active && start();\n return stop;\n }, [fn, active, interval]);\n\n useEffect(() => {\n if (autoInvoke) {\n start();\n }\n }, []);\n\n return { start, stop, toggle, active };\n}\n\nexport namespace useInterval {\n export type Options = UseIntervalOptions;\n export type ReturnValue = UseIntervalReturnValue;\n}\n"],"mappings":";;;AAqBA,SAAgB,YACd,IACA,UACA,EAAE,aAAa,UAA8B,EAAE,EACvB;CACxB,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,UAAsB,MAAM;CAC3C,MAAM,eAAA,GAAA,MAAA,QAAoC,KAAK;CAC/C,MAAM,SAAA,GAAA,MAAA,QAA2B,KAAK;CACtC,MAAM,oBAAA,GAAA,MAAA,QAA0B,SAAS;AACzC,kBAAiB,UAAU;CAE3B,MAAM,SAAA,GAAA,MAAA,mBAA0B;AAC9B,aAAW,QAAQ;AACjB,OAAI,CAAC,OAAO,CAAC,YAAY,QACvB,aAAY,UAAU,OAAO,YAAY,MAAM,SAAU,iBAAiB,QAAQ;AAEpF,UAAO;IACP;IACD,EAAE,CAAC;CAEN,MAAM,QAAA,GAAA,MAAA,mBAAyB;AAC7B,YAAU,MAAM;AAChB,MAAI,YAAY,QACd,QAAO,cAAc,YAAY,QAAQ;AAE3C,cAAY,UAAU;IACrB,EAAE,CAAC;CAEN,MAAM,UAAA,GAAA,MAAA,mBAA2B;AAC/B,aAAW,YAAY;AACrB,OAAI,SAAS;AACX,QAAI,YAAY,QACd,QAAO,cAAc,YAAY,QAAQ;AAE3C,gBAAY,UAAU;AACtB,WAAO;;AAET,OAAI,CAAC,YAAY,QACf,aAAY,UAAU,OAAO,YAAY,MAAM,SAAU,iBAAiB,QAAQ;AAEpF,UAAO;IACP;IACD,EAAE,CAAC;AAEN,EAAA,GAAA,MAAA,iBAAgB;AACd,QAAM,UAAU;AAChB,YAAU,OAAO;AACjB,SAAO;IACN;EAAC;EAAI;EAAQ;EAAS,CAAC;AAE1B,EAAA,GAAA,MAAA,iBAAgB;AACd,MAAI,WACF,QAAO;IAER,EAAE,CAAC;AAEN,QAAO;EAAE;EAAO;EAAM;EAAQ;EAAQ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-storage.cjs","names":[],"sources":["../../src/use-local-storage/create-storage.ts"],"sourcesContent":["/* oxlint-disable no-console */\nimport { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport type StorageType = 'localStorage' | 'sessionStorage';\n\nexport interface UseStorageOptions<T> {\n /** Storage key */\n key: string;\n\n /** Default value that will be set if value is not found in storage */\n defaultValue?: T;\n\n /** If set to true, value will be updated in useEffect after mount. Default value is true. */\n getInitialValueInEffect?: boolean;\n\n /** Determines whether the value must be synced between browser tabs, `true` by default */\n sync?: boolean;\n\n /** Function to serialize value into string to be save in storage */\n serialize?: (value: T) => string;\n\n /** Function to deserialize string value from storage to value */\n deserialize?: (value: string | undefined) => T;\n}\n\nfunction serializeJSON<T>(value: T, hookName: string = 'use-local-storage') {\n try {\n return JSON.stringify(value);\n } catch (error) {\n throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);\n }\n}\n\nfunction deserializeJSON(value: string | undefined) {\n try {\n return value && JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nfunction createStorageHandler(type: StorageType) {\n const getItem = (key: string) => {\n try {\n return window[type].getItem(key);\n } catch (error) {\n console.warn('use-local-storage: Failed to get value from storage, localStorage is blocked');\n return null;\n }\n };\n\n const setItem = (key: string, value: string) => {\n try {\n window[type].setItem(key, value);\n } catch (error) {\n console.warn('use-local-storage: Failed to set value to storage, localStorage is blocked');\n }\n };\n\n const removeItem = (key: string) => {\n try {\n window[type].removeItem(key);\n } catch (error) {\n console.warn(\n 'use-local-storage: Failed to remove value from storage, localStorage is blocked'\n );\n }\n };\n\n return { getItem, setItem, removeItem };\n}\n\nexport type UseStorageReturnValue<T> = [\n T, // current value\n (val: T | ((prevState: T) => T)) => void, // callback to set value in storage\n () => void, // callback to remove value from storage\n];\n\nexport function createStorage<T>(type: StorageType, hookName: string) {\n const eventName = type === 'localStorage' ? 'mantine-local-storage' : 'mantine-session-storage';\n const { getItem, setItem, removeItem } = createStorageHandler(type);\n\n return function useStorage({\n key,\n defaultValue,\n getInitialValueInEffect = true,\n sync = true,\n deserialize = deserializeJSON,\n serialize = (value: T) => serializeJSON(value, hookName),\n }: UseStorageOptions<T>): UseStorageReturnValue<T> {\n const readStorageValue = useCallback(\n (skipStorage?: boolean): T => {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' ||\n !(type in window) ||\n window[type] === null ||\n !!skipStorage;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n },\n [key, defaultValue]\n );\n\n const [value, setValue] = useState<T>(readStorageValue(getInitialValueInEffect));\n\n const setStorageValue = useCallback(\n (val: T | ((prevState: T) => T)) => {\n if (val instanceof Function) {\n setValue((current) => {\n const result = val(current);\n setItem(key, serialize(result));\n // Defer dispatching this event to avoid the handler being called during render.\n queueMicrotask(() => {\n window.dispatchEvent(
|
|
1
|
+
{"version":3,"file":"create-storage.cjs","names":[],"sources":["../../src/use-local-storage/create-storage.ts"],"sourcesContent":["/* oxlint-disable no-console */\nimport { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport type StorageType = 'localStorage' | 'sessionStorage';\n\nexport interface UseStorageOptions<T> {\n /** Storage key */\n key: string;\n\n /** Default value that will be set if value is not found in storage */\n defaultValue?: T;\n\n /** If set to true, value will be updated in useEffect after mount. Default value is true. */\n getInitialValueInEffect?: boolean;\n\n /** Determines whether the value must be synced between browser tabs, `true` by default */\n sync?: boolean;\n\n /** Function to serialize value into string to be save in storage */\n serialize?: (value: T) => string;\n\n /** Function to deserialize string value from storage to value */\n deserialize?: (value: string | undefined) => T;\n}\n\nfunction serializeJSON<T>(value: T, hookName: string = 'use-local-storage') {\n try {\n return JSON.stringify(value);\n } catch (error) {\n throw new Error(`@mantine/hooks ${hookName}: Failed to serialize the value`);\n }\n}\n\nfunction deserializeJSON(value: string | undefined) {\n try {\n return value && JSON.parse(value);\n } catch {\n return value;\n }\n}\n\nfunction createStorageHandler(type: StorageType) {\n const getItem = (key: string) => {\n try {\n return window[type].getItem(key);\n } catch (error) {\n console.warn('use-local-storage: Failed to get value from storage, localStorage is blocked');\n return null;\n }\n };\n\n const setItem = (key: string, value: string) => {\n try {\n window[type].setItem(key, value);\n } catch (error) {\n console.warn('use-local-storage: Failed to set value to storage, localStorage is blocked');\n }\n };\n\n const removeItem = (key: string) => {\n try {\n window[type].removeItem(key);\n } catch (error) {\n console.warn(\n 'use-local-storage: Failed to remove value from storage, localStorage is blocked'\n );\n }\n };\n\n return { getItem, setItem, removeItem };\n}\n\nexport type UseStorageReturnValue<T> = [\n T, // current value\n (val: T | ((prevState: T) => T)) => void, // callback to set value in storage\n () => void, // callback to remove value from storage\n];\n\nexport function createStorage<T>(type: StorageType, hookName: string) {\n const eventName = type === 'localStorage' ? 'mantine-local-storage' : 'mantine-session-storage';\n const { getItem, setItem, removeItem } = createStorageHandler(type);\n\n return function useStorage({\n key,\n defaultValue,\n getInitialValueInEffect = true,\n sync = true,\n deserialize = deserializeJSON,\n serialize = (value: T) => serializeJSON(value, hookName),\n }: UseStorageOptions<T>): UseStorageReturnValue<T> {\n const readStorageValue = useCallback(\n (skipStorage?: boolean): T => {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' ||\n !(type in window) ||\n window[type] === null ||\n !!skipStorage;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n },\n [key, defaultValue]\n );\n\n const [value, setValue] = useState<T>(readStorageValue(getInitialValueInEffect));\n\n const setStorageValue = useCallback(\n (val: T | ((prevState: T) => T)) => {\n if (val instanceof Function) {\n setValue((current) => {\n const result = val(current);\n setItem(key, serialize(result));\n // Defer dispatching this event to avoid the handler being called during render.\n queueMicrotask(() => {\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: result } }));\n });\n return result;\n });\n } else {\n setItem(key, serialize(val));\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: val } }));\n setValue(val);\n }\n },\n [key]\n );\n\n const removeStorageValue = useCallback(() => {\n removeItem(key);\n setValue(defaultValue as T);\n window.dispatchEvent(new CustomEvent(eventName, { detail: { key, value: defaultValue } }));\n }, [key, defaultValue]);\n\n useWindowEvent('storage', (event) => {\n if (sync) {\n if (event.storageArea === window[type] && event.key === key) {\n setValue(deserialize(event.newValue ?? undefined));\n }\n }\n });\n\n useWindowEvent(eventName, (event) => {\n if (sync) {\n if (event.detail.key === key) {\n setValue(event.detail.value);\n }\n }\n });\n\n useEffect(() => {\n if (defaultValue !== undefined && value === undefined) {\n setStorageValue(defaultValue);\n }\n }, [defaultValue, value, setStorageValue]);\n\n useEffect(() => {\n const val = readStorageValue();\n val !== undefined && setStorageValue(val);\n }, [key]);\n\n return [value === undefined ? (defaultValue as T) : value, setStorageValue, removeStorageValue];\n };\n}\n\nexport function readValue(type: StorageType) {\n const { getItem } = createStorageHandler(type);\n\n return function read<T>({\n key,\n defaultValue,\n deserialize = deserializeJSON,\n }: UseStorageOptions<T>) {\n let storageBlockedOrSkipped;\n\n try {\n storageBlockedOrSkipped =\n typeof window === 'undefined' || !(type in window) || window[type] === null;\n } catch (_e) {\n storageBlockedOrSkipped = true;\n }\n\n if (storageBlockedOrSkipped) {\n return defaultValue as T;\n }\n\n const storageValue = getItem(key);\n return storageValue !== null ? deserialize(storageValue) : (defaultValue as T);\n };\n}\n"],"mappings":"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"}
|
|
@@ -27,14 +27,18 @@ function useLongPress(onLongPress, options = {}) {
|
|
|
27
27
|
}
|
|
28
28
|
isLongPressActive.current = false;
|
|
29
29
|
isPressed.current = false;
|
|
30
|
-
if (timeout.current)
|
|
30
|
+
if (timeout.current !== -1) {
|
|
31
|
+
window.clearTimeout(timeout.current);
|
|
32
|
+
timeout.current = -1;
|
|
33
|
+
}
|
|
31
34
|
};
|
|
32
35
|
return {
|
|
33
36
|
onMouseDown: start,
|
|
34
37
|
onMouseUp: cancel,
|
|
35
38
|
onMouseLeave: cancel,
|
|
36
39
|
onTouchStart: start,
|
|
37
|
-
onTouchEnd: cancel
|
|
40
|
+
onTouchEnd: cancel,
|
|
41
|
+
onTouchCancel: cancel
|
|
38
42
|
};
|
|
39
43
|
}, [
|
|
40
44
|
onLongPress,
|