Skip to content

dragBounds improvements#12

Merged
gfazioli merged 20 commits intomasterfrom
dragBounds-improvements
Jan 26, 2026
Merged

dragBounds improvements#12
gfazioli merged 20 commits intomasterfrom
dragBounds-improvements

Conversation

@gfazioli
Copy link
Owner

  • feat(Window): add viewport and mixed unit constraints support
  • 🚀 feat(Window): allow string units for dragBounds and add demos
  • feat(Window): add container boundary constraints for non‑portal windows

- Extend min/max width/height props to accept px, vw, vh, and % values
- Introduce convertToPixels helper with comprehensive tests
- Add demos and stories for viewport‑based and mixed unit constraints
- Update documentation to showcase new constraint options
- Extend WindowBounds to accept string values (px, vw, vh, %)
- Convert string bounds to pixels in use-mantine-window
- Add viewport, percentage, and mixed unit drag bounds demos and docs
- Reset default position to (0,0) and add default size in demos
- Update docs to state windows cannot be dragged or resized outside container
- Hook now clamps width/height to parent size and limits resize to container bounds
- Adjust drag bounds and resize logic to respect container dimensions and withinPortal flag
Copilot AI review requested due to automatic review settings January 25, 2026 14:03
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for viewport units (vw, vh), percentages, and mixed unit types for window sizing and drag boundary constraints in the Mantine Window component.

Changes:

  • Added convertToPixels utility function to handle multiple CSS unit types (px, vw, vh, %)
  • Enhanced dragBounds, minWidth, maxWidth, minHeight, and maxHeight to accept string units in addition to numbers
  • Improved container boundary constraints for non-portal windows during resize operations
  • Added comprehensive documentation and demo examples for new features

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
package/src/lib/convert-to-pixels.ts New utility function to convert CSS values (px, vw, vh, %) to pixels
package/src/lib/convert-to-pixels.test.ts Comprehensive test suite for the conversion utility
package/src/hooks/use-mantine-window.ts Updated clamping and bounds logic to use convertToPixels; added container constraints for non-portal resize
package/src/Window.tsx Updated type definitions to accept string units for size and boundary constraints
package/src/Window.story.tsx Added five new story examples demonstrating viewport and mixed unit features
docs/docs.mdx Added documentation sections for viewport-based and percentage-based constraints
docs/demos/index.ts Exported new demo components
docs/demos/Window.demo.withinPortal.tsx Updated positioning and documentation for container boundary behavior
docs/demos/Window.demo.viewportDragBounds.tsx New demo showing viewport-based drag boundaries
docs/demos/Window.demo.viewportConstraints.tsx New demo showing viewport-based size constraints
docs/demos/Window.demo.percentageDragBounds.tsx New demo showing percentage-based drag boundaries
docs/demos/Window.demo.mixedDragBounds.tsx New demo showing mixed unit drag boundaries
docs/demos/Window.demo.mixedConstraints.tsx New demo showing mixed unit size constraints
Comments suppressed due to low confidence (1)

package/src/hooks/use-mantine-window.ts:431

  • Container boundary constraints are inconsistently applied across resize directions. The topLeft, top, left, and bottomLeft cases don't have explicit container boundary checks after clamping, while topRight, right, bottomRight, bottom, and bottomLeft do.

For the topLeft case specifically, when the window position changes (newX and newY are adjusted), there's no verification that the new position doesn't push the window outside the container bounds. This could allow the window to extend beyond the container when resizing from these corners.

