@ionic/core 8.7.17-dev.11771359170.1fda0949 → 8.7.17-dev.11771865171.14f4c2cf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1579,11 +1579,11 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1579
1579
  const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
1580
1580
  // don't use the inheritAttributes util because it removes dir from the host, and we still need that
1581
1581
  const hostDir = this.el.getAttribute('dir') || undefined;
1582
- return (h("div", { class: "calendar-header", part: "calendar-header" }, h("div", { class: "calendar-action-buttons" }, h("div", { class: "calendar-month-year" }, h("button", { class: {
1582
+ return (h("div", { class: "calendar-header" }, h("div", { class: "calendar-action-buttons" }, h("div", { class: "calendar-month-year" }, h("button", { class: {
1583
1583
  'calendar-month-year-toggle': true,
1584
1584
  'ion-activatable': true,
1585
1585
  'ion-focusable': true,
1586
- }, part: "month-year-button", disabled: disabled, "aria-label": this.showMonthAndYear ? 'Hide year picker' : 'Show year picker', onClick: () => this.toggleMonthAndYearView() }, h("span", { id: "toggle-wrapper" }, getMonthAndYear(this.locale, this.workingParts), h("ion-icon", { "aria-hidden": "true", icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false, flipRtl: true })), mode === 'md' && h("ion-ripple-effect", null))), h("div", { class: "calendar-next-prev" }, h("ion-buttons", null, h("ion-button", { "aria-label": "Previous month", disabled: prevMonthDisabled, onClick: () => this.prevMonth(), part: "prev-next-buttons prev-button" }, h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronBack, lazy: false, flipRtl: true })), h("ion-button", { "aria-label": "Next month", disabled: nextMonthDisabled, onClick: () => this.nextMonth(), part: "prev-next-buttons next-button" }, h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronForward, lazy: false, flipRtl: true }))))), h("div", { class: "calendar-days-of-week", "aria-hidden": "true", part: "days-of-week" }, getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
1586
+ }, part: "month-year-button", disabled: disabled, "aria-label": this.showMonthAndYear ? 'Hide year picker' : 'Show year picker', onClick: () => this.toggleMonthAndYearView() }, h("span", { id: "toggle-wrapper" }, getMonthAndYear(this.locale, this.workingParts), h("ion-icon", { "aria-hidden": "true", icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false, flipRtl: true })), mode === 'md' && h("ion-ripple-effect", null))), h("div", { class: "calendar-next-prev" }, h("ion-buttons", null, h("ion-button", { "aria-label": "Previous month", disabled: prevMonthDisabled, onClick: () => this.prevMonth() }, h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronBack, lazy: false, flipRtl: true })), h("ion-button", { "aria-label": "Next month", disabled: nextMonthDisabled, onClick: () => this.nextMonth() }, h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronForward, lazy: false, flipRtl: true }))))), h("div", { class: "calendar-days-of-week", "aria-hidden": "true" }, getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
1587
1587
  return h("div", { class: "day-of-week" }, d);
1588
1588
  }))));
1589
1589
  }
@@ -1815,7 +1815,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1815
1815
  if (!hasSlottedTitle && !this.showDefaultTitle) {
1816
1816
  return;
1817
1817
  }
1818
- return (h("div", { class: "datetime-header", part: "datetime-header" }, h("div", { class: "datetime-title" }, h("slot", { name: "title" }, "Select Date")), showExpandedHeader && h("div", { class: "datetime-selected-date" }, this.getHeaderSelectedDateText())));
1818
+ return (h("div", { class: "datetime-header" }, h("div", { class: "datetime-title" }, h("slot", { name: "title" }, "Select Date")), showExpandedHeader && h("div", { class: "datetime-selected-date" }, this.getHeaderSelectedDateText())));
1819
1819
  }
