React Split Pane Component
This challenge asks you to implement a reusable split pane component in React using TypeScript. Split pane components are commonly used in applications to divide a screen into two or more resizable panels, allowing users to customize the layout and focus on different sections of content simultaneously. This is a valuable skill for building flexible and user-friendly interfaces.
Problem Description
You need to create a SplitPane component that allows users to resize a dividing line between two child components (panes). The component should:
- Accept two child components: These represent the content to be displayed in each pane.
- Provide a resizable divider: A visual element (e.g., a line) that the user can drag to adjust the size of the panes.
- Maintain state for pane sizes: The component should track the width (or height, if vertical) of each pane.
- Handle resizing: When the user drags the divider, the component should update the pane sizes accordingly.
- Provide a minimum and maximum pane size: Prevent panes from becoming too small or too large.
- Support both horizontal and vertical orientations: The component should be configurable to split the screen horizontally (default) or vertically.
Expected Behavior:
- Initially, the split pane should have a default size distribution (e.g., 50/50).
- Dragging the divider should smoothly update the pane sizes.
- The divider should visually indicate its draggable state (e.g., change cursor on hover).
- The component should prevent the panes from exceeding the specified minimum or maximum sizes.
- The component should re-render correctly when the pane sizes change.
Edge Cases to Consider:
- What happens if one of the child components has dynamic content that affects its size?
- How should the component handle invalid input (e.g., null or undefined children)?
- Consider accessibility - ensure the divider is focusable and keyboard navigable.
Examples
Example 1: Horizontal Split (Default)
Input: <SplitPane><Panel>Left Pane</Panel><Panel>Right Pane</Panel></SplitPane>
Output: A horizontal split pane with "Left Pane" occupying 50% of the width and "Right Pane" occupying the other 50%. The divider is draggable.
Explanation: The component defaults to a horizontal split and divides the space equally.
Example 2: Vertical Split
Input: <SplitPane orientation="vertical"><Panel>Top Pane</Panel><Panel>Bottom Pane</Panel></SplitPane>
Output: A vertical split pane with "Top Pane" occupying 50% of the height and "Bottom Pane" occupying the other 50%. The divider is draggable.
Explanation: The `orientation="vertical"` prop changes the split direction.
Example 3: Minimum and Maximum Sizes
Input: <SplitPane minSize={100} maxSize={800}><Panel>Pane 1</Panel><Panel>Pane 2</Panel></SplitPane>
Output: A horizontal split pane where each pane initially occupies 50% of the available width. Dragging the divider will not allow either pane to be smaller than 100px or larger than 800px.
Explanation: The `minSize` and `maxSize` props enforce size limits.
Constraints
- Component Structure: The component should be a functional component using React Hooks.
- Styling: You can use CSS or a CSS-in-JS library (e.g., styled-components) for styling. Focus on functionality over elaborate styling.
- Performance: The component should be performant and avoid unnecessary re-renders. Use
useMemoanduseCallbackwhere appropriate. - Pane Size Range:
minSizeandmaxSizeshould be numbers representing pixel values. - Orientation: The
orientationprop should be a string, either "horizontal" (default) or "vertical".
Notes
- Consider using
useStateto manage the pane sizes and divider position. - You'll need to handle mouse events (e.g.,
onMouseDown,onMouseMove,onMouseUp) to implement the dragging functionality. - Think about how to calculate the new pane sizes based on the divider's position and the available space.
- Accessibility is important. Make sure the divider is focusable and can be interacted with using the keyboard.
- You can assume that the parent container of the
SplitPanecomponent has a defined width (for horizontal splits) or height (for vertical splits).