Skip to content

Conversation

@badmike
Copy link
Contributor

@badmike badmike commented Dec 28, 2025

This pull request adds pixel-based sizing to the Splitter component, allowing panels to be sized in fixed pixels (px) alongside the existing percentage (%) support. The changes handle pixel sizing across layout calculations, persistence, collapse/expand operations, and panel constraints, with automatic conversion between units as needed.

Changes:

Added a new sizeUnit prop to SplitterPanel to specify whether a panel uses pixel or percent sizing, with corresponding support throughout the sizing logic. [1] [2] [3]

Updated layout calculation and persistence logic to convert between percent and pixel units, ensuring fixed-width panels maintain their size during resizing and when persisting state. [1] [2] [3] [4]

Refactored constraint validation to internally normalize all constraints to percent-based values and recalculate layouts when the container size changes. [1] [2] [3]

Updated collapse and expand operations to store and restore panel sizes in their original unit, converting as needed between percent and pixel values. [1] [2] [3]

Updated documentation with descriptions and examples of the new pixel sizing feature. [1] [2]

Closes #836, #2069

Summary by CodeRabbit

Release Notes

  • New Features

    • Added pixel-based sizing support for panels with new sizeUnit prop, enabling fixed-size panels alongside fluid panels
    • Pixel sizing works seamlessly with panel persistence and collapse/expand functionality
  • Documentation

    • Added "Pixel sizing" documentation section with practical examples and usage patterns
    • Enhanced feature list to highlight percent and pixel sizing capabilities

✏️ Tip: You can customize this high-level summary in your review settings.

@badmike badmike changed the title Allow px in splitter feat(Splitter): add support for pixel sizing and constraints Dec 28, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 2, 2026

Open in StackBlitz

npm i https://pkg.pr.new/reka-ui@2362

commit: 7d15ade

@zernonia
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

Add pixel-based sizing support to the Splitter component. Introduces a sizeUnit prop allowing panels to specify '%' or 'px' units, adds utilities for percent-pixel conversions with responsive reflow via ResizeObserver, updates validation and storage to preserve unit information, and integrates changes across accessibility and layout recalculation paths.

Changes

Cohort / File(s) Summary
Documentation
docs/content/docs/components/splitter.md
Added feature note for percent and pixel sizing support; introduced "Pixel sizing" section with size-unit="px" example and compatibility notes for persistence and collapse APIs.
Core Components
packages/core/src/Splitter/SplitterPanel.vue, packages/core/src/Splitter/SplitterGroup.vue
Added sizeUnit prop to SplitterPanel; extended SplitterGroup with ResizeObserver-based group size tracking, percent-pixel constraint conversion helpers (getGroupSizeInPixels, getPanelConstraintsInPercent, getPanelDataWithPercentConstraints), and updated resize/collapse/expand logic to handle px-based constraints.
Unit Conversion Utilities
packages/core/src/Splitter/utils/units.ts
New module introducing SizeUnit type, convertPanelConstraintsToPercent, hasPixelSizedPanel, and recalculateLayoutForPixelPanels functions for bidirectional unit conversion and responsive layout recalculation when group size changes.
Validation & Persistence
packages/core/src/Splitter/utils/validation.ts, packages/core/src/Splitter/utils/storage.ts
Updated validation to condition 100% upper bound check on sizeUnit='%'; added sizeUnits field to PanelConfigurationState for persisting per-panel unit information during save/restore.
Accessibility Integration
packages/core/src/Splitter/utils/composables/useWindowSplitterPanelGroupBehavior.ts
Extended signature with getPanelDataWithPercentConstraints parameter; replaced panelDataArray usage with percent-constrained variant for ARIA calculations, accessibility attributes, and keyboard interactions.
Story & Examples
packages/core/src/Splitter/story/SplitterPixelSizing.story.vue
New story file demonstrating pixel sizing through four variants: fixed sidebar, persistence with px, conditional panels with dynamic ordering, and collapsible panel with toggle handlers.

Sequence Diagram

