feat: add nodeInset and nodeGap properties to Treemap for better la…#7044
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds Treemap spacing controls: new public props Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/chart/Treemap.tsx (2)
122-128: Missing explicit return type ongetTreemapRenderHeight.Suggested fix
-const getTreemapRenderHeight = (height: number, type: Props['type']) => { +const getTreemapRenderHeight = (height: number, type: Props['type']): number => {As per coding guidelines: "Type function parameters and return values explicitly."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/chart/Treemap.tsx` around lines 122 - 128, The function getTreemapRenderHeight lacks an explicit return type; add an explicit return type of number to its signature (e.g., getTreemapRenderHeight = (height: number, type: Props['type']): number => ...) so the function's return value is statically typed; update the declaration in Treemap.tsx where getTreemapRenderHeight is defined and ensure the return paths (both the height - NEST_INDEX_HEIGHT and height) conform to number.
458-468: JSDoc descriptions fornodePaddingandnodeGapare too vague for autogenerated API docs.
nodePaddingis described as "The padding between the nodes" but it actually insets the layout area used for a node's children (parent-child inset).nodeGapis described as "The gap between the nodes" but specifically applies between sibling nodes at the same depth. Since these JSDoc comments drive the autogenerated API docs, they should clearly communicate the distinction.📝 Suggested JSDoc improvement
/** - * The padding between the nodes. + * Insets the layout area used for a node's children, creating visual separation between parent and child nodes. * `@default` 0 */ nodePadding?: number; /** - * The gap between the nodes. + * Spacing between sibling nodes at the same depth. * `@default` 0 */ nodeGap?: number;As per coding guidelines: "JSDoc comments and TypeScript definitions in source files must be kept up-to-date as they are used to autogenerate API documentation via 'npm run omnidoc'"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/chart/Treemap.tsx` around lines 458 - 468, Update the JSDoc for the nodePadding and nodeGap props in Treemap.tsx to clearly differentiate their behavior: change the nodePadding description (nodePadding?: number) to state that it insets the layout area used for a node’s children (i.e., a parent-to-children inset), and change the nodeGap description (nodeGap?: number) to state that it controls the spacing between sibling nodes at the same depth (i.e., gap between adjacent children). Keep the default values and type annotations unchanged, but make the descriptions explicit so autogenerated docs reflect the parent-child inset vs sibling-gap distinction.test/chart/Treemap.spec.tsx (1)
13-28: Consider adding a test combiningnodePaddingandnodeGaptogether.Currently padding and gap are tested in isolation. A single test with
multiLevelInsetDatausing bothnodePadding={8}andnodeGap={6}would verify no interference between the two features. Not urgent since the story exercises both and the algorithm applies them independently.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/chart/Treemap.spec.tsx` around lines 13 - 28, Add a new test in Treemap.spec.tsx that renders the Treemap with multiLevelInsetData and both nodePadding={8} and nodeGap={6} to ensure they don't interfere; use the same rendering helper as other tests (e.g., the test's renderTreemap or renderWithProviders) to mount the tree, then assert that expected nodes (like "Root A", "A1", "A1a") are present and that their bounding boxes/positions reflect separation (e.g., non-overlapping rects or distinct x/y/top/left values) to confirm both padding and gap are applied concurrently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx`:
- Around line 73-92: The fill index calculation in
renderNodeGapAndPaddingContent can reference colors[5] because it multiplies by
a hardcoded 6 while colors has only 5 entries; update the expression used to
pick a color so it uses colors.length (and/or clamps the computed index to
colors.length - 1) instead of the literal 6 to avoid undefined fills for
TreemapNode rendering.
---
Nitpick comments:
In `@src/chart/Treemap.tsx`:
- Around line 122-128: The function getTreemapRenderHeight lacks an explicit
return type; add an explicit return type of number to its signature (e.g.,
getTreemapRenderHeight = (height: number, type: Props['type']): number => ...)
so the function's return value is statically typed; update the declaration in
Treemap.tsx where getTreemapRenderHeight is defined and ensure the return paths
(both the height - NEST_INDEX_HEIGHT and height) conform to number.
- Around line 458-468: Update the JSDoc for the nodePadding and nodeGap props in
Treemap.tsx to clearly differentiate their behavior: change the nodePadding
description (nodePadding?: number) to state that it insets the layout area used
for a node’s children (i.e., a parent-to-children inset), and change the nodeGap
description (nodeGap?: number) to state that it controls the spacing between
sibling nodes at the same depth (i.e., gap between adjacent children). Keep the
default values and type annotations unchanged, but make the descriptions
explicit so autogenerated docs reflect the parent-child inset vs sibling-gap
distinction.
In `@test/chart/Treemap.spec.tsx`:
- Around line 13-28: Add a new test in Treemap.spec.tsx that renders the Treemap
with multiLevelInsetData and both nodePadding={8} and nodeGap={6} to ensure they
don't interfere; use the same rendering helper as other tests (e.g., the test's
renderTreemap or renderWithProviders) to mount the tree, then assert that
expected nodes (like "Root A", "A1", "A1a") are present and that their bounding
boxes/positions reflect separation (e.g., non-overlapping rects or distinct
x/y/top/left values) to confirm both padding and gap are applied concurrently.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/chart/Treemap.tsxstorybook/stories/API/chart/Treemap.stories.tsxtest/chart/Treemap.spec.tsxtest/chart/Treemap.typed.spec.tsxwww/src/docs/apiExamples/Treemap/index.tsxwww/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsxwww/src/docs/exampleComponents/TreeMap/index.ts
Bundle ReportChanges will increase total bundle size by 7.62kB (0.15%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: recharts/bundle-es6Assets Changed:
view changes for bundle: recharts/bundle-cjsAssets Changed:
view changes for bundle: recharts/bundle-treeshaking-treemapAssets Changed:
view changes for bundle: recharts/bundle-umdAssets Changed:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7044 +/- ##
==========================================
+ Coverage 89.63% 89.68% +0.04%
==========================================
Files 536 537 +1
Lines 40488 40673 +185
Branches 5525 5548 +23
==========================================
+ Hits 36290 36476 +186
+ Misses 4190 4189 -1
Partials 8 8 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx (1)
88-88: The* 5fix resolves the out-of-bounds bug, but was previously recommended to use* colors.lengthinstead.The previously flagged
* 6was changed to* 5, which preventscolors[5] === undefined, but the agreed fix was to usecolors.lengthfor resilience against future palette changes.♻️ Proposed fix
- fill: depth < 2 ? colors[Math.floor((index / (root?.children?.length ?? 1)) * 5)] : '#ffffff00', + fill: depth < 2 ? colors[Math.floor((index / (root?.children?.length ?? 1)) * colors.length)] : '#ffffff00',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx` at line 88, Replace the hardcoded multiplier 5 with the palette's length to avoid out-of-bounds access: when computing the color index inside TreemapWithPaddingAndGaps (the expression using colors[Math.floor((index / (root?.children?.length ?? 1)) * 5)]), use colors.length instead of 5 so the computed index is always within colors' bounds (refer to symbols colors, index, root?.children?.length, and the fill assignment).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx`:
- Line 88: Replace the hardcoded multiplier 5 with the palette's length to avoid
out-of-bounds access: when computing the color index inside
TreemapWithPaddingAndGaps (the expression using colors[Math.floor((index /
(root?.children?.length ?? 1)) * 5)]), use colors.length instead of 5 so the
computed index is always within colors' bounds (refer to symbols colors, index,
root?.children?.length, and the fill assignment).
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
test-vr/__snapshots__/tests/Treemap.spec-vr.tsx-snapshots/nested-treemap-1-chromium-linux.pngis excluded by!**/*.pngtest-vr/__snapshots__/tests/Treemap.spec-vr.tsx-snapshots/nested-treemap-1-firefox-linux.pngis excluded by!**/*.pngtest-vr/__snapshots__/tests/Treemap.spec-vr.tsx-snapshots/nested-treemap-1-webkit-linux.pngis excluded by!**/*.pngtest-vr/__snapshots__/tests/www/TreemapApiExamples.spec-vr.tsx-snapshots/TreemapWithPaddingAndGaps-1-chromium-linux.pngis excluded by!**/*.pngtest-vr/__snapshots__/tests/www/TreemapApiExamples.spec-vr.tsx-snapshots/TreemapWithPaddingAndGaps-1-firefox-linux.pngis excluded by!**/*.pngtest-vr/__snapshots__/tests/www/TreemapApiExamples.spec-vr.tsx-snapshots/TreemapWithPaddingAndGaps-1-webkit-linux.pngis excluded by!**/*.png
📒 Files selected for processing (2)
test-vr/tests/www/TreemapApiExamples.spec-vr.tsxwww/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx (1)
88-88: Prefercolors.lengthover the hardcoded5for maintainability.The previous OOB issue (using
* 6with a 5-entry array) was fixed by changing to* 5, butcolors.lengthwould be the more maintainable fix as agreed in the earlier review thread.♻️ Proposed refactor
- fill: depth < 2 ? colors[Math.floor((index / (root?.children?.length ?? 1)) * 5)] : '#ffffff00', + fill: depth < 2 ? colors[Math.floor((index / (root?.children?.length ?? 1)) * colors.length)] : '#ffffff00',🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx` at line 88, Replace the hardcoded "5" with the actual colors array length to keep the color selection maintainable: in the TreemapWithPaddingAndGaps component change the fill calculation that currently uses "Math.floor((index / (root?.children?.length ?? 1)) * 5)" to use "colors.length" (e.g., Math.floor((index / (root?.children?.length ?? 1)) * colors.length)); reference the variables colors, index, and root to locate the expression and ensure the colors.length value is used instead of the magic number.
🧹 Nitpick comments (2)
src/chart/Treemap.tsx (2)
191-204:insetRectlogic is correct — minor note on redundant safeguard.
clampedPadding = Math.min(nodeInset, rect.width / 2, rect.height / 2)already guaranteeswidth - 2*clampedPadding ≥ 0, so the subsequentMath.max(..., 0)is technically redundant. It's harmless defensive coding, but worth noting if you ever decide to simplify.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/chart/Treemap.tsx` around lines 191 - 204, The insetRect function currently uses Math.max(..., 0) when computing width/height even though clampedPadding = Math.min(nodeInset, rect.width / 2, rect.height / 2) guarantees width - 2*clampedPadding and height - 2*clampedPadding are non-negative; simplify by removing the redundant Math.max guards and directly return width: rect.width - clampedPadding * 2 and height: rect.height - clampedPadding * 2 in insetRect to reduce unnecessary defensive code while keeping the clampedPadding calculation and early-return behavior intact.
120-128:NEST_INDEX_HEIGHTis silently coupled torenderNestIndex's DOM height — add a clarifying comment.The constant
30must match whatever the.recharts-treemap-nest-index-wrapperelement actually occupies. If the nest-index styles change (font-size, padding, margin), this constant needs to be updated manually. A comment cross-referencingrenderNestIndexwould prevent future drift.💬 Suggested comment
-const NEST_INDEX_HEIGHT = 30; +/** Height reserved for the breadcrumb/nest-index bar rendered by `renderNestIndex()`. + * Must be kept in sync with the inline styles on `.recharts-treemap-nest-index-wrapper`. */ +const NEST_INDEX_HEIGHT = 30;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/chart/Treemap.tsx` around lines 120 - 128, NEST_INDEX_HEIGHT (used by getTreemapRenderHeight) is tightly coupled to the actual DOM height of the element created by renderNestIndex (the .recharts-treemap-nest-index-wrapper); add a concise comment above the NEST_INDEX_HEIGHT declaration stating that the numeric value must match the rendered height of .recharts-treemap-nest-index-wrapper (and reference renderNestIndex) and note that changes to its font-size/padding/margin require updating this constant or switching to a measured/ref-based approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/chart/Treemap.spec.tsx`:
- Line 287: The test uses the wrong DOM element type when querying the treemap
cell: change the generic on the querySelector call for currentRootCell from
SVGPathElement to SVGRectElement so the cast matches the rendered <rect>; update
the expression that creates currentRootCell (the querySelector for
'.recharts-treemap-depth-0 .recharts-rectangle') to
querySelector<SVGRectElement> and keep the rest of the test (e.g.,
fireEvent.click) unchanged.
- Around line 62-206: Add test timer setup/teardown to the new tests: call
vi.useFakeTimers() at the start of each affected test (e.g., the tests titled
"uses the same drawing height for nest layout and surface", "renders nested
children directly on top of parent when nodeInset is not set", "insets nested
children when nodeInset is set", "renders sibling nodes without spacing when
nodeGap is not set", and "adds spacing between sibling nodes when nodeGap is
set") before rendering the Treemap, and call vi.runOnlyPendingTimers()
immediately after the render(...) call in each test to flush pending timers;
ensure you do not call vi.runAllTimers(). Also add vi.useRealTimers() in an
afterEach or at the end of each test if tests rely on real timers elsewhere.
In `@www/test/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.spec.tsx`:
- Around line 1-27: The test for renderNodeGapAndPaddingContent is missing the
required fake-timer setup; call vi.useFakeTimers() before rendering in the test
(e.g., at the start of the 'renders leaf labels...' it block) and call
vi.runOnlyPendingTimers() immediately after the
render(<svg>{renderNodeGapAndPaddingContent(node as any)}</svg>) to flush any
pending timers from Redux autoBatchEnhancer; optionally restore timers after the
test with vi.useRealTimers() if needed.
- Line 20: The test is using an unsafe any cast for the node passed to
renderNodeGapAndPaddingContent; instead, either populate the missing required
TreemapNode fields (e.g., value and tooltipIndex) on the node fixture so it is a
valid TreemapNode, or replace the cast with a safe partial cast such as casting
node as Partial<TreemapNode> and then narrowing (e.g., node as unknown as
TreemapNode) before calling renderNodeGapAndPaddingContent to document the
intent and avoid using any; update the variable named node and the call site of
renderNodeGapAndPaddingContent accordingly.
---
Duplicate comments:
In `@www/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsx`:
- Line 88: Replace the hardcoded "5" with the actual colors array length to keep
the color selection maintainable: in the TreemapWithPaddingAndGaps component
change the fill calculation that currently uses "Math.floor((index /
(root?.children?.length ?? 1)) * 5)" to use "colors.length" (e.g.,
Math.floor((index / (root?.children?.length ?? 1)) * colors.length)); reference
the variables colors, index, and root to locate the expression and ensure the
colors.length value is used instead of the magic number.
---
Nitpick comments:
In `@src/chart/Treemap.tsx`:
- Around line 191-204: The insetRect function currently uses Math.max(..., 0)
when computing width/height even though clampedPadding = Math.min(nodeInset,
rect.width / 2, rect.height / 2) guarantees width - 2*clampedPadding and height
- 2*clampedPadding are non-negative; simplify by removing the redundant Math.max
guards and directly return width: rect.width - clampedPadding * 2 and height:
rect.height - clampedPadding * 2 in insetRect to reduce unnecessary defensive
code while keeping the clampedPadding calculation and early-return behavior
intact.
- Around line 120-128: NEST_INDEX_HEIGHT (used by getTreemapRenderHeight) is
tightly coupled to the actual DOM height of the element created by
renderNestIndex (the .recharts-treemap-nest-index-wrapper); add a concise
comment above the NEST_INDEX_HEIGHT declaration stating that the numeric value
must match the rendered height of .recharts-treemap-nest-index-wrapper (and
reference renderNestIndex) and note that changes to its font-size/padding/margin
require updating this constant or switching to a measured/ref-based approach.
ℹ️ Review info
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/chart/Treemap.tsxstorybook/stories/API/chart/Treemap.stories.tsxtest/chart/Treemap.spec.tsxtest/chart/Treemap.typed.spec.tsxwww/src/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.tsxwww/test/docs/exampleComponents/TreeMap/TreemapWithPaddingAndGaps.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- test/chart/Treemap.typed.spec.tsx
|
Hi @PavelVanecek, sorry I've been a bit busy with work/personal stuff so I haven't been able to pay attention to this for a bit. I noticed that you pushed a fix to the remaining issues, so thanks for that! Now this branch is passing all of the CI checks, is there anything else necessary to get it to the point that it can be merged? |
|
All done here @MaximSrour, we have quite a few PRs open so I am merging them one by one. |
|
No worries, totally understandable! Just wanted to make sure that I wasn't missing anything :) Thanks for the support on this one! |
…pacing-props-to-treemap
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/chart/Treemap.tsx (1)
120-128: Good refactoring, but add explicit return type.Extracting the magic number
30intoNEST_INDEX_HEIGHTimproves readability. Per coding guidelines, add an explicit return type annotation.Suggested fix
-const getTreemapRenderHeight = (height: number, type: Props['type']) => { +const getTreemapRenderHeight = (height: number, type: Props['type']): number => { if (type === 'nest') { return height - NEST_INDEX_HEIGHT; } return height; };As per coding guidelines: "Type function parameters and return values explicitly."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/chart/Treemap.tsx` around lines 120 - 128, The helper getTreemapRenderHeight currently lacks an explicit return type; add a return type annotation of number to the function signature (i.e., change getTreemapRenderHeight = (height: number, type: Props['type']) => { ... } to explicitly return number) so the function and its use of NEST_INDEX_HEIGHT remain properly typed and satisfy the coding guideline requiring explicit parameter and return types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/chart/Treemap.tsx`:
- Around line 120-128: The helper getTreemapRenderHeight currently lacks an
explicit return type; add a return type annotation of number to the function
signature (i.e., change getTreemapRenderHeight = (height: number, type:
Props['type']) => { ... } to explicitly return number) so the function and its
use of NEST_INDEX_HEIGHT remain properly typed and satisfy the coding guideline
requiring explicit parameter and return types.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 93f99b7c-f3c9-479c-9557-ac9632c46b24
📒 Files selected for processing (1)
src/chart/Treemap.tsx
Description
This PR improves Treemap layout by introducing configurable spacing for hierarchical nodes and adds documentation/examples to demonstrate the behavior.
Related Issue
Closes #7043
Motivation and Context
Treemap currently renders child nodes directly on top of parents (covering them entirely) and flush against siblings. This change adds explicit controls for:
nodeInset),nodeGap),to improve readability in dense hierarchical datasets and enable clearer visual grouping without requiring custom geometry logic from users.
How Has This Been Tested?
I ran the entire test suite using:
npm run testnpm run test-storybooknpm run test-vrRan mutation tests on the modified files
Also validated visually using the created storybooks and the documentation example.
Screenshots (if appropriate):
In flat mode:
In nested mode:
In documentation site:
Types of changes
Checklist:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests