-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat(core): add pluggable layout constraints system #2190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Code reviewFound 3 issues:
react-grid-layout/test/examples/22-constraints.jsx Lines 37 to 44 in eb36ad2
react-grid-layout/src/core/constraints.ts Lines 235 to 238 in eb36ad2
react-grid-layout/src/react/components/GridItem.tsx Lines 518 to 526 in eb36ad2
Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Add a LayoutConstraint interface following the same patterns as Compactor
and PositionStrategy. This enables pluggable position and size constraints,
replacing hardcoded logic with composable, tree-shakeable constraint functions.
Built-in constraints:
- gridBounds: Keep items within grid boundaries (default)
- minMaxSize: Respect per-item min/max constraints (default)
- containerBounds: Constrain to visible container (replaces isBounded)
- boundedX/boundedY: Axis-specific bounding
Factory functions:
- aspectRatio(ratio): Maintain width-to-height ratio during resize
- snapToGrid(stepX, stepY): Snap positions to coarser grid
- minSize(w, h): Grid-wide minimum size
- maxSize(w, h): Grid-wide maximum size
Usage:
```tsx
<GridLayout
constraints={[gridBounds, minMaxSize, aspectRatio(16/9)]}
/>
// Per-item constraints
const layout = [
{ i: 'video', x: 0, y: 0, w: 4, h: 2, constraints: [aspectRatio(16/9)] }
];
```
This addresses feature requests for:
- Axis-specific bounding (PR #1298)
- Aspect ratio locking (PR #323, #1777)
- Snap-to-grid positioning
- Custom constraint behavior
Add three new interactive examples demonstrating the pluggable constraints system: - 22-constraints.jsx: Built-in constraints (gridBounds, minMaxSize, containerBounds, boundedX, boundedY) - 23-aspect-ratio.jsx: Per-item aspect ratio constraints for video, photo, and banner layouts - 24-custom-constraints.jsx: Creating custom constraint functions with various use cases Also updates: - README.md: Add links to new examples - CLAUDE.md: Add documentation for example system - examples/util/vars.js: Register new examples for navigation
…tation - Add constraints.ts to Package Structure section in CLAUDE.md - Fix containerBounds to calculate visible rows from containerHeight - Add rowHeight and margin to ConstraintContext for pixel-to-grid conversion - containerBounds now falls back to maxRows when containerHeight is 0 - Update RFC to reflect the corrected implementation - Update tests for new containerBounds behavior
Bug fixes: - Add validation to snapToGrid factory to prevent division by zero - Make gridBounds.constrainSize handle-aware for correct bounds calculation during west/north resize handles - Preserve per-item constraints in cloneLayoutItem - Fix aspectRatio to calculate pixel-accurate proportions accounting for different column width vs row height Example improvements: - Convert all constraint examples to v2 API (GridLayout + useContainerWidth) - Fix example constraint order: boundedX/boundedY now replace gridBounds - Rename example files to match master's numbering (20-22) - Add constraint exports to index-dev.js for dev server support - Show constraint source code in custom constraints example - Remove "top half only" option from custom constraints Tests: - Add comprehensive tests for all bug fixes - Update aspectRatio tests for pixel-aware calculations - Update snapshots for cloneLayoutItem change
- Add maxRows: 10 to example 20 so boundedY and containerBounds constraints have a meaningful limit to enforce - Remove outdated "initial heights are approximate" note from example 21 since aspectRatio constraint now calculates pixel-accurate proportions
## Changes ### GridItem.tsx - Remove react-resizable's minConstraints/maxConstraints that were using item.minW/maxW/minH/maxH. Now react-resizable only enforces a minimum of 1 grid unit (safety net). This allows our pluggable constraint system to be the sole authority on size limits, making constraints=[] work as expected. ### index-dev.js - Add compactor exports (noCompactor, verticalCompactor) for use in examples ### Example 20 (constraints.jsx) - Add "No Compaction" checkbox to demonstrate position constraints - Vertical compaction moves items back up, hiding boundedX/boundedY effects - With noCompactor, users can clearly see how position constraints work - Improved explanations for each constraint type ### constraints-test.ts - Add tests for empty constraints behavior (no limits enforced) - Add tests for boundedX allowing free Y movement - Add tests for boundedY allowing free X movement - Add tests for constraint composition (gridBounds + minMaxSize) - Verify that without minMaxSize, item.maxW is not enforced
eb36ad2 to
8d6991f
Compare
- Update RFC 0002 with example links, usage guide, and implementation details - Add documentation links to all constraint examples (20, 21, 22) - Examples link to GitHub URLs (for viewing outside repo context) - RFC uses relative links (for GitHub markdown rendering) - Document constraint vs compaction interaction - Add custom constraint creation guide with ConstraintContext details
Code reviewFound 1 issue:
react-grid-layout/rfcs/0002-pluggable-constraints.md Lines 14 to 16 in 8622c5c
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
- CLAUDE.md: examples should use v2 API with useContainerWidth hook - RFC: use yarn dev instead of npm run dev
Summary
Add a
LayoutConstraintinterface following the same patterns asCompactorandPositionStrategy. This enables pluggable position and size constraints, replacing hardcoded logic with composable, tree-shakeable constraint functions.LayoutConstraintinterface withconstrainPositionandconstrainSizemethodsgridBounds,minMaxSize,containerBounds,boundedX,boundedYaspectRatio(),snapToGrid(),minSize(),maxSize()constraintsprop toGridLayout(default:[gridBounds, minMaxSize])LayoutItem.constraintsarrayisBoundedprop tocontainerBoundsconstraint for backwards compatibilityUsage
Grid-level constraints:
Per-item constraints:
Addresses feature requests
Test plan
isBoundedprop continues to work