sequenceDiagram
    participant RO as ResizeObserver
    participant SG as SplitterGroup
    participant UC as Unit Converter
    participant Layout as Layout Engine
    participant A11y as Accessibility

    RO->>SG: Group element resized
    SG->>SG: Update groupSizeInPixels
    SG->>UC: getGroupSizeInPixels + panelData
    UC->>UC: convertPanelConstraintsToPercent<br/>(px → % conversion)
    UC->>SG: Return panelConstraintsInPercent
    SG->>Layout: recalculateLayoutForPixelPanels<br/>(prevSize, nextSize)
    Layout->>Layout: Recompute percent for px panels<br/>Scale non-px panels to 100%
    Layout->>SG: Updated layout array
    SG->>A11y: getPanelDataWithPercentConstraints()
    A11y->>A11y: Update ARIA values & attributes<br/>for accessibility reflection
    SG->>SG: Emit layout change events
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A splitter now speaks in pixels and percent,
With ResizeObserver watching where panels went,
From px to percent, conversions take flight,
Responsive and nimble, the layout sits tight!
✨ Constraints transform as the viewport grows bright. 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and concisely describes the main feature: pixel sizing support for the Splitter component, which is the primary change across all modified files.
Linked Issues check ✅ Passed The PR fully implements pixel unit support for panel sizing (minSize, maxSize, default sizes) via the new sizeUnit prop and constraint conversion utilities, directly addressing issue #836's requirements.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing pixel sizing support: new sizeUnit prop, constraint conversions, layout recalculation, state persistence, validation updates, documentation, and story examples—all within scope of the linked feature request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
packages/core/src/Splitter/utils/units.ts (1)

126-126: Remove unused variable.

prevPercentForPixelPanels is computed but never referenced in subsequent logic. This appears to be leftover from development.

