@ionic/core 8.7.17-dev.11771865171.14f4c2cf → 8.7.17-dev.11771870864.19b2cde1
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.
- package/components/ion-range.js +39 -152
- package/components/ion-segment-view.js +11 -5
- package/components/ion-select.js +3 -3
- package/components/ion-textarea.js +4 -4
- package/components/modal.js +206 -43
- package/dist/cjs/ion-modal.cjs.entry.js +206 -43
- package/dist/cjs/ion-range.cjs.entry.js +39 -149
- package/dist/cjs/ion-segment-view.cjs.entry.js +10 -5
- package/dist/cjs/ion-select_3.cjs.entry.js +3 -3
- package/dist/cjs/ion-textarea.cjs.entry.js +2 -2
- package/dist/cjs/ionic.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/modal/gestures/sheet.js +108 -11
- package/dist/collection/components/modal/gestures/swipe-to-close.js +54 -1
- package/dist/collection/components/modal/modal.js +98 -31
- package/dist/collection/components/range/range.js +42 -172
- package/dist/collection/components/segment-view/segment-view.ios.css +2 -1
- package/dist/collection/components/segment-view/segment-view.js +28 -3
- package/dist/collection/components/segment-view/segment-view.md.css +2 -1
- package/dist/collection/components/select/select.js +6 -3
- package/dist/collection/components/textarea/textarea.js +4 -4
- package/dist/docs.json +120 -144
- package/dist/esm/ion-modal.entry.js +206 -43
- package/dist/esm/ion-range.entry.js +39 -149
- package/dist/esm/ion-segment-view.entry.js +10 -5
- package/dist/esm/ion-select_3.entry.js +3 -3
- package/dist/esm/ion-textarea.entry.js +2 -2
- package/dist/esm/ionic.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/html.html-data.json +4 -0
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-012212e4.entry.js +4 -0
- package/dist/ionic/p-0f418a37.entry.js +4 -0
- package/dist/ionic/p-1838bed5.entry.js +4 -0
- package/dist/ionic/p-9a2d390d.entry.js +4 -0
- package/dist/ionic/{p-c19f63d0.entry.js → p-e1d1f3cc.entry.js} +1 -1
- package/dist/types/components/modal/gestures/sheet.d.ts +2 -2
- package/dist/types/components/modal/gestures/swipe-to-close.d.ts +2 -2
- package/dist/types/components/modal/modal-interface.d.ts +7 -0
- package/dist/types/components/modal/modal.d.ts +17 -1
- package/dist/types/components/range/range-interface.d.ts +0 -1
- package/dist/types/components/range/range.d.ts +4 -33
- package/dist/types/components/segment-view/segment-view.d.ts +4 -0
- package/dist/types/components/select/select.d.ts +3 -0
- package/dist/types/components.d.ts +27 -2
- package/hydrate/index.js +270 -228
- package/hydrate/index.mjs +270 -228
- package/package.json +1 -1
- package/dist/ionic/p-020af078.entry.js +0 -4
- package/dist/ionic/p-88367362.entry.js +0 -4
- package/dist/ionic/p-91840a80.entry.js +0 -4
- package/dist/ionic/p-991a3dd9.entry.js +0 -4
|
@@ -12,7 +12,7 @@ import { calculateSpringStep, handleCanDismiss } from "./utils";
|
|
|
12
12
|
export const SwipeToCloseDefaults = {
|
|
13
13
|
MIN_PRESENTING_SCALE: 0.915,
|
|
14
14
|
};
|
|
15
|
-
export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
15
|
+
export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onDragStart, onDragMove, onDragEnd) => {
|
|
16
16
|
/**
|
|
17
17
|
* The step value at which a card modal
|
|
18
18
|
* is eligible for dismissing via gesture.
|
|
@@ -122,6 +122,7 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
|
|
|
122
122
|
disableContentScrollY(contentEl);
|
|
123
123
|
}
|
|
124
124
|
animation.progressStart(true, isOpen ? 1 : 0);
|
|
125
|
+
onDragStart();
|
|
125
126
|
};
|
|
126
127
|
const onMove = (detail) => {
|
|
127
128
|
const { deltaY } = detail;
|
|
@@ -189,6 +190,13 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
|
|
|
189
190
|
setCardStatusBarDark();
|
|
190
191
|
}
|
|
191
192
|
lastStep = clampedStep;
|
|
193
|
+
const eventDetail = {
|
|
194
|
+
currentY: detail.currentY,
|
|
195
|
+
deltaY: detail.deltaY,
|
|
196
|
+
velocityY: detail.velocityY,
|
|
197
|
+
progress: calculateProgress(el, detail.deltaY),
|
|
198
|
+
};
|
|
199
|
+
onDragMove(eventDetail);
|
|
192
200
|
};
|
|
193
201
|
const onEnd = (detail) => {
|
|
194
202
|
const velocity = detail.velocityY;
|
|
@@ -247,6 +255,13 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
|
|
|
247
255
|
else if (shouldComplete) {
|
|
248
256
|
onDismiss();
|
|
249
257
|
}
|
|
258
|
+
const eventDetail = {
|
|
259
|
+
currentY: detail.currentY,
|
|
260
|
+
deltaY: detail.deltaY,
|
|
261
|
+
velocityY: detail.velocityY,
|
|
262
|
+
progress: calculateProgress(el, detail.deltaY),
|
|
263
|
+
};
|
|
264
|
+
onDragEnd(eventDetail);
|
|
250
265
|
};
|
|
251
266
|
const gesture = createGesture({
|
|
252
267
|
el,
|
|
@@ -264,3 +279,41 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
|
|
|
264
279
|
const computeDuration = (remaining, velocity) => {
|
|
265
280
|
return clamp(400, remaining / Math.abs(velocity * 1.1), 500);
|
|
266
281
|
};
|
|
282
|
+
/**
|
|
283
|
+
* Calculates the progress of the swipe gesture.
|
|
284
|
+
*
|
|
285
|
+
* The progress is a value between 0 and 1 that represents how far
|
|
286
|
+
* the swipe has progressed towards closing the modal.
|
|
287
|
+
*
|
|
288
|
+
* A value closer to 1 means the modal is closer to being opened,
|
|
289
|
+
* while a value closer to 0 means the modal is closer to being closed.
|
|
290
|
+
*
|
|
291
|
+
* @param el The modal
|
|
292
|
+
* @param deltaY The change in Y position (positive when dragging down, negative when dragging up)
|
|
293
|
+
* @returns The progress of the swipe gesture
|
|
294
|
+
*/
|
|
295
|
+
const calculateProgress = (el, deltaY) => {
|
|
296
|
+
const windowHeight = window.innerHeight;
|
|
297
|
+
// Position when fully open
|
|
298
|
+
const modalTop = el.getBoundingClientRect().top;
|
|
299
|
+
/**
|
|
300
|
+
* The distance between the top of the modal and the bottom of the screen
|
|
301
|
+
* is the total distance the modal needs to travel to be fully closed.
|
|
302
|
+
*/
|
|
303
|
+
const totalDistance = windowHeight - modalTop;
|
|
304
|
+
/**
|
|
305
|
+
* The pull percentage is how far the user has swiped compared to the total
|
|
306
|
+
* distance needed to close the modal.
|
|
307
|
+
*/
|
|
308
|
+
const pullPercentage = deltaY / totalDistance;
|
|
309
|
+
/**
|
|
310
|
+
* The progress is the inverse of the pull percentage because
|
|
311
|
+
* when the user starts swiping up, the progress should be close to 1,
|
|
312
|
+
* and when the user has swiped all the way down, the progress should be
|
|
313
|
+
* close to 0.
|
|
314
|
+
*/
|
|
315
|
+
const progress = 1 - pullPercentage;
|
|
316
|
+
// Round to the nearest thousandth to avoid returning very small decimal
|
|
317
|
+
const roundedProgress = Math.round(progress * 1000) / 1000;
|
|
318
|
+
return Math.max(0, Math.min(1, roundedProgress));
|
|
319
|
+
};
|
|
@@ -501,32 +501,7 @@ export class Modal {
|
|
|
501
501
|
return;
|
|
502
502
|
}
|
|
503
503
|
const statusBarStyle = (_a = this.statusBarStyle) !== null && _a !== void 0 ? _a : StatusBarStyle.Default;
|
|
504
|
-
this.gesture = createSwipeToCloseGesture(el, ani, statusBarStyle, () =>
|
|
505
|
-
/**
|
|
506
|
-
* While the gesture animation is finishing
|
|
507
|
-
* it is possible for a user to tap the backdrop.
|
|
508
|
-
* This would result in the dismiss animation
|
|
509
|
-
* being played again. Typically this is avoided
|
|
510
|
-
* by setting `presented = false` on the overlay
|
|
511
|
-
* component; however, we cannot do that here as
|
|
512
|
-
* that would prevent the element from being
|
|
513
|
-
* removed from the DOM.
|
|
514
|
-
*/
|
|
515
|
-
this.gestureAnimationDismissing = true;
|
|
516
|
-
/**
|
|
517
|
-
* Reset the status bar style as the dismiss animation
|
|
518
|
-
* starts otherwise the status bar will be the wrong
|
|
519
|
-
* color for the duration of the dismiss animation.
|
|
520
|
-
* The dismiss method does this as well, but
|
|
521
|
-
* in this case it's only called once the animation
|
|
522
|
-
* has finished.
|
|
523
|
-
*/
|
|
524
|
-
setCardStatusBarDefault(this.statusBarStyle);
|
|
525
|
-
this.animation.onFinish(async () => {
|
|
526
|
-
await this.dismiss(undefined, GESTURE);
|
|
527
|
-
this.gestureAnimationDismissing = false;
|
|
528
|
-
});
|
|
529
|
-
});
|
|
504
|
+
this.gesture = createSwipeToCloseGesture(el, ani, statusBarStyle, () => this.cardOnDismiss(), () => this.onDragStart(), (detail) => this.onDragMove(detail), (detail) => this.onDragEnd(detail));
|
|
530
505
|
this.gesture.enable(true);
|
|
531
506
|
}
|
|
532
507
|
initSheetGesture() {
|
|
@@ -547,7 +522,7 @@ export class Modal {
|
|
|
547
522
|
this.currentBreakpoint = breakpoint;
|
|
548
523
|
this.ionBreakpointDidChange.emit({ breakpoint });
|
|
549
524
|
}
|
|
550
|
-
});
|
|
525
|
+
}, () => this.onDragStart(), (detail) => this.onDragMove(detail), (detail) => this.onDragEnd(detail));
|
|
551
526
|
this.gesture = gesture;
|
|
552
527
|
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
|
|
553
528
|
this.gesture.enable(true);
|
|
@@ -644,6 +619,32 @@ export class Modal {
|
|
|
644
619
|
this.gestureAnimationDismissing = false;
|
|
645
620
|
});
|
|
646
621
|
}
|
|
622
|
+
cardOnDismiss() {
|
|
623
|
+
/**
|
|
624
|
+
* While the gesture animation is finishing
|
|
625
|
+
* it is possible for a user to tap the backdrop.
|
|
626
|
+
* This would result in the dismiss animation
|
|
627
|
+
* being played again. Typically this is avoided
|
|
628
|
+
* by setting `presented = false` on the overlay
|
|
629
|
+
* component; however, we cannot do that here as
|
|
630
|
+
* that would prevent the element from being
|
|
631
|
+
* removed from the DOM.
|
|
632
|
+
*/
|
|
633
|
+
this.gestureAnimationDismissing = true;
|
|
634
|
+
/**
|
|
635
|
+
* Reset the status bar style as the dismiss animation
|
|
636
|
+
* starts otherwise the status bar will be the wrong
|
|
637
|
+
* color for the duration of the dismiss animation.
|
|
638
|
+
* The dismiss method does this as well, but
|
|
639
|
+
* in this case it's only called once the animation
|
|
640
|
+
* has finished.
|
|
641
|
+
*/
|
|
642
|
+
setCardStatusBarDefault(this.statusBarStyle);
|
|
643
|
+
this.animation.onFinish(async () => {
|
|
644
|
+
await this.dismiss(undefined, GESTURE);
|
|
645
|
+
this.gestureAnimationDismissing = false;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
647
648
|
/**
|
|
648
649
|
* Dismiss the modal overlay after it has been presented.
|
|
649
650
|
* This is a no-op if the overlay has not been presented yet. If you want
|
|
@@ -967,6 +968,15 @@ export class Modal {
|
|
|
967
968
|
(_a = this.parentRemovalObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
968
969
|
this.parentRemovalObserver = undefined;
|
|
969
970
|
}
|
|
971
|
+
onDragStart() {
|
|
972
|
+
this.ionDragStart.emit();
|
|
973
|
+
}
|
|
974
|
+
onDragMove(detail) {
|
|
975
|
+
this.ionDragMove.emit(detail);
|
|
976
|
+
}
|
|
977
|
+
onDragEnd(detail) {
|
|
978
|
+
this.ionDragEnd.emit(detail);
|
|
979
|
+
}
|
|
970
980
|
render() {
|
|
971
981
|
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
|
|
972
982
|
const showHandle = handle !== false && isSheetModal;
|
|
@@ -974,20 +984,20 @@ export class Modal {
|
|
|
974
984
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
975
985
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
976
986
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
977
|
-
return (h(Host, Object.assign({ key: '
|
|
987
|
+
return (h(Host, Object.assign({ key: 'bca3cbdb2ce8e5127d27eae7494c434aaeddaf88', "no-router": true,
|
|
978
988
|
// Allow the modal to be navigable when the handle is focusable
|
|
979
989
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
980
990
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
981
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '
|
|
991
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: 'b1c4112123d84d8a9b9d455bcc17d884f99d9f28', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '080c8e6d37b311a1b5ad2655d99f18668abae211', class: "modal-shadow" }), h("div", Object.assign({ key: '8ba05e9520b1b5529bf0caeb766da5bf612d4d14',
|
|
982
992
|
/*
|
|
983
993
|
role and aria-modal must be used on the
|
|
984
994
|
same element. They must also be set inside the
|
|
985
995
|
shadow DOM otherwise ion-button will not be highlighted
|
|
986
996
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
987
997
|
*/
|
|
988
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
998
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '2d2d5d731f55755f32ebcbf557f97486dc6202a6', class: "modal-handle",
|
|
989
999
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
990
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '
|
|
1000
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'c717d19865dafba02e15db79bc0662c5d89e96fd', onSlotchange: this.onSlotChange }))));
|
|
991
1001
|
}
|
|
992
1002
|
static get is() { return "ion-modal"; }
|
|
993
1003
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1734,6 +1744,63 @@ export class Modal {
|
|
|
1734
1744
|
"resolved": "void",
|
|
1735
1745
|
"references": {}
|
|
1736
1746
|
}
|
|
1747
|
+
}, {
|
|
1748
|
+
"method": "ionDragStart",
|
|
1749
|
+
"name": "ionDragStart",
|
|
1750
|
+
"bubbles": true,
|
|
1751
|
+
"cancelable": true,
|
|
1752
|
+
"composed": true,
|
|
1753
|
+
"docs": {
|
|
1754
|
+
"tags": [],
|
|
1755
|
+
"text": "Event that is emitted when the sheet modal or card modal gesture starts."
|
|
1756
|
+
},
|
|
1757
|
+
"complexType": {
|
|
1758
|
+
"original": "void",
|
|
1759
|
+
"resolved": "void",
|
|
1760
|
+
"references": {}
|
|
1761
|
+
}
|
|
1762
|
+
}, {
|
|
1763
|
+
"method": "ionDragMove",
|
|
1764
|
+
"name": "ionDragMove",
|
|
1765
|
+
"bubbles": true,
|
|
1766
|
+
"cancelable": true,
|
|
1767
|
+
"composed": true,
|
|
1768
|
+
"docs": {
|
|
1769
|
+
"tags": [],
|
|
1770
|
+
"text": "Event that is emitted when the sheet modal or card modal gesture moves."
|
|
1771
|
+
},
|
|
1772
|
+
"complexType": {
|
|
1773
|
+
"original": "ModalDragEventDetail",
|
|
1774
|
+
"resolved": "ModalDragEventDetail",
|
|
1775
|
+
"references": {
|
|
1776
|
+
"ModalDragEventDetail": {
|
|
1777
|
+
"location": "import",
|
|
1778
|
+
"path": "./modal-interface",
|
|
1779
|
+
"id": "src/components/modal/modal-interface.ts::ModalDragEventDetail"
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
}, {
|
|
1784
|
+
"method": "ionDragEnd",
|
|
1785
|
+
"name": "ionDragEnd",
|
|
1786
|
+
"bubbles": true,
|
|
1787
|
+
"cancelable": true,
|
|
1788
|
+
"composed": true,
|
|
1789
|
+
"docs": {
|
|
1790
|
+
"tags": [],
|
|
1791
|
+
"text": "Event that is emitted when the sheet modal or card modal gesture ends."
|
|
1792
|
+
},
|
|
1793
|
+
"complexType": {
|
|
1794
|
+
"original": "ModalDragEventDetail",
|
|
1795
|
+
"resolved": "ModalDragEventDetail",
|
|
1796
|
+
"references": {
|
|
1797
|
+
"ModalDragEventDetail": {
|
|
1798
|
+
"location": "import",
|
|
1799
|
+
"path": "./modal-interface",
|
|
1800
|
+
"id": "src/components/modal/modal-interface.ts::ModalDragEventDetail"
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1737
1804
|
}];
|
|
1738
1805
|
}
|
|
1739
1806
|
static get methods() {
|
|
@@ -17,30 +17,13 @@ import { roundToMaxDecimalPlaces } from "../../utils/floating-point";
|
|
|
17
17
|
* @slot start - Content is placed to the left of the range slider in LTR, and to the right in RTL.
|
|
18
18
|
* @slot end - Content is placed to the right of the range slider in LTR, and to the left in RTL.
|
|
19
19
|
*
|
|
20
|
-
* @part label - The label text describing the range.
|
|
21
20
|
* @part tick - An inactive tick mark.
|
|
22
21
|
* @part tick-active - An active tick mark.
|
|
22
|
+
* @part pin - The counter that appears above a knob.
|
|
23
|
+
* @part knob - The handle that is used to drag the range.
|
|
23
24
|
* @part bar - The inactive part of the bar.
|
|
24
25
|
* @part bar-active - The active part of the bar.
|
|
25
|
-
* @part
|
|
26
|
-
* @part knob-handle-a - The container element for the first knob. Only available when `dualKnobs` is `true`.
|
|
27
|
-
* @part knob-handle-b - The container element for the second knob. Only available when `dualKnobs` is `true`.
|
|
28
|
-
* @part knob-handle-lower - The container element for the lower knob. Only available when `dualKnobs` is `true`.
|
|
29
|
-
* @part knob-handle-upper - The container element for the upper knob. Only available when `dualKnobs` is `true`.
|
|
30
|
-
* @part pin - The counter that appears above a knob.
|
|
31
|
-
* @part pin-a - The counter that appears above the first knob. Only available when `dualKnobs` is `true`.
|
|
32
|
-
* @part pin-b - The counter that appears above the second knob. Only available when `dualKnobs` is `true`.
|
|
33
|
-
* @part pin-lower - The counter that appears above the lower knob. Only available when `dualKnobs` is `true`.
|
|
34
|
-
* @part pin-upper - The counter that appears above the upper knob. Only available when `dualKnobs` is `true`.
|
|
35
|
-
* @part knob - The visual knob element that appears on the range track.
|
|
36
|
-
* @part knob-a - The visual knob element for the first knob. Only available when `dualKnobs` is `true`.
|
|
37
|
-
* @part knob-b - The visual knob element for the second knob. Only available when `dualKnobs` is `true`.
|
|
38
|
-
* @part knob-lower - The visual knob element for the lower knob. Only available when `dualKnobs` is `true`.
|
|
39
|
-
* @part knob-upper - The visual knob element for the upper knob. Only available when `dualKnobs` is `true`.
|
|
40
|
-
* @part activated - Added to the knob-handle, knob, and pin when the knob is activated (has the `ion-activated` class). Only one set has this part at a time when `dualKnobs` is `true`.
|
|
41
|
-
* @part focused - Added to the knob-handle, knob, and pin that currently has focus. Only one set has this part at a time when `dualKnobs` is `true`.
|
|
42
|
-
* @part hover - Added to the knob-handle, knob, and pin when the knob has hover. Only one set has this part at a time when `dualKnobs` is `true`.
|
|
43
|
-
* @part pressed - Added to the knob-handle, knob, and pin that is currently being pressed to drag. Only one set has this part at a time when `dualKnobs` is `true`.
|
|
26
|
+
* @part label - The label text describing the range.
|
|
44
27
|
*/
|
|
45
28
|
export class Range {
|
|
46
29
|
constructor() {
|
|
@@ -51,7 +34,6 @@ export class Range {
|
|
|
51
34
|
this.inheritedAttributes = {};
|
|
52
35
|
this.contentEl = null;
|
|
53
36
|
this.initialContentScrollY = true;
|
|
54
|
-
this.focusFromPointer = false;
|
|
55
37
|
this.ratioA = 0;
|
|
56
38
|
this.ratioB = 0;
|
|
57
39
|
/**
|
|
@@ -161,29 +143,6 @@ export class Range {
|
|
|
161
143
|
this.gesture.enable(!this.disabled);
|
|
162
144
|
}
|
|
163
145
|
};
|
|
164
|
-
/**
|
|
165
|
-
* Observes the knob handles for the ion-activated class and syncs
|
|
166
|
-
* activatedKnob so the activated part is correctly set on the handle,
|
|
167
|
-
* knob, and pin.
|
|
168
|
-
*/
|
|
169
|
-
this.setupActivatedObserver = () => {
|
|
170
|
-
const knobHandleA = this.el.shadowRoot.querySelector('.range-knob-handle-a');
|
|
171
|
-
const knobHandleB = this.el.shadowRoot.querySelector('.range-knob-handle-b');
|
|
172
|
-
const syncActivated = () => {
|
|
173
|
-
this.activatedKnob = (knobHandleA === null || knobHandleA === void 0 ? void 0 : knobHandleA.classList.contains('ion-activated'))
|
|
174
|
-
? 'A'
|
|
175
|
-
: (knobHandleB === null || knobHandleB === void 0 ? void 0 : knobHandleB.classList.contains('ion-activated'))
|
|
176
|
-
? 'B'
|
|
177
|
-
: undefined;
|
|
178
|
-
};
|
|
179
|
-
this.activatedObserver = new MutationObserver(syncActivated);
|
|
180
|
-
this.activatedObserver.observe(this.el.shadowRoot, {
|
|
181
|
-
attributes: true,
|
|
182
|
-
attributeFilter: ['class'],
|
|
183
|
-
subtree: true,
|
|
184
|
-
});
|
|
185
|
-
syncActivated();
|
|
186
|
-
};
|
|
187
146
|
this.handleKeyboard = (knob, isIncrease) => {
|
|
188
147
|
const { ensureValueInBounds } = this;
|
|
189
148
|
let step = this.step;
|
|
@@ -206,7 +165,6 @@ export class Range {
|
|
|
206
165
|
this.onBlur = () => {
|
|
207
166
|
if (this.hasFocus) {
|
|
208
167
|
this.hasFocus = false;
|
|
209
|
-
this.focusedKnob = undefined;
|
|
210
168
|
this.ionBlur.emit();
|
|
211
169
|
}
|
|
212
170
|
};
|
|
@@ -217,20 +175,21 @@ export class Range {
|
|
|
217
175
|
}
|
|
218
176
|
};
|
|
219
177
|
this.onKnobFocus = (knob) => {
|
|
220
|
-
// Clicking focuses the range which is needed for the keyboard,
|
|
221
|
-
// but we only want to add the ion-focused class when focused via Tab.
|
|
222
|
-
if (!this.focusFromPointer) {
|
|
223
|
-
this.focusedKnob = knob;
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
this.focusFromPointer = false;
|
|
227
|
-
this.focusedKnob = undefined;
|
|
228
|
-
}
|
|
229
|
-
// If the knob was not already focused, emit the focus event
|
|
230
178
|
if (!this.hasFocus) {
|
|
231
179
|
this.hasFocus = true;
|
|
232
180
|
this.ionFocus.emit();
|
|
233
181
|
}
|
|
182
|
+
// Manually manage ion-focused class for dual knobs
|
|
183
|
+
if (this.dualKnobs && this.el.shadowRoot) {
|
|
184
|
+
const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
|
|
185
|
+
const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
|
|
186
|
+
// Remove ion-focused from both knobs first
|
|
187
|
+
knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
|
|
188
|
+
knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
|
|
189
|
+
// Add ion-focused only to the focused knob
|
|
190
|
+
const focusedKnobEl = knob === 'A' ? knobA : knobB;
|
|
191
|
+
focusedKnobEl === null || focusedKnobEl === void 0 ? void 0 : focusedKnobEl.classList.add('ion-focused');
|
|
192
|
+
}
|
|
234
193
|
};
|
|
235
194
|
this.onKnobBlur = () => {
|
|
236
195
|
// Check if focus is moving to another knob within the same range
|
|
@@ -242,18 +201,18 @@ export class Range {
|
|
|
242
201
|
if (!isStillFocusedOnKnob) {
|
|
243
202
|
if (this.hasFocus) {
|
|
244
203
|
this.hasFocus = false;
|
|
245
|
-
this.focusedKnob = undefined;
|
|
246
204
|
this.ionBlur.emit();
|
|
247
205
|
}
|
|
206
|
+
// Remove ion-focused from both knobs when focus leaves the range
|
|
207
|
+
if (this.dualKnobs && this.el.shadowRoot) {
|
|
208
|
+
const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
|
|
209
|
+
const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
|
|
210
|
+
knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
|
|
211
|
+
knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
|
|
212
|
+
}
|
|
248
213
|
}
|
|
249
214
|
}, 0);
|
|
250
215
|
};
|
|
251
|
-
this.onKnobMouseEnter = (knob) => {
|
|
252
|
-
this.hoveredKnob = knob;
|
|
253
|
-
};
|
|
254
|
-
this.onKnobMouseLeave = () => {
|
|
255
|
-
this.hoveredKnob = undefined;
|
|
256
|
-
};
|
|
257
216
|
}
|
|
258
217
|
debounceChanged() {
|
|
259
218
|
const { ionInput, debounce, originalIonInput } = this;
|
|
@@ -330,7 +289,6 @@ export class Range {
|
|
|
330
289
|
this.originalIonInput = this.ionInput;
|
|
331
290
|
this.setupGesture();
|
|
332
291
|
this.updateRatio();
|
|
333
|
-
this.setupActivatedObserver();
|
|
334
292
|
this.didLoad = true;
|
|
335
293
|
}
|
|
336
294
|
connectedCallback() {
|
|
@@ -356,10 +314,6 @@ export class Range {
|
|
|
356
314
|
this.gesture.destroy();
|
|
357
315
|
this.gesture = undefined;
|
|
358
316
|
}
|
|
359
|
-
if (this.activatedObserver) {
|
|
360
|
-
this.activatedObserver.disconnect();
|
|
361
|
-
this.activatedObserver = undefined;
|
|
362
|
-
}
|
|
363
317
|
}
|
|
364
318
|
getValue() {
|
|
365
319
|
var _a;
|
|
@@ -512,6 +466,7 @@ export class Range {
|
|
|
512
466
|
ratio = 1 - ratio;
|
|
513
467
|
}
|
|
514
468
|
this.pressedKnob = !this.dualKnobs || Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio) ? 'A' : 'B';
|
|
469
|
+
this.setFocus(this.pressedKnob);
|
|
515
470
|
}
|
|
516
471
|
get valA() {
|
|
517
472
|
return ratioToValue(this.ratioA, this.min, this.max, this.step);
|
|
@@ -538,23 +493,9 @@ export class Range {
|
|
|
538
493
|
updateRatio() {
|
|
539
494
|
const value = this.getValue();
|
|
540
495
|
const { min, max } = this;
|
|
541
|
-
/**
|
|
542
|
-
* For dual knobs, value gives lower/upper but not which is A vs B.
|
|
543
|
-
* Assign (lowerRatio, upperRatio) to (ratioA, ratioB) in the way that
|
|
544
|
-
* minimizes change from the current ratios so the knobs don't swap.
|
|
545
|
-
*/
|
|
546
496
|
if (this.dualKnobs) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if (Math.abs(this.ratioA - lowerRatio) + Math.abs(this.ratioB - upperRatio) <=
|
|
550
|
-
Math.abs(this.ratioA - upperRatio) + Math.abs(this.ratioB - lowerRatio)) {
|
|
551
|
-
this.ratioA = lowerRatio;
|
|
552
|
-
this.ratioB = upperRatio;
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
this.ratioA = upperRatio;
|
|
556
|
-
this.ratioB = lowerRatio;
|
|
557
|
-
}
|
|
497
|
+
this.ratioA = valueToRatio(value.lower, min, max);
|
|
498
|
+
this.ratioB = valueToRatio(value.upper, min, max);
|
|
558
499
|
}
|
|
559
500
|
else {
|
|
560
501
|
this.ratioA = valueToRatio(value, min, max);
|
|
@@ -571,6 +512,14 @@ export class Range {
|
|
|
571
512
|
};
|
|
572
513
|
this.noUpdate = false;
|
|
573
514
|
}
|
|
515
|
+
setFocus(knob) {
|
|
516
|
+
if (this.el.shadowRoot) {
|
|
517
|
+
const knobEl = this.el.shadowRoot.querySelector(knob === 'A' ? '.range-knob-a' : '.range-knob-b');
|
|
518
|
+
if (knobEl) {
|
|
519
|
+
knobEl.focus();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
574
523
|
/**
|
|
575
524
|
* Returns true if content was passed to the "start" slot
|
|
576
525
|
*/
|
|
@@ -588,7 +537,7 @@ export class Range {
|
|
|
588
537
|
}
|
|
589
538
|
renderRangeSlider() {
|
|
590
539
|
var _a;
|
|
591
|
-
const { min, max, step, handleKeyboard,
|
|
540
|
+
const { min, max, step, handleKeyboard, pressedKnob, disabled, pin, ratioLower, ratioUpper, pinFormatter, inheritedAttributes, } = this;
|
|
592
541
|
let barStart = `${ratioLower * 100}%`;
|
|
593
542
|
let barEnd = `${100 - ratioUpper * 100}%`;
|
|
594
543
|
const rtl = isRTL(this.el);
|
|
@@ -648,9 +597,7 @@ export class Range {
|
|
|
648
597
|
ticks.push(tick);
|
|
649
598
|
}
|
|
650
599
|
}
|
|
651
|
-
return (h("div", { class: "range-slider", ref: (rangeEl) => (this.rangeSlider = rangeEl),
|
|
652
|
-
this.focusFromPointer = true;
|
|
653
|
-
},
|
|
600
|
+
return (h("div", { class: "range-slider", ref: (rangeEl) => (this.rangeSlider = rangeEl),
|
|
654
601
|
/**
|
|
655
602
|
* Since the gesture has a threshold, the value
|
|
656
603
|
* won't change until the user has dragged past
|
|
@@ -663,7 +610,6 @@ export class Range {
|
|
|
663
610
|
* we need to listen for the "pointerUp" event.
|
|
664
611
|
*/
|
|
665
612
|
onPointerUp: (ev) => {
|
|
666
|
-
this.focusFromPointer = false;
|
|
667
613
|
/**
|
|
668
614
|
* If the user drags the knob on the web
|
|
669
615
|
* version (does not occur on mobile),
|
|
@@ -689,11 +635,6 @@ export class Range {
|
|
|
689
635
|
'has-ticks': ticks.length > 0,
|
|
690
636
|
}, role: "presentation", style: barStyle, part: "bar-active" })), renderKnob(rtl, {
|
|
691
637
|
knob: 'A',
|
|
692
|
-
position: getKnobPosition('A', this.ratioA, this.ratioB, this.dualKnobs),
|
|
693
|
-
dualKnobs: this.dualKnobs,
|
|
694
|
-
activated: activatedKnob === 'A',
|
|
695
|
-
focused: focusedKnob === 'A',
|
|
696
|
-
hovered: hoveredKnob === 'A',
|
|
697
638
|
pressed: pressedKnob === 'A',
|
|
698
639
|
value: this.valA,
|
|
699
640
|
ratio: this.ratioA,
|
|
@@ -706,16 +647,9 @@ export class Range {
|
|
|
706
647
|
inheritedAttributes,
|
|
707
648
|
onKnobFocus: this.onKnobFocus,
|
|
708
649
|
onKnobBlur: this.onKnobBlur,
|
|
709
|
-
onKnobMouseEnter: this.onKnobMouseEnter,
|
|
710
|
-
onKnobMouseLeave: this.onKnobMouseLeave,
|
|
711
650
|
}), this.dualKnobs &&
|
|
712
651
|
renderKnob(rtl, {
|
|
713
652
|
knob: 'B',
|
|
714
|
-
position: getKnobPosition('B', this.ratioA, this.ratioB, this.dualKnobs),
|
|
715
|
-
dualKnobs: this.dualKnobs,
|
|
716
|
-
activated: activatedKnob === 'B',
|
|
717
|
-
focused: focusedKnob === 'B',
|
|
718
|
-
hovered: hoveredKnob === 'B',
|
|
719
653
|
pressed: pressedKnob === 'B',
|
|
720
654
|
value: this.valB,
|
|
721
655
|
ratio: this.ratioB,
|
|
@@ -728,8 +662,6 @@ export class Range {
|
|
|
728
662
|
inheritedAttributes,
|
|
729
663
|
onKnobFocus: this.onKnobFocus,
|
|
730
664
|
onKnobBlur: this.onKnobBlur,
|
|
731
|
-
onKnobMouseEnter: this.onKnobMouseEnter,
|
|
732
|
-
onKnobMouseLeave: this.onKnobMouseLeave,
|
|
733
665
|
})));
|
|
734
666
|
}
|
|
735
667
|
render() {
|
|
@@ -748,12 +680,6 @@ export class Range {
|
|
|
748
680
|
const hasEndContent = (hasLabel && labelPlacement === 'end') || this.hasEndSlotContent;
|
|
749
681
|
const needsEndAdjustment = inItem && !hasEndContent;
|
|
750
682
|
const mode = getIonMode(this);
|
|
751
|
-
/**
|
|
752
|
-
* Determine the name and position of the pressed knob to apply
|
|
753
|
-
* Host classes for styling.
|
|
754
|
-
*/
|
|
755
|
-
const pressedKnobName = dualKnobs ? pressedKnob === null || pressedKnob === void 0 ? void 0 : pressedKnob.toLowerCase() : undefined;
|
|
756
|
-
const pressedKnobPosition = dualKnobs && pressedKnob ? getKnobPosition(pressedKnob, this.ratioA, this.ratioB, dualKnobs) : undefined;
|
|
757
683
|
/**
|
|
758
684
|
* Determine if any knob is at the min or max value to
|
|
759
685
|
* apply Host classes for styling.
|
|
@@ -761,24 +687,21 @@ export class Range {
|
|
|
761
687
|
const valueAtMin = dualKnobs ? this.valA === min || this.valB === min : this.valA === min;
|
|
762
688
|
const valueAtMax = dualKnobs ? this.valA === max || this.valB === max : this.valA === max;
|
|
763
689
|
renderHiddenInput(true, el, this.name, JSON.stringify(this.getValue()), disabled);
|
|
764
|
-
return (h(Host, { key: '
|
|
690
|
+
return (h(Host, { key: 'ed646a42d51b8fe22012198c354cbcf5a389c108', onFocusin: this.onFocus, onFocusout: this.onBlur, id: rangeId, class: createColorClasses(this.color, {
|
|
765
691
|
[mode]: true,
|
|
766
692
|
'in-item': inItem,
|
|
767
693
|
'range-disabled': disabled,
|
|
768
|
-
'range-dual-knobs': dualKnobs,
|
|
769
694
|
'range-pressed': pressedKnob !== undefined,
|
|
770
|
-
[`range-pressed-${pressedKnobName}`]: pressedKnob !== undefined && pressedKnobName !== undefined,
|
|
771
|
-
[`range-pressed-${pressedKnobPosition}`]: pressedKnob !== undefined && pressedKnobPosition !== undefined,
|
|
772
695
|
'range-has-pin': pin,
|
|
773
696
|
[`range-label-placement-${labelPlacement}`]: true,
|
|
774
697
|
'range-item-start-adjustment': needsStartAdjustment,
|
|
775
698
|
'range-item-end-adjustment': needsEndAdjustment,
|
|
776
699
|
'range-value-min': valueAtMin,
|
|
777
700
|
'range-value-max': valueAtMax,
|
|
778
|
-
}) }, h("label", { key: '
|
|
701
|
+
}) }, h("label", { key: '3083e4f2a624e3b268396acb4415f7c6ac44d851', class: "range-wrapper", id: "range-label" }, h("div", { key: '47b92f94d2a0381dd7c5cd3dda54ed2942096715', class: {
|
|
779
702
|
'label-text-wrapper': true,
|
|
780
703
|
'label-text-wrapper-hidden': !hasLabel,
|
|
781
|
-
}, part: "label" }, label !== undefined ? h("div", { class: "label-text" }, label) : h("slot", { name: "label" })), h("div", { key: '
|
|
704
|
+
}, 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" })))));
|
|
782
705
|
}
|
|
783
706
|
static get is() { return "ion-range"; }
|
|
784
707
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1134,9 +1057,6 @@ export class Range {
|
|
|
1134
1057
|
return {
|
|
1135
1058
|
"ratioA": {},
|
|
1136
1059
|
"ratioB": {},
|
|
1137
|
-
"activatedKnob": {},
|
|
1138
|
-
"focusedKnob": {},
|
|
1139
|
-
"hoveredKnob": {},
|
|
1140
1060
|
"pressedKnob": {}
|
|
1141
1061
|
};
|
|
1142
1062
|
}
|
|
@@ -1283,7 +1203,7 @@ export class Range {
|
|
|
1283
1203
|
}];
|
|
1284
1204
|
}
|
|
1285
1205
|
}
|
|
1286
|
-
const renderKnob = (rtl, { knob,
|
|
1206
|
+
const renderKnob = (rtl, { knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard, pinFormatter, inheritedAttributes, onKnobFocus, onKnobBlur, }) => {
|
|
1287
1207
|
const start = rtl ? 'right' : 'left';
|
|
1288
1208
|
const knobStyle = () => {
|
|
1289
1209
|
const style = {};
|
|
@@ -1304,66 +1224,16 @@ const renderKnob = (rtl, { knob, position, dualKnobs, value, ratio, min, max, di
|
|
|
1304
1224
|
ev.preventDefault();
|
|
1305
1225
|
ev.stopPropagation();
|
|
1306
1226
|
}
|
|
1307
|
-
}, onFocus: () => onKnobFocus(knob), onBlur: onKnobBlur,
|
|
1227
|
+
}, onFocus: () => onKnobFocus(knob), onBlur: onKnobBlur, class: {
|
|
1308
1228
|
'range-knob-handle': true,
|
|
1309
|
-
'range-knob-
|
|
1310
|
-
'range-knob-
|
|
1229
|
+
'range-knob-a': knob === 'A',
|
|
1230
|
+
'range-knob-b': knob === 'B',
|
|
1311
1231
|
'range-knob-pressed': pressed,
|
|
1312
1232
|
'range-knob-min': value === min,
|
|
1313
1233
|
'range-knob-max': value === max,
|
|
1314
1234
|
'ion-activatable': true,
|
|
1315
1235
|
'ion-focusable': true,
|
|
1316
|
-
|
|
1317
|
-
}, part: [
|
|
1318
|
-
'knob-handle',
|
|
1319
|
-
dualKnobs && knob === 'A' && 'knob-handle-a',
|
|
1320
|
-
dualKnobs && knob === 'B' && 'knob-handle-b',
|
|
1321
|
-
dualKnobs && position === 'lower' && 'knob-handle-lower',
|
|
1322
|
-
dualKnobs && position === 'upper' && 'knob-handle-upper',
|
|
1323
|
-
pressed && 'pressed',
|
|
1324
|
-
focused && 'focused',
|
|
1325
|
-
hovered && 'hover',
|
|
1326
|
-
activated && 'activated',
|
|
1327
|
-
]
|
|
1328
|
-
.filter(Boolean)
|
|
1329
|
-
.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: [
|
|
1330
|
-
'pin',
|
|
1331
|
-
dualKnobs && knob === 'A' && 'pin-a',
|
|
1332
|
-
dualKnobs && knob === 'B' && 'pin-b',
|
|
1333
|
-
dualKnobs && position === 'lower' && 'pin-lower',
|
|
1334
|
-
dualKnobs && position === 'upper' && 'pin-upper',
|
|
1335
|
-
pressed && 'pressed',
|
|
1336
|
-
focused && 'focused',
|
|
1337
|
-
hovered && 'hover',
|
|
1338
|
-
activated && 'activated',
|
|
1339
|
-
]
|
|
1340
|
-
.filter(Boolean)
|
|
1341
|
-
.join(' ') }, pinFormatter(value))), h("div", { class: "range-knob", role: "presentation", part: [
|
|
1342
|
-
'knob',
|
|
1343
|
-
dualKnobs && knob === 'A' && 'knob-a',
|
|
1344
|
-
dualKnobs && knob === 'B' && 'knob-b',
|
|
1345
|
-
dualKnobs && position === 'lower' && 'knob-lower',
|
|
1346
|
-
dualKnobs && position === 'upper' && 'knob-upper',
|
|
1347
|
-
pressed && 'pressed',
|
|
1348
|
-
focused && 'focused',
|
|
1349
|
-
hovered && 'hover',
|
|
1350
|
-
activated && 'activated',
|
|
1351
|
-
]
|
|
1352
|
-
.filter(Boolean)
|
|
1353
|
-
.join(' ') })));
|
|
1354
|
-
};
|
|
1355
|
-
/**
|
|
1356
|
-
* Returns whether the given knob is at the lower or upper position based
|
|
1357
|
-
* on current ratios for the given knob.
|
|
1358
|
-
*/
|
|
1359
|
-
const getKnobPosition = (knob, ratioA, ratioB, dualKnobs) => {
|
|
1360
|
-
if (dualKnobs) {
|
|
1361
|
-
if (knob === 'A') {
|
|
1362
|
-
return ratioA <= ratioB ? 'lower' : 'upper';
|
|
1363
|
-
}
|
|
1364
|
-
return ratioB <= ratioA ? 'lower' : 'upper';
|
|
1365
|
-
}
|
|
1366
|
-
return 'lower';
|
|
1236
|
+
}, 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" })));
|
|
1367
1237
|
};
|
|
1368
1238
|
const ratioToValue = (ratio, min, max, step) => {
|
|
1369
1239
|
let value = (max - min) * ratio;
|