1820
1820
  /**
1821
1821
  * Render time picker inside of datetime.
@@ -1895,7 +1895,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1895
1895
  const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
1896
1896
  const hasWheelVariant = hasDatePresentation && preferWheel;
1897
1897
  renderHiddenInput(true, el, name, formatValue(value), disabled);
1898
- return (h(Host, { key: '3d0787ecb3ad104c4a60d68a6e57140f018a70f2', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
1898
+ return (h(Host, { key: '19e20c9b6b5f9467e91a2567b6dc7d9d38b56cc3', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses(color, {
1899
1899
  [mode]: true,
1900
1900
  ['datetime-readonly']: readonly,
1901
1901
  ['datetime-disabled']: disabled,
@@ -1905,7 +1905,7 @@ const Datetime = /*@__PURE__*/ proxyCustomElement(class Datetime extends HTMLEle
1905
1905
  [`datetime-size-${size}`]: true,
1906
1906
  [`datetime-prefer-wheel`]: hasWheelVariant,
1907
1907
  [`datetime-grid`]: isGridStyle,
1908
- })) }, h("div", { key: '6b245a0033d5ddd1918bc839f142141bf5ec54c5', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1908
+ })) }, h("div", { key: 'e31b5ef76cd6262dafd39f2d21980887880ec32e', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1909
1909
  }
1910
1910
  get el() { return this; }
1911
1911
  static get watchers() { return {
@@ -79,6 +79,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
79
79
  this.inheritedAttributes = {};
80
80
  this.contentEl = null;
81
81
  this.initialContentScrollY = true;
82
+ this.focusFromPointer = false;
82
83
  this.ratioA = 0;
83
84
  this.ratioB = 0;
84
85
  /**
@@ -188,6 +189,29 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
188
189
  this.gesture.enable(!this.disabled);
189
190
  }
190
191
  };
192
+ /**
193
+ * Observes the knob handles for the ion-activated class and syncs
194
+ * activatedKnob so the activated part is correctly set on the handle,
195
+ * knob, and pin.
196
+ */
197
+ this.setupActivatedObserver = () => {
198
+ const knobHandleA = this.el.shadowRoot.querySelector('.range-knob-handle-a');
199
+ const knobHandleB = this.el.shadowRoot.querySelector('.range-knob-handle-b');
200
+ const syncActivated = () => {
201
+ this.activatedKnob = (knobHandleA === null || knobHandleA === void 0 ? void 0 : knobHandleA.classList.contains('ion-activated'))
202
+ ? 'A'
203
+ : (knobHandleB === null || knobHandleB === void 0 ? void 0 : knobHandleB.classList.contains('ion-activated'))
204
+ ? 'B'
205
+ : undefined;
206
+ };
207
+ this.activatedObserver = new MutationObserver(syncActivated);
208
+ this.activatedObserver.observe(this.el.shadowRoot, {
209
+ attributes: true,
210
+ attributeFilter: ['class'],
211
+ subtree: true,
212
+ });
213
+ syncActivated();
214
+ };
191
215
  this.handleKeyboard = (knob, isIncrease) => {
192
216
  const { ensureValueInBounds } = this;
193
217
  let step = this.step;
@@ -210,6 +234,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
210
234
  this.onBlur = () => {
211
235
  if (this.hasFocus) {
212
236
  this.hasFocus = false;
237
+ this.focusedKnob = undefined;
213
238
  this.ionBlur.emit();
214
239
  }
215
240
  };
@@ -220,21 +245,20 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
220
245
  }
221
246
  };
222
247
  this.onKnobFocus = (knob) => {
248
+ // Clicking focuses the range which is needed for the keyboard,
249
+ // but we only want to add the ion-focused class when focused via Tab.
250
+ if (!this.focusFromPointer) {
251
+ this.focusedKnob = knob;
252
+ }
253
+ else {
254
+ this.focusFromPointer = false;
255
+ this.focusedKnob = undefined;
256
+ }
257
+ // If the knob was not already focused, emit the focus event
223
258
  if (!this.hasFocus) {
224
259
  this.hasFocus = true;
225
260
  this.ionFocus.emit();
226
261
  }
227
- // Manually manage ion-focused class for dual knobs
228
- if (this.dualKnobs && this.el.shadowRoot) {
229
- const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
230
- const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
231
- // Remove ion-focused from both knobs first
232
- knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
233
- knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
234
- // Add ion-focused only to the focused knob
235
- const focusedKnobEl = knob === 'A' ? knobA : knobB;
236
- focusedKnobEl === null || focusedKnobEl === void 0 ? void 0 : focusedKnobEl.classList.add('ion-focused');
237
- }
238
262
  };
239
263
  this.onKnobBlur = () => {
240
264
  // Check if focus is moving to another knob within the same range
@@ -246,18 +270,18 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
246
270
  if (!isStillFocusedOnKnob) {
247
271
  if (this.hasFocus) {
248
272
  this.hasFocus = false;
273
+ this.focusedKnob = undefined;
249
274
  this.ionBlur.emit();
250
275
  }
251
- // Remove ion-focused from both knobs when focus leaves the range
252
- if (this.dualKnobs && this.el.shadowRoot) {
253
- const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
254
- const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
255
- knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
256
- knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
257
- }
258
276
  }
259
277
  }, 0);
260
278
  };