🧹 Suggested cleanup
-  const prevPercentForPixelPanels = pixelPanelIndices.reduce((sum, index) => sum + (layout[index] ?? 0), 0)
-
   const nextPixelPercents = pixelPanelIndices.map((index) => {
packages/core/src/Splitter/story/SplitterPixelSizing.story.vue (1)

17-24: Redundant state update may cause inconsistent state.

The toggleCollapsible function sets collapsibleOpen.value on line 23 after calling collapse()/expand(). However, the @collapse and @expand event handlers (lines 152-153) also update this same state via handleCollapsed and handleExpanded. This can lead to the state being toggled twice or race conditions if the events fire asynchronously.

Remove the manual toggle since the event handlers already manage the state:

Proposed fix
 function toggleCollapsible() {
   if (collapsibleOpen.value)
     collapsiblePanelRef.value?.collapse?.()
   else
     collapsiblePanelRef.value?.expand?.()
-
-  collapsibleOpen.value = !collapsibleOpen.value
 }

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac84b72 and 7d15ade.

📒 Files selected for processing (8)
  • docs/content/docs/components/splitter.md
  • packages/core/src/Splitter/SplitterGroup.vue
  • packages/core/src/Splitter/SplitterPanel.vue
  • packages/core/src/Splitter/story/SplitterPixelSizing.story.vue
  • packages/core/src/Splitter/utils/composables/useWindowSplitterPanelGroupBehavior.ts
  • packages/core/src/Splitter/utils/storage.ts
  • packages/core/src/Splitter/utils/units.ts
  • packages/core/src/Splitter/utils/validation.ts
🔇 Additional comments (22)
packages/core/src/Splitter/utils/validation.ts (1)

109-138: LGTM!

The validation logic correctly adapts to the new sizeUnit prop:

  • Warning messages now correctly display the unit being validated
  • The defaultSize > 100 check is properly conditioned on sizeUnit === '%' since pixel values can legitimately exceed 100
  • The maxSize comparison still applies regardless of unit, which is correct
packages/core/src/Splitter/utils/units.ts (3)

16-27: LGTM!

The conversion logic correctly handles edge cases:

  • Returns the value unchanged for % units
  • Safely returns undefined when group size is unavailable for px conversion
  • Prevents division-by-zero issues

29-77: LGTM!

The early return at lines 37-38 ensures that if any panel uses px but the group size isn't measured yet, the function returns null rather than producing invalid fallback values. This prevents the fallback chain at line 70 from incorrectly using raw pixel values as percentages.


90-160: Algorithm looks correct for maintaining fixed pixel widths.

The recalculation logic properly:

  1. Preserves pixel-sized panels' absolute widths by converting their current percentage to pixels then back to percentage at the new group size
  2. Scales percentage-based panels proportionally to fill the remaining space
  3. Returns null appropriately when recalculation isn't possible or needed
packages/core/src/Splitter/SplitterPanel.vue (3)

21-22: LGTM!

The new sizeUnit prop is well-integrated:

  • Type-safe with '%' | 'px' union
  • Properly propagated to PanelConstraints type for downstream consumption
  • Defaults to '%' for backward compatibility

Also applies to: 54-54


120-132: LGTM!

Correctly triggers constraint reevaluation when sizeUnit changes, allowing panels to react to dynamic unit switching.


165-170: LGTM!

The exposed API documentation accurately reflects that getSize() and resize() now operate in the panel's configured unit (percentage for %, pixels for px).

docs/content/docs/components/splitter.md (1)

200-224: LGTM!

The documentation clearly explains the pixel sizing feature with a practical example showing the recommended pattern: a fixed-width sidebar alongside a flexible content panel. The note about persistence and collapse/expand API compatibility is helpful for users.

packages/core/src/Splitter/utils/storage.ts (1)

108-122: LGTM!

The storage implementation efficiently persists sizeUnits:

  • Only stores non-default values ('px'), keeping storage compact
  • Conditionally includes sizeUnits only when there are entries to store
  • Follows the existing index-based pattern consistent with layout storage
packages/core/src/Splitter/story/SplitterPixelSizing.story.vue (1)

27-165: LGTM!

The story variants comprehensively demonstrate the new pixel sizing feature including fixed sidebars, persistence, conditional panels, and collapsible behavior. The template structure and prop usage are correct.

packages/core/src/Splitter/utils/composables/useWindowSplitterPanelGroupBehavior.ts (2)

37-40: LGTM!

The early guard correctly aborts the effect when percent constraints cannot be computed (e.g., when group size is unavailable), preventing invalid ARIA attribute updates.


120-161: LGTM!

The Enter key handler correctly uses percent-constrained panel data for collapse/expand calculations while maintaining proper constraint access. The delta calculation and layout adjustment logic are sound.

packages/core/src/Splitter/SplitterGroup.vue (10)

155-171: LGTM!

The fallback to getBoundingClientRect measurement with caching is a reasonable approach for scenarios where the ResizeObserver hasn't yet fired (initial render, SSR hydration).


206-230: LGTM!

The ResizeObserver setup correctly handles:

  • Feature detection for SSR compatibility
  • Proper cleanup on unmount
  • HTMLElement type guard before observing

361-402: LGTM!

The watch handler efficiently guards against unnecessary recalculations and correctly triggers layout updates only when pixel-sized panels exist and the group size actually changes.


498-551: LGTM!

The resizePanel function correctly converts pixel sizes to percentages for internal calculations while respecting the panel's sizeUnit configuration.


654-663: LGTM!

The collapse logic correctly stores the pre-collapse size in the panel's original unit (converting from percent to pixels when needed), enabling accurate restoration on expand.


712-730: LGTM!

The expand logic correctly converts the stored pixel size back to percent for layout calculations, with appropriate fallback to minSize when the restored size is smaller.


762-782: LGTM!

The getPanelSize function correctly returns sizes in the panel's configured unit, converting from the internal percentage representation to pixels when needed.


784-812: LGTM!

The isPanelCollapsed function correctly uses percent-based constraints and handles the SSR edge case with appropriate fallback logic.


866-889: LGTM!

The panelDataHelper function correctly prioritizes percent-normalized constraints from the group while maintaining backward compatibility with direct panel constraint access.


173-192: LGTM!

The helper functions getPanelConstraintsInPercent and getPanelDataWithPercentConstraints provide a clean abstraction for converting pixel constraints to percentages, enabling consistent internal calculations.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

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.

[Feature]: Add unit / pixel unit for panel size

2 participants