WIP [LUNA-3186]: Make marker prop optional in BpkPriceRange (backwards compatible option)#4131
Conversation
- Updated Props type to make marker optional - Added conditional rendering logic for marker and dot - Moved indicatorPercent calculation into useEffect for better performance - Used useCallback to memoize calcPercentage function - Added comprehensive test coverage (11 tests total) - Created NoMarkerWithLabels and NoMarkerWithoutLabels example components - Updated documentation with usage examples and props table - Verified functionality with Chrome DevTools and Storybook Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
Removed useCallback in favour of simpler arrow function approach. All tests continue to pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
Moved all conditional logic into dotClassName computation instead of duplicating checks at render time. This creates a single source of truth and makes the JSX more readable. Before: Check type for className, then marker && type && !showPriceIndicator for render After: Check all conditions for className, then just dotClassName for render All 11 tests continue to pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
| const [prefilledWidth, setPrefilledWidth] = useState(0); | ||
| const calcPercentage = (current: number) => | ||
| (clamp(current, min, max) - min) / (max - min); | ||
| const indicatorPercent = calcPercentage(marker.percentage); |
There was a problem hiding this comment.
I moved this into the effect where it's used, as it's now conditional on if the marker prop is present.
| if (marker.percentage < segments.low.percentage) { | ||
| if (marker && marker.percentage < segments.low.percentage) { | ||
| type = MARKER_TYPES.LOW; | ||
| } else if (marker.percentage > segments.high.percentage) { | ||
| } else if (marker && marker.percentage > segments.high.percentage) { | ||
| type = MARKER_TYPES.HIGH; | ||
| } else { | ||
| type = MARKER_TYPES.MEDIUM; |
There was a problem hiding this comment.
Defaulting to MEDUIM when the marker isn't provided. I add guards for displaying markers below to prevent this from ever showing. Keeping this as a strictly defined type makes the logic further below simpler.
| const shouldShowMarker = !!marker && showPriceIndicator; | ||
| const shouldShowDot = !!marker && !showPriceIndicator; |
There was a problem hiding this comment.
My thinking was to make the meaning of these conditions explicit, rather than complicate the logic below.
There was a problem hiding this comment.
Pull request overview
This PR makes the marker prop optional in the BpkPriceRange component, enabling display of price range bars without a specific price indicator while maintaining full backward compatibility.
Changes:
- Made
markerprop optional in TypeScript type definition - Added conditional logic to handle undefined marker values throughout the component
- Added comprehensive test coverage including accessibility tests for the no-marker scenario
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/bpk-component-price-range/src/BpkPriceRange.tsx | Updated Props type to make marker optional, added conditional checks for marker usage, and introduced helper variables for conditional rendering |
| packages/bpk-component-price-range/src/BpkPriceRange-test.tsx | Added 4 new unit tests covering rendering without marker, marker value changes, and min/max recalculation |
| packages/bpk-component-price-range/src/accessibility-test.tsx | Added accessibility test for no-marker scenario |
| packages/bpk-component-price-range/README.md | Added documentation for optional marker usage and comprehensive props table |
| examples/bpk-component-price-range/examples.tsx | Created two new example components demonstrating no-marker usage with and without labels |
| examples/bpk-component-price-range/stories.tsx | Exported new example components as Storybook stories |
Comments suppressed due to low confidence (2)
packages/bpk-component-price-range/src/BpkPriceRange.tsx:72
- The variable
typeis used later indotClassNameeven whenmarkeris undefined. This will result intypebeing assignedMARKER_TYPES.MEDIUMwhen marker is undefined, which is incorrect. Consider makingtypeoptional and only assigning it when marker exists, or handle the undefined case explicitly in thedotClassNamelogic.
let type: MarkerType;
if (marker && marker.percentage < segments.low.percentage) {
type = MARKER_TYPES.LOW;
} else if (marker && marker.percentage > segments.high.percentage) {
type = MARKER_TYPES.HIGH;
} else {
type = MARKER_TYPES.MEDIUM;
}
packages/bpk-component-price-range/src/BpkPriceRange.tsx:123
- The
dotClassNameusestypevariable which may beMARKER_TYPES.MEDIUMeven when marker is undefined. This could cause incorrect styling. SincedotClassNameis only used whenshouldShowDotis true (which requires marker), consider moving this className calculation inside a conditional block or only after validating marker exists.
const dotClassName = getClassName(
`bpk-price-range__line--${type}`,
'bpk-price-range__line--dot',
);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
…ake-marker-optional-in-price-range' into feature/LUNA-3186-make-marker-optional-in-price-range
| max?: number; | ||
| showPriceIndicator?: boolean; | ||
| marker: Marker; | ||
| showPriceIndicator?: boolean; // Should be named 'showPriceLabels'. |
There was a problem hiding this comment.
The meaning of this prop has changed with this PR. As marker is now optional, the presence of any form of marker which notes the position of the current price is determined by the presence or absence of the marker prop.
This showPriceIndicator prop controls two things:
- The presence or absence of prices below the change in colour of the bar segments
Example of price below the segments:
Example of no price below the segments
- Weather the price marker tooltip is a dot positioned on the range, or a price tooltip displaying the price of the marker
Example of dot
Example of price marker
Unfortunately, re-naming this prop is a breaking change. We're in the process of raising this issue with Backpack, explaining this problem & forming a plan to re-name this variable (and potentially the name of the marker prop too). In the meantime, we've left this code comment to try and make this clearer.
There was a problem hiding this comment.
|
Visit https://backpack.github.io/storybook-prs/4131 to see this build running in a browser. |
| if (marker && marker.percentage < segments.low.percentage) { | ||
| type = MARKER_TYPES.LOW; | ||
| } else if (marker.percentage > segments.high.percentage) { | ||
| } else if (marker && marker.percentage > segments.high.percentage) { |
There was a problem hiding this comment.
marker && marker.percentage can be written as marker?.percentage.
There was a problem hiding this comment.
See line 102 :-)
| min = 0, | ||
| segments, | ||
| showPriceIndicator = true, | ||
| showPriceIndicator = true, // Should be named 'showPriceLabels'. |
There was a problem hiding this comment.
Are we keeping these comments? What's the reason behind having a preference for a different name?
There was a problem hiding this comment.
not sure we should keep this comment but here's rationale behind preference #4131 (comment)
There was a problem hiding this comment.
My thinking was yes, as we think that the showPriceIndicator name is a bit confusing. Changing the name is a breaking change though, which we thought was unnecessarily complex for what we're trying to do for price bands.
The thinking was that this comment could suggest that this prop actually is in control of showing price labels, rather than the indicator itself (hence the preference for a different name).
There was a problem hiding this comment.
Rob and I had a quick call to discuss this: my initial assumption against a breaking change would slow us down was false: we'll have to bump the version of backpack anyway. We're now leaning towards making the breaking change, provided if we think that it's necessary to make this name change. Rob's having a think about this, and we'll circle back to it tomorrow.
|
Closing this, as we've decided to go with a different option (#4158) |

Summary
Makes the
markerprop optional in the BpkPriceRange component. When the marker prop is omitted, the component displays only the three-tier price range bars (low/medium/high segments) without any marker, dot, or badge.This lets us display price bands without a specific price indicator, whilst maintaining full backward compatibility with existing usage.
Changes
Core Component Updates
markerprop optional in the Props type definitiondotClassNameconditional on type being definedExamples
Price range with marker provided
showPriceIndicator = true(default)With
showPriceIndicator = falsePrice range with marker missing
showPriceIndicator = true(default)With
showPriceIndicator = false(Luna don't need this, but this is introduced by this PR)Test Coverage
Examples and Stories
NoMarkerWithLabelsExample- Shows bars with segment price labelsNoMarkerWithoutLabelsExample- Shows only bars (cleanest UI)Documentation
Verification
Accessibility
Breaking Changes
None. This is a purely additive change with full backward compatibility.
References
🤖 Generated with Claude Code