279
+ this.onKnobMouseEnter = (knob) => {
280
+ this.hoveredKnob = knob;
281
+ };
282
+ this.onKnobMouseLeave = () => {
283
+ this.hoveredKnob = undefined;
284
+ };
261
285
  }
262
286
  debounceChanged() {
263
287
  const { ionInput, debounce, originalIonInput } = this;
@@ -334,6 +358,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
334
358
  this.originalIonInput = this.ionInput;
335
359
  this.setupGesture();
336
360
  this.updateRatio();
361
+ this.setupActivatedObserver();
337
362
  this.didLoad = true;
338
363
  }
339
364
  connectedCallback() {
@@ -359,6 +384,10 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
359
384
  this.gesture.destroy();
360
385
  this.gesture = undefined;
361
386
  }
387
+ if (this.activatedObserver) {
388
+ this.activatedObserver.disconnect();
389
+ this.activatedObserver = undefined;
390
+ }
362
391
  }
363
392
  getValue() {
364
393
  var _a;
@@ -511,7 +540,6 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
511
540
  ratio = 1 - ratio;
512
541
  }
513
542
  this.pressedKnob = !this.dualKnobs || Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio) ? 'A' : 'B';
514
- this.setFocus(this.pressedKnob);
515
543
  }
516
544
  get valA() {
517
545
  return ratioToValue(this.ratioA, this.min, this.max, this.step);
@@ -538,9 +566,23 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
538
566
  updateRatio() {
539
567
  const value = this.getValue();
540
568
  const { min, max } = this;
569
+ /**
570
+ * For dual knobs, value gives lower/upper but not which is A vs B.
571
+ * Assign (lowerRatio, upperRatio) to (ratioA, ratioB) in the way that
572
+ * minimizes change from the current ratios so the knobs don't swap.
573
+ */
541
574
  if (this.dualKnobs) {
542
- this.ratioA = valueToRatio(value.lower, min, max);
543
- this.ratioB = valueToRatio(value.upper, min, max);
575
+ const lowerRatio = valueToRatio(value.lower, min, max);
576
+ const upperRatio = valueToRatio(value.upper, min, max);
577
+ if (Math.abs(this.ratioA - lowerRatio) + Math.abs(this.ratioB - upperRatio) <=
578
+ Math.abs(this.ratioA - upperRatio) + Math.abs(this.ratioB - lowerRatio)) {
579
+ this.ratioA = lowerRatio;
580
+ this.ratioB = upperRatio;
581
+ }
582
+ else {
583
+ this.ratioA = upperRatio;
584
+ this.ratioB = lowerRatio;
585
+ }
544
586
  }
545
587
  else {
546
588
  this.ratioA = valueToRatio(value, min, max);
@@ -557,14 +599,6 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
557
599
  };
558
600
  this.noUpdate = false;
559
601
  }
560
- setFocus(knob) {
561
- if (this.el.shadowRoot) {
562
- const knobEl = this.el.shadowRoot.querySelector(knob === 'A' ? '.range-knob-a' : '.range-knob-b');
563
- if (knobEl) {
564
- knobEl.focus();
565
- }
566
- }
567
- }
568
602
  /**
569
603
  * Returns true if content was passed to the "start" slot
570
604
  */
@@ -582,7 +616,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
582
616
  }
