UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

1 lines 12.9 kB
{"version":3,"file":"FloatingWindowResizeHandle.cjs","names":["factory","useProps","useFloatingWindowContext","Box"],"sources":["../../../src/components/FloatingWindow/FloatingWindowResizeHandle.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-deprecated */\nimport { useEffect, useRef } from 'react';\nimport { useMergedRef } from '@mantine/hooks';\nimport { Box, BoxProps, ElementProps, factory, Factory, useProps } from '../../core';\nimport { useFloatingWindowContext } from './FloatingWindow.context';\n\nexport interface FloatingWindowResizeHandleProps extends BoxProps, ElementProps<'div', 'role'> {}\n\nexport type FloatingWindowResizeHandleFactory = Factory<{\n props: FloatingWindowResizeHandleProps;\n ref: HTMLDivElement;\n}>;\n\nconst defaultProps = {} satisfies Partial<FloatingWindowResizeHandleProps>;\n\nconst KEYBOARD_STEP = 10;\n\nfunction clampDimension(\n value: number,\n min: number | undefined,\n max: number | undefined,\n viewportMax: number | undefined\n) {\n let v = value;\n if (min != null) {\n v = Math.max(v, min);\n }\n if (max != null) {\n v = Math.min(v, max);\n }\n if (viewportMax != null) {\n v = Math.min(v, viewportMax);\n }\n return v;\n}\n\nfunction getViewportLimits(\n rect: DOMRect,\n constrainToViewport: boolean | undefined,\n constrainOffset: number | undefined\n) {\n if (!constrainToViewport) {\n return { maxWidth: undefined, maxHeight: undefined };\n }\n const offset = constrainOffset ?? 0;\n return {\n maxWidth: window.innerWidth - rect.left - offset,\n maxHeight: window.innerHeight - rect.top - offset,\n };\n}\n\nexport const FloatingWindowResizeHandle = factory<FloatingWindowResizeHandleFactory>((_props) => {\n const props = useProps('FloatingWindowResizeHandle', defaultProps, _props);\n const { children, ref, style, ...others } = props;\n const ctx = useFloatingWindowContext();\n const handleRef = useRef<HTMLDivElement>(null);\n const ctxRef = useRef(ctx);\n ctxRef.current = ctx;\n const valueNowRef = useRef<number | null>(null);\n\n const hasWidth =\n ctx.dimensions?.initialWidth != null ||\n ctx.dimensions?.minWidth != null ||\n ctx.dimensions?.maxWidth != null;\n const hasHeight =\n ctx.dimensions?.initialHeight != null ||\n ctx.dimensions?.minHeight != null ||\n ctx.dimensions?.maxHeight != null;\n\n useEffect(() => {\n const handle = handleRef.current;\n if (!handle) {\n return;\n }\n\n const controller = new AbortController();\n const { signal } = controller;\n let isResizing = false;\n let startX = 0;\n let startY = 0;\n let startWidth = 0;\n let startHeight = 0;\n\n const applySize = (width: number | null, height: number | null) => {\n if (width === null && height === null) {\n return;\n }\n\n const { dimensions, constrainToViewport, constrainOffset, onSizeChange } = ctxRef.current;\n const root = ctxRef.current.rootRef.current;\n if (!root) {\n return;\n }\n\n const rect = root.getBoundingClientRect();\n const viewportLimits = getViewportLimits(rect, constrainToViewport, constrainOffset);\n\n if (width !== null) {\n const nextWidth = clampDimension(\n width,\n dimensions?.minWidth,\n dimensions?.maxWidth,\n viewportLimits.maxWidth\n );\n root.style.width = `${nextWidth}px`;\n }\n\n if (height !== null) {\n const nextHeight = clampDimension(\n height,\n dimensions?.minHeight,\n dimensions?.maxHeight,\n viewportLimits.maxHeight\n );\n root.style.height = `${nextHeight}px`;\n }\n\n const resizedRect = root.getBoundingClientRect();\n\n if (width !== null) {\n valueNowRef.current = resizedRect.width;\n handle.setAttribute('aria-valuenow', String(Math.round(resizedRect.width)));\n }\n\n onSizeChange?.({ width: resizedRect.width, height: resizedRect.height });\n };\n\n const onStart = (e: MouseEvent | TouchEvent) => {\n if ('button' in e && e.button !== 0) {\n return;\n }\n\n e.stopPropagation();\n e.preventDefault();\n\n if (!hasWidth && !hasHeight) {\n return;\n }\n\n const root = ctxRef.current.rootRef.current;\n if (!root) {\n return;\n }\n\n const point = 'touches' in e ? e.touches[0] : e;\n startX = point.clientX;\n startY = point.clientY;\n const rect = root.getBoundingClientRect();\n startWidth = rect.width;\n startHeight = rect.height;\n isResizing = true;\n\n document.body.style.userSelect = 'none';\n document.body.style.webkitUserSelect = 'none';\n\n ctxRef.current.onResizeStart?.();\n\n document.addEventListener('mousemove', onMove, { signal });\n document.addEventListener('mouseup', onEnd, { signal });\n document.addEventListener('touchmove', onMove, { signal, passive: false });\n document.addEventListener('touchend', onEnd, { signal });\n document.addEventListener('touchcancel', onEnd, { signal });\n };\n\n const onMove = (e: MouseEvent | TouchEvent) => {\n if (!isResizing) {\n return;\n }\n\n e.preventDefault();\n const point = 'touches' in e ? e.touches[0] : e;\n const deltaX = point.clientX - startX;\n const deltaY = point.clientY - startY;\n applySize(hasWidth ? startWidth + deltaX : null, hasHeight ? startHeight + deltaY : null);\n };\n\n const onEnd = () => {\n if (!isResizing) {\n return;\n }\n\n isResizing = false;\n document.body.style.userSelect = '';\n document.body.style.webkitUserSelect = '';\n ctxRef.current.onResizeEnd?.();\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n const { dimensions } = ctxRef.current;\n const root = ctxRef.current.rootRef.current;\n if (!root) {\n return;\n }\n\n const rect = root.getBoundingClientRect();\n let newWidth: number | null = null;\n let newHeight: number | null = null;\n\n if (e.key === 'ArrowRight' && hasWidth) {\n newWidth = rect.width + KEYBOARD_STEP;\n } else if (e.key === 'ArrowLeft' && hasWidth) {\n newWidth = rect.width - KEYBOARD_STEP;\n } else if (e.key === 'ArrowDown' && hasHeight) {\n newHeight = rect.height + KEYBOARD_STEP;\n } else if (e.key === 'ArrowUp' && hasHeight) {\n newHeight = rect.height - KEYBOARD_STEP;\n } else if (e.key === 'Home') {\n if (hasWidth) {\n newWidth = dimensions?.minWidth ?? rect.width;\n }\n if (hasHeight) {\n newHeight = dimensions?.minHeight ?? rect.height;\n }\n } else if (e.key === 'End') {\n if (hasWidth) {\n newWidth = dimensions?.maxWidth ?? rect.width;\n }\n if (hasHeight) {\n newHeight = dimensions?.maxHeight ?? rect.height;\n }\n }\n\n if (newWidth !== null || newHeight !== null) {\n e.preventDefault();\n applySize(newWidth, newHeight);\n }\n };\n\n handle.addEventListener('mousedown', onStart, { signal });\n handle.addEventListener('touchstart', onStart, { signal, passive: false });\n handle.addEventListener('keydown', onKeyDown, { signal });\n\n return () => {\n onEnd();\n controller.abort();\n };\n }, [hasWidth, hasHeight]);\n\n useEffect(() => {\n const handle = handleRef.current;\n if (!handle) {\n return;\n }\n\n if (!hasWidth) {\n valueNowRef.current = null;\n handle.removeAttribute('aria-valuenow');\n return;\n }\n\n if (valueNowRef.current !== null) {\n return;\n }\n\n const initialWidth = ctx.dimensions?.initialWidth;\n\n if (initialWidth == null) {\n handle.removeAttribute('aria-valuenow');\n return;\n }\n\n const width = clampDimension(\n initialWidth,\n ctx.dimensions?.minWidth,\n ctx.dimensions?.maxWidth,\n undefined\n );\n\n handle.setAttribute('aria-valuenow', String(Math.round(width)));\n }, [hasWidth, ctx.dimensions?.initialWidth, ctx.dimensions?.minWidth, ctx.dimensions?.maxWidth]);\n\n return (\n <Box\n ref={useMergedRef(ref, handleRef)}\n role=\"separator\"\n aria-label=\"Resize window\"\n aria-valuemin={ctx.dimensions?.minWidth}\n aria-valuemax={ctx.dimensions?.maxWidth}\n tabIndex={0}\n {...others}\n style={[{ touchAction: 'none' }, style]}\n >\n {children}\n </Box>\n );\n});\n\nFloatingWindowResizeHandle.displayName = '@mantine/core/FloatingWindowResizeHandle';\n"],"mappings":"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"}