diff --git a/core/src/components/range/range.tsx b/core/src/components/range/range.tsx index eac3dd3ebcd..d39e9732e82 100644 --- a/core/src/components/range/range.tsx +++ b/core/src/components/range/range.tsx @@ -639,6 +639,51 @@ export class Range implements ComponentInterface { } }; + private onKnobFocus = (knob: KnobName) => { + if (!this.hasFocus) { + this.hasFocus = true; + this.ionFocus.emit(); + } + + // Manually manage ion-focused class for dual knobs + if (this.dualKnobs && this.el.shadowRoot) { + const knobA = this.el.shadowRoot.querySelector('.range-knob-a'); + const knobB = this.el.shadowRoot.querySelector('.range-knob-b'); + + // Remove ion-focused from both knobs first + knobA?.classList.remove('ion-focused'); + knobB?.classList.remove('ion-focused'); + + // Add ion-focused only to the focused knob + const focusedKnobEl = knob === 'A' ? knobA : knobB; + focusedKnobEl?.classList.add('ion-focused'); + } + }; + + private onKnobBlur = () => { + // Check if focus is moving to another knob within the same range + // by delaying the reset to allow the new focus to register + setTimeout(() => { + const activeElement = this.el.shadowRoot?.activeElement; + const isStillFocusedOnKnob = activeElement && activeElement.classList.contains('range-knob-handle'); + + if (!isStillFocusedOnKnob) { + if (this.hasFocus) { + this.hasFocus = false; + this.ionBlur.emit(); + } + + // Remove ion-focused from both knobs when focus leaves the range + if (this.dualKnobs && this.el.shadowRoot) { + const knobA = this.el.shadowRoot.querySelector('.range-knob-a'); + const knobB = this.el.shadowRoot.querySelector('.range-knob-b'); + knobA?.classList.remove('ion-focused'); + knobB?.classList.remove('ion-focused'); + } + } + }, 0); + }; + /** * Returns true if content was passed to the "start" slot */ @@ -813,6 +858,8 @@ export class Range implements ComponentInterface { min, max, inheritedAttributes, + onKnobFocus: this.onKnobFocus, + onKnobBlur: this.onKnobBlur, })} {this.dualKnobs && @@ -828,6 +875,8 @@ export class Range implements ComponentInterface { min, max, inheritedAttributes, + onKnobFocus: this.onKnobFocus, + onKnobBlur: this.onKnobBlur, })} ); @@ -908,11 +957,27 @@ interface RangeKnob { pinFormatter: PinFormatter; inheritedAttributes: Attributes; handleKeyboard: (name: KnobName, isIncrease: boolean) => void; + onKnobFocus: (knob: KnobName) => void; + onKnobBlur: () => void; } const renderKnob = ( rtl: boolean, - { knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard, pinFormatter, inheritedAttributes }: RangeKnob + { + knob, + value, + ratio, + min, + max, + disabled, + pressed, + pin, + handleKeyboard, + pinFormatter, + inheritedAttributes, + onKnobFocus, + onKnobBlur, + }: RangeKnob ) => { const start = rtl ? 'right' : 'left'; @@ -941,6 +1006,8 @@ const renderKnob = ( ev.stopPropagation(); } }} + onFocus={() => onKnobFocus(knob)} + onBlur={onKnobBlur} class={{ 'range-knob-handle': true, 'range-knob-a': knob === 'A', diff --git a/core/src/components/range/test/basic/index.html b/core/src/components/range/test/basic/index.html index 50a7ad05197..98370423f06 100644 --- a/core/src/components/range/test/basic/index.html +++ b/core/src/components/range/test/basic/index.html @@ -80,6 +80,10 @@