583
617
  renderRangeSlider() {
584
618
  var _a;
585
- const { min, max, step, handleKeyboard, pressedKnob, disabled, pin, ratioLower, ratioUpper, pinFormatter, inheritedAttributes, } = this;
619
+ const { min, max, step, handleKeyboard, activatedKnob, focusedKnob, hoveredKnob, pressedKnob, disabled, pin, ratioLower, ratioUpper, pinFormatter, inheritedAttributes, } = this;
586
620
  let barStart = `${ratioLower * 100}%`;
587
621
  let barEnd = `${100 - ratioUpper * 100}%`;
588
622
  const rtl = isRTL(this.el);
@@ -642,7 +676,9 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
642
676
  ticks.push(tick);
643
677
  }
644
678
  }
645
- return (h("div", { class: "range-slider", ref: (rangeEl) => (this.rangeSlider = rangeEl),
679
+ return (h("div", { class: "range-slider", ref: (rangeEl) => (this.rangeSlider = rangeEl), onPointerDown: () => {
680
+ this.focusFromPointer = true;
681
+ },
646
682
  /**
647
683
  * Since the gesture has a threshold, the value
648
684
  * won't change until the user has dragged past
@@ -655,6 +691,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
655
691
  * we need to listen for the "pointerUp" event.
656
692
  */
657
693
  onPointerUp: (ev) => {
694
+ this.focusFromPointer = false;
658
695
  /**
659
696
  * If the user drags the knob on the web
660
697
  * version (does not occur on mobile),
@@ -680,6 +717,11 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
680
717
  'has-ticks': ticks.length > 0,
681
718
  }, role: "presentation", style: barStyle, part: "bar-active" })), renderKnob(rtl, {
682
719
  knob: 'A',
720
+ position: getKnobPosition('A', this.ratioA, this.ratioB, this.dualKnobs),
721
+ dualKnobs: this.dualKnobs,
722
+ activated: activatedKnob === 'A',
723
+ focused: focusedKnob === 'A',
724
+ hovered: hoveredKnob === 'A',
683
725
  pressed: pressedKnob === 'A',
684
726
  value: this.valA,
685
727
  ratio: this.ratioA,
@@ -692,9 +734,16 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
692
734
  inheritedAttributes,
693
735
  onKnobFocus: this.onKnobFocus,
694
736
  onKnobBlur: this.onKnobBlur,
737
+ onKnobMouseEnter: this.onKnobMouseEnter,
738
+ onKnobMouseLeave: this.onKnobMouseLeave,
695
739
  }), this.dualKnobs &&
696
740
  renderKnob(rtl, {
697
741
  knob: 'B',
742
+ position: getKnobPosition('B', this.ratioA, this.ratioB, this.dualKnobs),
743
+ dualKnobs: this.dualKnobs,
744
+ activated: activatedKnob === 'B',
745
+ focused: focusedKnob === 'B',
746
+ hovered: hoveredKnob === 'B',
698
747
  pressed: pressedKnob === 'B',
699
748
  value: this.valB,
700
749
  ratio: this.ratioB,
@@ -707,6 +756,8 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
707
756
  inheritedAttributes,
708
757
  onKnobFocus: this.onKnobFocus,
709
758
  onKnobBlur: this.onKnobBlur,
759
+ onKnobMouseEnter: this.onKnobMouseEnter,
760
+ onKnobMouseLeave: this.onKnobMouseLeave,
710
761
  })));
711
762
  }
712
763
  render() {
@@ -725,6 +776,12 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
725
776
  const hasEndContent = (hasLabel && labelPlacement === 'end') || this.hasEndSlotContent;
726
777
  const needsEndAdjustment = inItem && !hasEndContent;
727
778
  const mode = getIonMode(this);
779
+ /**
780
+ * Determine the name and position of the pressed knob to apply
781
+ * Host classes for styling.
782
+ */
783
+ const pressedKnobName = dualKnobs ? pressedKnob === null || pressedKnob === void 0 ? void 0 : pressedKnob.toLowerCase() : undefined;
784
+ const pressedKnobPosition = dualKnobs && pressedKnob ? getKnobPosition(pressedKnob, this.ratioA, this.ratioB, dualKnobs) : undefined;
728
785
  /**
729
786
  * Determine if any knob is at the min or max value to
730
787
  * apply Host classes for styling.
@@ -732,21 +789,24 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
732
789
  const valueAtMin = dualKnobs ? this.valA === min || this.valB === min : this.valA === min;
733
790
  const valueAtMax = dualKnobs ? this.valA === max || this.valB === max : this.valA === max;
734
791
  renderHiddenInput(true, el, this.name, JSON.stringify(this.getValue()), disabled);
735
- return (h(Host, { key: 'ed646a42d51b8fe22012198c354cbcf5a389c108', onFocusin: this.onFocus, onFocusout: this.onBlur, id: rangeId, class: createColorClasses(this.color, {
792
+ return (h(Host, { key: '8e439db9836fdefdc779573082c788e3ddb3ef73', onFocusin: this.onFocus, onFocusout: this.onBlur, id: rangeId, class: createColorClasses(this.color, {
736
793
  [mode]: true,
737
794
  'in-item': inItem,
738
795
  'range-disabled': disabled,
796
+ 'range-dual-knobs': dualKnobs,
739
797
  'range-pressed': pressedKnob !== undefined,
798
+ [`range-pressed-${pressedKnobName}`]: pressedKnob !== undefined && pressedKnobName !== undefined,
799
+ [`range-pressed-${pressedKnobPosition}`]: pressedKnob !== undefined && pressedKnobPosition !== undefined,
740
800
  'range-has-pin': pin,
741
801
  [`range-label-placement-${labelPlacement}`]: true,
742
802
  'range-item-start-adjustment': needsStartAdjustment,
743
803
  'range-item-end-adjustment': needsEndAdjustment,
744
804
  'range-value-min': valueAtMin,
745
805
  'range-value-max': valueAtMax,
746
- }) }, h("label", { key: '3083e4f2a624e3b268396acb4415f7c6ac44d851', class: "range-wrapper", id: "range-label" }, h("div", { key: '47b92f94d2a0381dd7c5cd3dda54ed2942096715', class: {
806
+ }) }, h("label", { key: 'e14c56db4d1eef11a3a0639c4bbed368041fc3eb', class: "range-wrapper", id: "range-label" }, h("div", { key: '16d125b0af19fdfa3663731657a7cca51a7ed442', class: {
747
807
  'label-text-wrapper': true,
748
808
  'label-text-wrapper-hidden': !hasLabel,
749
- }, part: "label" }, label !== undefined ? h("div", { class: "label-text" }, label) : h("slot", { name: "label" })), h("div", { key: '5341da8d19eb29091df680978a0e20cc8f2eec65', class: "native-wrapper" }, h("slot", { key: '09f1437078032676695442d8c827a16faa7dffe2', name: "start" }), this.renderRangeSlider(), h("slot", { key: '02b7781970ea4d44f10b5f4627a2ca36eca45f85', name: "end" })))));
809
+ }, part: "label" }, label !== undefined ? h("div", { class: "label-text" }, label) : h("slot", { name: "label" })), h("div", { key: '545cc52a3e675e9df328dab537a4e44b7f3c59f8', class: "native-wrapper" }, h("slot", { key: 'ac54b45a21c9db231ebe11498d508d05864b56fb', name: "start" }), this.renderRangeSlider(), h("slot", { key: '7182dba53df2ff878d572b30afda64b37082c82e', name: "end" })))));
750
810
  }
751
811
  get el() { return this; }
752
812
  static get watchers() { return {
@@ -781,6 +841,9 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
781
841
  "labelPlacement": [1, "label-placement"],
782
842
  "ratioA": [32],
783
843
  "ratioB": [32],
844
+ "activatedKnob": [32],
845
+ "focusedKnob": [32],
846
+ "hoveredKnob": [32],
784
847
  "pressedKnob": [32]
785
848
  }, undefined, {
786
849
  "debounce": ["debounceChanged"],
@@ -791,7 +854,7 @@ const Range = /*@__PURE__*/ proxyCustomElement(class Range extends HTMLElement {
791
854
  "disabled": ["disabledChanged"],
792
855
  "value": ["valueChanged"]
793
856
  }]);
794
- const renderKnob = (rtl, { knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard, pinFormatter, inheritedAttributes, onKnobFocus, onKnobBlur, }) => {
857
+ const renderKnob = (rtl, { knob, position, dualKnobs, value, ratio, min, max, disabled, activated, focused, hovered, pressed, pin, handleKeyboard, pinFormatter, inheritedAttributes, onKnobFocus, onKnobBlur, onKnobMouseEnter, onKnobMouseLeave, }) => {
795
858
  const start = rtl ? 'right' : 'left';
796
859
  const knobStyle = () => {
797
860
  const style = {};
@@ -812,16 +875,66 @@ const renderKnob = (rtl, { knob, value, ratio, min, max, disabled, pressed, pin,
812
875
  ev.preventDefault();
813
876
  ev.stopPropagation();
814
877
  }
815
- }, onFocus: () => onKnobFocus(knob), onBlur: onKnobBlur, class: {
878
+ }, onFocus: () => onKnobFocus(knob), onBlur: onKnobBlur, onMouseEnter: () => onKnobMouseEnter(knob), onMouseLeave: onKnobMouseLeave, class: {
816
879
  'range-knob-handle': true,
817
- 'range-knob-a': knob === 'A',
818
- 'range-knob-b': knob === 'B',
880
+ 'range-knob-handle-a': knob === 'A',
881
+ 'range-knob-handle-b': knob === 'B',
819
882
  'range-knob-pressed': pressed,
820
883
  'range-knob-min': value === min,
821
884
  'range-knob-max': value === max,
822
885
  'ion-activatable': true,
823
886
  'ion-focusable': true,
824
- }, style: knobStyle(), role: "slider", tabindex: disabled ? -1 : 0, "aria-label": ariaLabel !== undefined ? ariaLabel : null, "aria-labelledby": ariaLabel === undefined ? 'range-label' : null, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled ? 'true' : null, "aria-valuenow": value }, pin && (h("div", { class: "range-pin", role: "presentation", part: "pin" }, pinFormatter(value))), h("div", { class: "range-knob", role: "presentation", part: "knob" })));
887
+ 'ion-focused': focused,
888
+ }, part: [
889
+ 'knob-handle',
890
+ dualKnobs && knob === 'A' && 'knob-handle-a',
891
+ dualKnobs && knob === 'B' && 'knob-handle-b',
892
+ dualKnobs && position === 'lower' && 'knob-handle-lower',
893
+ dualKnobs && position === 'upper' && 'knob-handle-upper',
894
+ pressed && 'pressed',
895
+ focused && 'focused',
896
+ hovered && 'hover',
897
+ activated && 'activated',
898
+ ]
899
+ .filter(Boolean)
900
+ .join(' '), style: knobStyle(), role: "slider", tabindex: disabled ? -1 : 0, "aria-label": ariaLabel !== undefined ? ariaLabel : null, "aria-labelledby": ariaLabel === undefined ? 'range-label' : null, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled ? 'true' : null, "aria-valuenow": value }, pin && (h("div", { class: "range-pin", role: "presentation", part: [
901
+ 'pin',
902
+ dualKnobs && knob === 'A' && 'pin-a',
903
+ dualKnobs && knob === 'B' && 'pin-b',
904
+ dualKnobs && position === 'lower' && 'pin-lower',
905
+ dualKnobs && position === 'upper' && 'pin-upper',
906
+ pressed && 'pressed',
907
+ focused && 'focused',
908
+ hovered && 'hover',
909
+ activated && 'activated',
910
+ ]
911
+ .filter(Boolean)
912
+ .join(' ') }, pinFormatter(value))), h("div", { class: "range-knob", role: "presentation", part: [
913
+ 'knob',
914
+ dualKnobs && knob === 'A' && 'knob-a',
915
+ dualKnobs && knob === 'B' && 'knob-b',
916
+ dualKnobs && position === 'lower' && 'knob-lower',
917
+ dualKnobs && position === 'upper' && 'knob-upper',
918
+ pressed && 'pressed',
919
+ focused && 'focused',
920
+ hovered && 'hover',
921
+ activated && 'activated',
922
+ ]
923
+ .filter(Boolean)
924
+ .join(' ') })));
925
+ };
926
+ /**
927
+ * Returns whether the given knob is at the lower or upper position based
928
+ * on current ratios for the given knob.
929
+ */
930
+ const getKnobPosition = (knob, ratioA, ratioB, dualKnobs) => {
931
+ if (dualKnobs) {
932
+ if (knob === 'A') {
933
+ return ratioA <= ratioB ? 'lower' : 'upper';
934
+ }
935
+ return ratioB <= ratioA ? 'lower' : 'upper';
936
+ }
937
+ return 'lower';
825
938
  };
826
939
  const ratioToValue = (ratio, min, max, step) => {
827
940
  let value = (max - min) * ratio;
@@ -1575,11 +1575,11 @@ const Datetime = class {
1575
1575
  const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
1576
1576
  // don't use the inheritAttributes util because it removes dir from the host, and we still need that
1577
1577
  const hostDir = this.el.getAttribute('dir') || undefined;
1578
- return (index.h("div", { class: "calendar-header", part: "calendar-header" }, index.h("div", { class: "calendar-action-buttons" }, index.h("div", { class: "calendar-month-year" }, index.h("button", { class: {
1578
+ return (index.h("div", { class: "calendar-header" }, index.h("div", { class: "calendar-action-buttons" }, index.h("div", { class: "calendar-month-year" }, index.h("button", { class: {
1579
1579
  'calendar-month-year-toggle': true,
1580
1580
  'ion-activatable': true,
1581
1581
  'ion-focusable': true,
1582
- }, part: "month-year-button", disabled: disabled, "aria-label": this.showMonthAndYear ? 'Hide year picker' : 'Show year picker', onClick: () => this.toggleMonthAndYearView() }, index.h("span", { id: "toggle-wrapper" }, data.getMonthAndYear(this.locale, this.workingParts), index.h("ion-icon", { "aria-hidden": "true", icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false, flipRtl: true })), mode === 'md' && index.h("ion-ripple-effect", null))), index.h("div", { class: "calendar-next-prev" }, index.h("ion-buttons", null, index.h("ion-button", { "aria-label": "Previous month", disabled: prevMonthDisabled, onClick: () => this.prevMonth(), part: "prev-next-buttons prev-button" }, index.h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: index$1.chevronBack, lazy: false, flipRtl: true })), index.h("ion-button", { "aria-label": "Next month", disabled: nextMonthDisabled, onClick: () => this.nextMonth(), part: "prev-next-buttons next-button" }, index.h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: index$1.chevronForward, lazy: false, flipRtl: true }))))), index.h("div", { class: "calendar-days-of-week", "aria-hidden": "true", part: "days-of-week" }, data.getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
1582
+ }, part: "month-year-button", disabled: disabled, "aria-label": this.showMonthAndYear ? 'Hide year picker' : 'Show year picker', onClick: () => this.toggleMonthAndYearView() }, index.h("span", { id: "toggle-wrapper" }, data.getMonthAndYear(this.locale, this.workingParts), index.h("ion-icon", { "aria-hidden": "true", icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false, flipRtl: true })), mode === 'md' && index.h("ion-ripple-effect", null))), index.h("div", { class: "calendar-next-prev" }, index.h("ion-buttons", null, index.h("ion-button", { "aria-label": "Previous month", disabled: prevMonthDisabled, onClick: () => this.prevMonth() }, index.h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: index$1.chevronBack, lazy: false, flipRtl: true })), index.h("ion-button", { "aria-label": "Next month", disabled: nextMonthDisabled, onClick: () => this.nextMonth() }, index.h("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: index$1.chevronForward, lazy: false, flipRtl: true }))))), index.h("div", { class: "calendar-days-of-week", "aria-hidden": "true" }, data.getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
1583
1583
  return index.h("div", { class: "day-of-week" }, d);
1584
1584
  }))));
1585
1585
  }
@@ -1811,7 +1811,7 @@ const Datetime = class {
1811
1811
  if (!hasSlottedTitle && !this.showDefaultTitle) {
1812
1812
  return;
1813
1813
  }
1814
- return (index.h("div", { class: "datetime-header", part: "datetime-header" }, index.h("div", { class: "datetime-title" }, index.h("slot", { name: "title" }, "Select Date")), showExpandedHeader && index.h("div", { class: "datetime-selected-date" }, this.getHeaderSelectedDateText())));
1814
+ return (index.h("div", { class: "datetime-header" }, index.h("div", { class: "datetime-title" }, index.h("slot", { name: "title" }, "Select Date")), showExpandedHeader && index.h("div", { class: "datetime-selected-date" }, this.getHeaderSelectedDateText())));
1815
1815
  }
1816
1816
  /**
1817
1817
  * Render time picker inside of datetime.
@@ -1891,7 +1891,7 @@ const Datetime = class {
1891
1891
  const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
1892
1892
  const hasWheelVariant = hasDatePresentation && preferWheel;
1893
1893
  helpers.renderHiddenInput(true, el, name, data.formatValue(value), disabled);
1894
- return (index.h(index.Host, { key: '3d0787ecb3ad104c4a60d68a6e57140f018a70f2', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, theme.createColorClasses(color, {
1894
+ return (index.h(index.Host, { key: '19e20c9b6b5f9467e91a2567b6dc7d9d38b56cc3', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, theme.createColorClasses(color, {
1895
1895
  [mode]: true,
1896
1896
  ['datetime-readonly']: readonly,
1897
1897
  ['datetime-disabled']: disabled,
@@ -1901,7 +1901,7 @@ const Datetime = class {
1901
1901
  [`datetime-size-${size}`]: true,
1902
1902
  [`datetime-prefer-wheel`]: hasWheelVariant,
1903
1903
  [`datetime-grid`]: isGridStyle,
1904
- })) }, index.h("div", { key: '6b245a0033d5ddd1918bc839f142141bf5ec54c5', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1904
+ })) }, index.h("div", { key: 'e31b5ef76cd6262dafd39f2d21980887880ec32e', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
1905
1905
  }
1906
1906
  get el() { return index.getElement(this); }
1907
1907
  static get watchers() { return {