From e01c7d728575fcbc03d7371acbcf1071e735dbbc Mon Sep 17 00:00:00 2001 From: ShaneK Date: Fri, 7 Mar 2025 11:36:42 -0800 Subject: [PATCH] fix(range): handling the case where range would return NaN if max or min were set to undefined by setting max and min to their default values if you try to set them directly to undefined --- core/src/components/range/range.tsx | 18 +++++++++++++++--- core/src/components/range/test/range.spec.ts | 17 +++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index da4c2d7534..830e185a5e 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -2,7 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil/core'; import { findClosestIonContent, disableContentScrollY, resetContentScrollY } from '@utils/content'; import type { Attributes } from '@utils/helpers'; -import { inheritAriaAttributes, clamp, debounceEvent, renderHiddenInput } from '@utils/helpers'; +import { inheritAriaAttributes, clamp, debounceEvent, renderHiddenInput, isSafeNumber } from '@utils/helpers'; import { printIonWarning } from '@utils/logging'; import { isRTL } from '@utils/rtl'; import { createColorClasses, hostContext } from '@utils/theme'; @@ -109,7 +109,11 @@ export class Range implements ComponentInterface { */ @Prop() min = 0; @Watch('min') - protected minChanged() { + protected minChanged(newValue: number) { + if (!isSafeNumber(newValue)) { + this.min = 0; + } + if (!this.noUpdate) { this.updateRatio(); } @@ -120,7 +124,11 @@ export class Range implements ComponentInterface { */ @Prop() max = 100; @Watch('max') - protected maxChanged() { + protected maxChanged(newValue: number) { + if (!isSafeNumber(newValue)) { + this.max = 100; + } + if (!this.noUpdate) { this.updateRatio(); } @@ -300,6 +308,10 @@ export class Range implements ComponentInterface { } this.inheritedAttributes = inheritAriaAttributes(this.el); + // If the min or max is not safe, set it to 0 or 100 respectively. + // Our watch does this, but not before the initial load. + this.min = isSafeNumber(this.min) ? this.min : 0; + this.max = isSafeNumber(this.max) ? this.max : 100; } componentDidLoad() { diff --git a/core/src/components/range/test/range.spec.ts b/core/src/components/range/test/range.spec.ts index 8698f9bbf0..557d09814d 100644 --- a/core/src/components/range/test/range.spec.ts +++ b/core/src/components/range/test/range.spec.ts @@ -28,6 +28,23 @@ describe('Range', () => { }); }); + it('should handle undefined min and max values by falling back to defaults', async () => { + const page = await newSpecPage({ + components: [Range], + html: ` +
Range
+
`, + }); + + const range = page.body.querySelector('ion-range')!; + // Here we have to cast this to any, but in its react wrapper it accepts undefined as a valid value + range.min = undefined as any; + range.max = undefined as any; + await page.waitForChanges(); + expect(range.min).toBe(0); + expect(range.max).toBe(100); + }); + it('should return the clamped value for a range dual knob component', () => { sharedRange.min = 0; sharedRange.max = 100;