Consider adding container boundary validation for all resize directions to ensure consistent behavior, or add a comment explaining why certain directions don't need these checks.

      switch (resizeDirection.current) {
        case 'topLeft':
          newWidth = clampWidth(resizeStart.current.width - deltaX);
          newHeight = clampHeight(resizeStart.current.height - deltaY);
          newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
          newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
          break;
        case 'top':
          newHeight = clampHeight(resizeStart.current.height - deltaY);
          newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
          break;
        case 'topRight':
          newWidth = clampWidth(resizeStart.current.width + deltaX);
          // Limit width based on position and container
          if (!withinPortal && newX + newWidth > containerMaxWidth) {
            newWidth = containerMaxWidth - newX;
          }
          newHeight = clampHeight(resizeStart.current.height - deltaY);
          newY = resizeStart.current.posY + (resizeStart.current.height - newHeight);
          break;
        case 'right':
          newWidth = clampWidth(resizeStart.current.width + deltaX);
          // Limit width based on position and container
          if (!withinPortal && newX + newWidth > containerMaxWidth) {
            newWidth = containerMaxWidth - newX;
          }
          break;
        case 'bottomRight':
          newWidth = clampWidth(resizeStart.current.width + deltaX);
          // Limit width based on position and container
          if (!withinPortal && newX + newWidth > containerMaxWidth) {
            newWidth = containerMaxWidth - newX;
          }
          newHeight = clampHeight(resizeStart.current.height + deltaY);
          // Limit height based on position and container
          if (!withinPortal && newY + newHeight > containerMaxHeight) {
            newHeight = containerMaxHeight - newY;
          }
          break;
        case 'bottom':
          newHeight = clampHeight(resizeStart.current.height + deltaY);
          // Limit height based on position and container
          if (!withinPortal && newY + newHeight > containerMaxHeight) {
            newHeight = containerMaxHeight - newY;
          }
          break;
        case 'bottomLeft':
          newWidth = clampWidth(resizeStart.current.width - deltaX);
          newHeight = clampHeight(resizeStart.current.height + deltaY);
          // Limit height based on position and container
          if (!withinPortal && newY + newHeight > containerMaxHeight) {
            newHeight = containerMaxHeight - newY;
          }
          newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
          break;
        case 'left':
          newWidth = clampWidth(resizeStart.current.width - deltaX);
          newX = resizeStart.current.posX + (resizeStart.current.width - newWidth);
          break;

…formed inputs

- Add tests for negative values, NaN, Infinity, malformed strings, zero, large, and decimal inputs
- Guard against non‑finite numbers in pixel, viewport, and percentage conversions
- Ensure function returns undefined for invalid or non‑finite values, improving robustness
- Ensures callback updates when windowRef changes, preventing stale references.
…ort and container size

- Use Mantine's useViewportSize and useResizeObserver to track container and viewport dimensions.
- Memoize constraint conversions to avoid repeated calculations during drag/resize.
- Simplify drag and resize bounds using memoized values.
- Improve performance and correctness when window is in portal or not.
…ainer mode

- Add bounds checks for containerMaxWidth/Height during resize
- Ensure windows stay within container boundaries
- Improves user experience by keeping windows visible and draggable only within the container.
…n useMantineWindow

- Return undefined for percentage units when window is undefined (SSR compatibility).
- Add tests verifying SSR behavior of convertToPixels.
- Use local state for container dimensions to avoid flicker on first render.
- Update constraints and bounds logic to use the new container state.
… and size

- Update Window props to accept string units for width, height, x, y
- Convert units to pixels on mount with SSR‑safe defaults
- Use useMounted, useClickOutside, and useMergedRef for z‑index handling
- Add data-mantine-window attribute for easier querying
- Add demos, stories, and tests for viewport, percentage, and mixed units
- Update docs to showcase new responsive examples
- Extract state handling to `useWindowState`
- Extract constraints conversion to `useWindowConstraints`
- Extract dimension tracking to `useWindowDimensions`
- Extract drag handling to `useWindowDrag`
- Extract resize handling to `useWindowResize`
- Simplify `useMantineWindow` to orchestrate these hooks and improve readability.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

- Eliminates unused icons and UI components
- Reduces bundle size and improves build performance
- Simplifies Window component logic
- Verify clampWidth respects min/max, container limits, and edge cases.
- Verify clampHeight handles min/max, container limits, and edge cases.
- Test applyDragBounds with explicit bounds, partial bounds, negative and decimal values.
- Ensure viewport and container constraints work when dragBounds absent.
- Confirm behavior for oversized windows, zero dimensions, and Infinity values.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 15 comments.

- Introduce Window.demo.percentagePosition and Window.demo.percentageSize
- Update docs to explain viewport vs. percentage references and best practices
- Refactor existing demos to use useDisclosure and remove withinPortal
- Add eslint-disable comment to console logs in callbacks demo
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.

- Replace table with bullet points to clarify viewport, percentage, and pixel references
- Explain how `withinPortal` affects percentage units
- Improve readability and consistency with other documentation sections
- Percentages now return undefined when no reference size is provided, preventing misleading pixel values.
- Updated tests to assert undefined for '50%' and '100%' without a reference.
- Maintains consistent behavior across unit conversions.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 11 comments.

…ocalStorage key

- Add viewport fallback when container width/height are 0 to avoid NaN calculations.
- Use clamp functions during resize to keep dimensions within constraints.
- Ensure localStorage keys are always set correctly, fixing incorrect key usage.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 1 comment.

- Replace Box wrapper with Button and useDisclosure for opening windows
- Remove withinPortal to keep windows inline
- Simplify useWindowResize calculations using adjusted values
- Update localStorage keys to use volatile suffix when persistState is false
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 8 comments.

- Remove containerRef and windowRef from useEffect dependency array
- Prevents unnecessary re‑runs when refs change
- Improves performance and avoids stale closures in the hook
- Update Window prop docs to include viewport units and percentages
- Extend convertToPixels to support '%' and return undefined when reference missing
- Add detailed examples and supported units list
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 5 comments.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.

@gfazioli gfazioli merged commit adb764a into master Jan 26, 2026
13 checks passed
@gfazioli gfazioli deleted the dragBounds-improvements branch January 26, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant