UNPKG

25.6 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5const index = require('./index-a0a08b2a.js');
6const ionicGlobal = require('./ionic-global-06f21c1a.js');
7const helpers = require('./helpers-d381ec4d.js');
8const theme = require('./theme-30b7a575.js');
9
10const rangeIosCss = ":host{--knob-handle-size:calc(var(--knob-size) * 2);display:-ms-flexbox;display:flex;position:relative;-ms-flex:3;flex:3;-ms-flex-align:center;align-items:center;font-family:var(--ion-font-family, inherit);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.range-disabled){pointer-events:none}::slotted(ion-label){-ms-flex:initial;flex:initial}::slotted(ion-icon[slot]){font-size:24px}.range-slider{position:relative;-ms-flex:1;flex:1;width:100%;height:var(--height);contain:size layout style;cursor:-webkit-grab;cursor:grab;-ms-touch-action:pan-y;touch-action:pan-y}:host(.range-pressed) .range-slider{cursor:-webkit-grabbing;cursor:grabbing}.range-pin{position:absolute;background:var(--ion-color-base);color:var(--ion-color-contrast);text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box}.range-knob-handle{left:0;top:calc((var(--height) - var(--knob-handle-size)) / 2);margin-left:calc(0px - var(--knob-handle-size) / 2);position:absolute;width:var(--knob-handle-size);height:var(--knob-handle-size);text-align:center}[dir=rtl] .range-knob-handle,:host-context([dir=rtl]) .range-knob-handle{left:unset;right:unset;right:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.range-knob-handle{margin-left:unset;-webkit-margin-start:calc(0px - var(--knob-handle-size) / 2);margin-inline-start:calc(0px - var(--knob-handle-size) / 2)}}[dir=rtl] .range-knob-handle,:host-context([dir=rtl]) .range-knob-handle{left:unset}.range-knob-handle:active,.range-knob-handle:focus{outline:none}.range-bar{border-radius:var(--bar-border-radius);left:0;top:calc((var(--height) - var(--bar-height)) / 2);position:absolute;width:100%;height:var(--bar-height);background:var(--bar-background);pointer-events:none}[dir=rtl] .range-bar,:host-context([dir=rtl]) .range-bar{left:unset;right:unset;right:0}[dir=rtl] .range-bar,:host-context([dir=rtl]) .range-bar{left:unset}.range-knob{border-radius:var(--knob-border-radius);left:calc(50% - var(--knob-size) / 2);top:calc(50% - var(--knob-size) / 2);position:absolute;width:var(--knob-size);height:var(--knob-size);background:var(--knob-background);-webkit-box-shadow:var(--knob-box-shadow);box-shadow:var(--knob-box-shadow);z-index:2;pointer-events:none}[dir=rtl] .range-knob,:host-context([dir=rtl]) .range-knob{left:unset;right:unset;right:calc(50% - var(--knob-size) / 2)}[dir=rtl] .range-knob,:host-context([dir=rtl]) .range-knob{left:unset}:host(.range-pressed) .range-bar-active{will-change:left, right}:host(.in-item){width:100%}:host(.in-item) ::slotted(ion-label){-ms-flex-item-align:center;align-self:center}:host{--knob-border-radius:50%;--knob-background:#ffffff;--knob-box-shadow:0 3px 1px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.13), 0 0 0 1px rgba(0, 0, 0, 0.02);--knob-size:28px;--bar-height:2px;--bar-background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);--bar-background-active:var(--ion-color-primary, #3880ff);--bar-border-radius:0;--height:42px;padding-left:16px;padding-right:16px;padding-top:8px;padding-bottom:8px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}}:host(.ion-color) .range-bar-active,:host(.ion-color) .range-tick-active{background:var(--ion-color-base)}::slotted([slot=start]){margin-left:0;margin-right:16px;margin-top:0;margin-bottom:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted([slot=start]){margin-left:unset;margin-right:unset;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}}::slotted([slot=end]){margin-left:16px;margin-right:0;margin-top:0;margin-bottom:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted([slot=end]){margin-left:unset;margin-right:unset;-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}}:host(.range-has-pin){padding-top:20px}.range-bar-active{bottom:0;width:auto;background:var(--bar-background-active)}.range-tick{margin-left:-1px;border-radius:0;position:absolute;top:18px;width:2px;height:8px;background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);pointer-events:none}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.range-tick{margin-left:unset;-webkit-margin-start:-1px;margin-inline-start:-1px}}.range-tick-active{background:var(--bar-background-active)}.range-pin{-webkit-transform:translate3d(0, 28px, 0) scale(0.01);transform:translate3d(0, 28px, 0) scale(0.01);padding-left:8px;padding-right:8px;padding-top:8px;padding-bottom:8px;display:inline-block;position:relative;top:-20px;min-width:28px;-webkit-transition:-webkit-transform 120ms ease;transition:-webkit-transform 120ms ease;transition:transform 120ms ease;transition:transform 120ms ease, -webkit-transform 120ms ease;background:transparent;color:var(--ion-text-color, #000);font-size:12px;text-align:center}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.range-pin{padding-left:unset;padding-right:unset;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px}}.range-knob-pressed .range-pin{-webkit-transform:translate3d(0, 0, 0) scale(1);transform:translate3d(0, 0, 0) scale(1)}:host(.range-disabled){opacity:0.5}";
11
12const rangeMdCss = ":host{--knob-handle-size:calc(var(--knob-size) * 2);display:-ms-flexbox;display:flex;position:relative;-ms-flex:3;flex:3;-ms-flex-align:center;align-items:center;font-family:var(--ion-font-family, inherit);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.range-disabled){pointer-events:none}::slotted(ion-label){-ms-flex:initial;flex:initial}::slotted(ion-icon[slot]){font-size:24px}.range-slider{position:relative;-ms-flex:1;flex:1;width:100%;height:var(--height);contain:size layout style;cursor:-webkit-grab;cursor:grab;-ms-touch-action:pan-y;touch-action:pan-y}:host(.range-pressed) .range-slider{cursor:-webkit-grabbing;cursor:grabbing}.range-pin{position:absolute;background:var(--ion-color-base);color:var(--ion-color-contrast);text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box}.range-knob-handle{left:0;top:calc((var(--height) - var(--knob-handle-size)) / 2);margin-left:calc(0px - var(--knob-handle-size) / 2);position:absolute;width:var(--knob-handle-size);height:var(--knob-handle-size);text-align:center}[dir=rtl] .range-knob-handle,:host-context([dir=rtl]) .range-knob-handle{left:unset;right:unset;right:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.range-knob-handle{margin-left:unset;-webkit-margin-start:calc(0px - var(--knob-handle-size) / 2);margin-inline-start:calc(0px - var(--knob-handle-size) / 2)}}[dir=rtl] .range-knob-handle,:host-context([dir=rtl]) .range-knob-handle{left:unset}.range-knob-handle:active,.range-knob-handle:focus{outline:none}.range-bar{border-radius:var(--bar-border-radius);left:0;top:calc((var(--height) - var(--bar-height)) / 2);position:absolute;width:100%;height:var(--bar-height);background:var(--bar-background);pointer-events:none}[dir=rtl] .range-bar,:host-context([dir=rtl]) .range-bar{left:unset;right:unset;right:0}[dir=rtl] .range-bar,:host-context([dir=rtl]) .range-bar{left:unset}.range-knob{border-radius:var(--knob-border-radius);left:calc(50% - var(--knob-size) / 2);top:calc(50% - var(--knob-size) / 2);position:absolute;width:var(--knob-size);height:var(--knob-size);background:var(--knob-background);-webkit-box-shadow:var(--knob-box-shadow);box-shadow:var(--knob-box-shadow);z-index:2;pointer-events:none}[dir=rtl] .range-knob,:host-context([dir=rtl]) .range-knob{left:unset;right:unset;right:calc(50% - var(--knob-size) / 2)}[dir=rtl] .range-knob,:host-context([dir=rtl]) .range-knob{left:unset}:host(.range-pressed) .range-bar-active{will-change:left, right}:host(.in-item){width:100%}:host(.in-item) ::slotted(ion-label){-ms-flex-item-align:center;align-self:center}:host{--knob-border-radius:50%;--knob-background:var(--bar-background-active);--knob-box-shadow:none;--knob-size:18px;--bar-height:2px;--bar-background:rgba(var(--ion-color-primary-rgb, 56, 128, 255), 0.26);--bar-background-active:var(--ion-color-primary, #3880ff);--bar-border-radius:0;--height:42px;--pin-background:var(--ion-color-primary, #3880ff);--pin-color:var(--ion-color-primary-contrast, #fff);padding-left:14px;padding-right:14px;padding-top:8px;padding-bottom:8px;font-size:12px}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){:host{padding-left:unset;padding-right:unset;-webkit-padding-start:14px;padding-inline-start:14px;-webkit-padding-end:14px;padding-inline-end:14px}}:host(.ion-color) .range-bar{background:rgba(var(--ion-color-base-rgb), 0.26)}:host(.ion-color) .range-bar-active,:host(.ion-color) .range-knob,:host(.ion-color) .range-pin,:host(.ion-color) .range-pin::before,:host(.ion-color) .range-tick{background:var(--ion-color-base);color:var(--ion-color-contrast)}::slotted([slot=start]){margin-left:0;margin-right:14px;margin-top:0;margin-bottom:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted([slot=start]){margin-left:unset;margin-right:unset;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:14px;margin-inline-end:14px}}::slotted([slot=end]){margin-left:14px;margin-right:0;margin-top:0;margin-bottom:0}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){::slotted([slot=end]){margin-left:unset;margin-right:unset;-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:0;margin-inline-end:0}}:host(.range-has-pin){padding-top:28px}.range-bar-active{bottom:0;width:auto;background:var(--bar-background-active)}.range-knob{-webkit-transform:scale(0.67);transform:scale(0.67);-webkit-transition-duration:120ms;transition-duration:120ms;-webkit-transition-property:background-color, border, -webkit-transform;transition-property:background-color, border, -webkit-transform;transition-property:transform, background-color, border;transition-property:transform, background-color, border, -webkit-transform;-webkit-transition-timing-function:ease;transition-timing-function:ease;z-index:2}.range-tick{position:absolute;top:calc((var(--height) - var(--bar-height)) / 2);width:var(--bar-height);height:var(--bar-height);background:var(--bar-background-active);z-index:1;pointer-events:none}.range-tick-active{background:transparent}.range-pin{padding-left:0;padding-right:0;padding-top:8px;padding-bottom:8px;border-radius:50%;-webkit-transform:translate3d(0, 0, 0) scale(0.01);transform:translate3d(0, 0, 0) scale(0.01);display:inline-block;position:relative;min-width:28px;height:28px;-webkit-transition:background 120ms ease, -webkit-transform 120ms ease;transition:background 120ms ease, -webkit-transform 120ms ease;transition:transform 120ms ease, background 120ms ease;transition:transform 120ms ease, background 120ms ease, -webkit-transform 120ms ease;background:var(--pin-background);color:var(--pin-color);text-align:center}.range-pin::before{left:50%;top:3px;margin-left:-13px;border-radius:50% 50% 50% 0;position:absolute;width:26px;height:26px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transition:background 120ms ease;transition:background 120ms ease;background:var(--pin-background);content:\"\";z-index:-1}[dir=rtl] .range-pin::before,:host-context([dir=rtl]) .range-pin::before{left:unset;right:unset;right:50%}@supports ((-webkit-margin-start: 0) or (margin-inline-start: 0)) or (-webkit-margin-start: 0){.range-pin::before{margin-left:unset;-webkit-margin-start:-13px;margin-inline-start:-13px}}[dir=rtl] .range-pin::before,:host-context([dir=rtl]) .range-pin::before{left:unset}.range-knob-pressed .range-pin{-webkit-transform:translate3d(0, -24px, 0) scale(1);transform:translate3d(0, -24px, 0) scale(1)}:host(:not(.range-has-pin)) .range-knob-pressed .range-knob{-webkit-transform:scale(1);transform:scale(1)}:host(.range-disabled) .range-bar-active,:host(.range-disabled) .range-bar,:host(.range-disabled) .range-tick{background-color:var(--ion-color-step-250, #bfbfbf)}:host(.range-disabled) .range-knob{-webkit-transform:scale(0.55);transform:scale(0.55);outline:5px solid #fff;background-color:var(--ion-color-step-250, #bfbfbf)}";
13
14const Range = class {
15 constructor(hostRef) {
16 index.registerInstance(this, hostRef);
17 this.ionChange = index.createEvent(this, "ionChange", 7);
18 this.ionStyle = index.createEvent(this, "ionStyle", 7);
19 this.ionFocus = index.createEvent(this, "ionFocus", 7);
20 this.ionBlur = index.createEvent(this, "ionBlur", 7);
21 this.didLoad = false;
22 this.noUpdate = false;
23 this.hasFocus = false;
24 this.inheritedAttributes = {};
25 this.ratioA = 0;
26 this.ratioB = 0;
27 /**
28 * How long, in milliseconds, to wait to trigger the
29 * `ionChange` event after each change in the range value.
30 * This also impacts form bindings such as `ngModel` or `v-model`.
31 */
32 this.debounce = 0;
33 // TODO: In Ionic Framework v6 this should initialize to this.rangeId like the other form components do.
34 /**
35 * The name of the control, which is submitted with the form data.
36 */
37 this.name = '';
38 /**
39 * Show two knobs.
40 */
41 this.dualKnobs = false;
42 /**
43 * Minimum integer value of the range.
44 */
45 this.min = 0;
46 /**
47 * Maximum integer value of the range.
48 */
49 this.max = 100;
50 /**
51 * If `true`, a pin with integer value is shown when the knob
52 * is pressed.
53 */
54 this.pin = false;
55 /**
56 * If `true`, the knob snaps to tick marks evenly spaced based
57 * on the step property value.
58 */
59 this.snaps = false;
60 /**
61 * Specifies the value granularity.
62 */
63 this.step = 1;
64 /**
65 * If `true`, tick marks are displayed based on the step value.
66 * Only applies when `snaps` is `true`.
67 */
68 this.ticks = true;
69 /**
70 * If `true`, the user cannot interact with the range.
71 */
72 this.disabled = false;
73 /**
74 * the value of the range.
75 */
76 this.value = 0;
77 this.clampBounds = (value) => {
78 return helpers.clamp(this.min, value, this.max);
79 };
80 this.ensureValueInBounds = (value) => {
81 if (this.dualKnobs) {
82 return {
83 lower: this.clampBounds(value.lower),
84 upper: this.clampBounds(value.upper)
85 };
86 }
87 else {
88 return this.clampBounds(value);
89 }
90 };
91 this.setupGesture = async () => {
92 const rangeSlider = this.rangeSlider;
93 if (rangeSlider) {
94 this.gesture = (await Promise.resolve().then(function () { return require('./index-a1dd5c93.js'); })).createGesture({
95 el: rangeSlider,
96 gestureName: 'range',
97 gesturePriority: 100,
98 threshold: 0,
99 onStart: ev => this.onStart(ev),
100 onMove: ev => this.onMove(ev),
101 onEnd: ev => this.onEnd(ev),
102 });
103 this.gesture.enable(!this.disabled);
104 }
105 };
106 this.handleKeyboard = (knob, isIncrease) => {
107 let step = this.step;
108 step = step > 0 ? step : 1;
109 step = step / (this.max - this.min);
110 if (!isIncrease) {
111 step *= -1;
112 }
113 if (knob === 'A') {
114 this.ratioA = helpers.clamp(0, this.ratioA + step, 1);
115 }
116 else {
117 this.ratioB = helpers.clamp(0, this.ratioB + step, 1);
118 }
119 this.updateValue();
120 };
121 this.onBlur = () => {
122 if (this.hasFocus) {
123 this.hasFocus = false;
124 this.ionBlur.emit();
125 this.emitStyle();
126 }
127 };
128 this.onFocus = () => {
129 if (!this.hasFocus) {
130 this.hasFocus = true;
131 this.ionFocus.emit();
132 this.emitStyle();
133 }
134 };
135 }
136 debounceChanged() {
137 this.ionChange = helpers.debounceEvent(this.ionChange, this.debounce);
138 }
139 minChanged() {
140 if (!this.noUpdate) {
141 this.updateRatio();
142 }
143 }
144 maxChanged() {
145 if (!this.noUpdate) {
146 this.updateRatio();
147 }
148 }
149 disabledChanged() {
150 if (this.gesture) {
151 this.gesture.enable(!this.disabled);
152 }
153 this.emitStyle();
154 }
155 valueChanged(value) {
156 if (!this.noUpdate) {
157 this.updateRatio();
158 }
159 value = this.ensureValueInBounds(value);
160 this.ionChange.emit({ value });
161 }
162 componentWillLoad() {
163 /**
164 * If user has custom ID set then we should
165 * not assign the default incrementing ID.
166 */
167 this.rangeId = (this.el.hasAttribute('id')) ? this.el.getAttribute('id') : `ion-r-${rangeIds++}`;
168 this.inheritedAttributes = helpers.inheritAttributes(this.el, ['aria-label']);
169 }
170 componentDidLoad() {
171 this.setupGesture();
172 this.didLoad = true;
173 }
174 connectedCallback() {
175 this.updateRatio();
176 this.debounceChanged();
177 this.disabledChanged();
178 /**
179 * If we have not yet rendered
180 * ion-range, then rangeSlider is not defined.
181 * But if we are moving ion-range via appendChild,
182 * then rangeSlider will be defined.
183 */
184 if (this.didLoad) {
185 this.setupGesture();
186 }
187 }
188 disconnectedCallback() {
189 if (this.gesture) {
190 this.gesture.destroy();
191 this.gesture = undefined;
192 }
193 }
194 getValue() {
195 const value = this.value || 0;
196 if (this.dualKnobs) {
197 if (typeof value === 'object') {
198 return value;
199 }
200 return {
201 lower: 0,
202 upper: value
203 };
204 }
205 else {
206 if (typeof value === 'object') {
207 return value.upper;
208 }
209 return value;
210 }
211 }
212 emitStyle() {
213 this.ionStyle.emit({
214 'interactive': true,
215 'interactive-disabled': this.disabled
216 });
217 }
218 onStart(detail) {
219 const rect = this.rect = this.rangeSlider.getBoundingClientRect();
220 const currentX = detail.currentX;
221 // figure out which knob they started closer to
222 let ratio = helpers.clamp(0, (currentX - rect.left) / rect.width, 1);
223 if (document.dir === 'rtl') {
224 ratio = 1 - ratio;
225 }
226 this.pressedKnob =
227 !this.dualKnobs ||
228 Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio)
229 ? 'A'
230 : 'B';
231 this.setFocus(this.pressedKnob);
232 // update the active knob's position
233 this.update(currentX);
234 }
235 onMove(detail) {
236 this.update(detail.currentX);
237 }
238 onEnd(detail) {
239 this.update(detail.currentX);
240 this.pressedKnob = undefined;
241 }
242 update(currentX) {
243 // figure out where the pointer is currently at
244 // update the knob being interacted with
245 const rect = this.rect;
246 let ratio = helpers.clamp(0, (currentX - rect.left) / rect.width, 1);
247 if (document.dir === 'rtl') {
248 ratio = 1 - ratio;
249 }
250 if (this.snaps) {
251 // snaps the ratio to the current value
252 ratio = valueToRatio(ratioToValue(ratio, this.min, this.max, this.step), this.min, this.max);
253 }
254 // update which knob is pressed
255 if (this.pressedKnob === 'A') {
256 this.ratioA = ratio;
257 }
258 else {
259 this.ratioB = ratio;
260 }
261 // Update input value
262 this.updateValue();
263 }
264 get valA() {
265 return ratioToValue(this.ratioA, this.min, this.max, this.step);
266 }
267 get valB() {
268 return ratioToValue(this.ratioB, this.min, this.max, this.step);
269 }
270 get ratioLower() {
271 if (this.dualKnobs) {
272 return Math.min(this.ratioA, this.ratioB);
273 }
274 return 0;
275 }
276 get ratioUpper() {
277 if (this.dualKnobs) {
278 return Math.max(this.ratioA, this.ratioB);
279 }
280 return this.ratioA;
281 }
282 updateRatio() {
283 const value = this.getValue();
284 const { min, max } = this;
285 if (this.dualKnobs) {
286 this.ratioA = valueToRatio(value.lower, min, max);
287 this.ratioB = valueToRatio(value.upper, min, max);
288 }
289 else {
290 this.ratioA = valueToRatio(value, min, max);
291 }
292 }
293 updateValue() {
294 this.noUpdate = true;
295 const { valA, valB } = this;
296 this.value = !this.dualKnobs
297 ? valA
298 : {
299 lower: Math.min(valA, valB),
300 upper: Math.max(valA, valB)
301 };
302 this.noUpdate = false;
303 }
304 setFocus(knob) {
305 if (this.el.shadowRoot) {
306 const knobEl = this.el.shadowRoot.querySelector(knob === 'A' ? '.range-knob-a' : '.range-knob-b');
307 if (knobEl) {
308 knobEl.focus();
309 }
310 }
311 }
312 render() {
313 const { min, max, step, el, handleKeyboard, pressedKnob, disabled, pin, ratioLower, ratioUpper, inheritedAttributes, rangeId } = this;
314 /**
315 * Look for external label, ion-label, or aria-labelledby.
316 * If none, see if user placed an aria-label on the host
317 * and use that instead.
318 */
319 let { labelText } = helpers.getAriaLabel(el, rangeId);
320 if (labelText === undefined || labelText === null) {
321 labelText = inheritedAttributes['aria-label'];
322 }
323 const mode = ionicGlobal.getIonMode(this);
324 const barStart = `${ratioLower * 100}%`;
325 const barEnd = `${100 - ratioUpper * 100}%`;
326 const doc = document;
327 const isRTL = doc.dir === 'rtl';
328 const start = isRTL ? 'right' : 'left';
329 const end = isRTL ? 'left' : 'right';
330 const tickStyle = (tick) => {
331 return {
332 [start]: tick[start]
333 };
334 };
335 const barStyle = {
336 [start]: barStart,
337 [end]: barEnd
338 };
339 const ticks = [];
340 if (this.snaps && this.ticks) {
341 for (let value = min; value <= max; value += step) {
342 const ratio = valueToRatio(value, min, max);
343 const tick = {
344 ratio,
345 active: ratio >= ratioLower && ratio <= ratioUpper,
346 };
347 tick[start] = `${ratio * 100}%`;
348 ticks.push(tick);
349 }
350 }
351 helpers.renderHiddenInput(true, el, this.name, JSON.stringify(this.getValue()), disabled);
352 return (index.h(index.Host, { onFocusin: this.onFocus, onFocusout: this.onBlur, id: rangeId, class: theme.createColorClasses(this.color, {
353 [mode]: true,
354 'in-item': theme.hostContext('ion-item', el),
355 'range-disabled': disabled,
356 'range-pressed': pressedKnob !== undefined,
357 'range-has-pin': pin
358 }) }, index.h("slot", { name: "start" }), index.h("div", { class: "range-slider", ref: rangeEl => this.rangeSlider = rangeEl }, ticks.map(tick => (index.h("div", { style: tickStyle(tick), role: "presentation", class: {
359 'range-tick': true,
360 'range-tick-active': tick.active
361 }, part: tick.active ? 'tick-active' : 'tick' }))), index.h("div", { class: "range-bar", role: "presentation", part: "bar" }), index.h("div", { class: "range-bar range-bar-active", role: "presentation", style: barStyle, part: "bar-active" }), renderKnob(isRTL, {
362 knob: 'A',
363 pressed: pressedKnob === 'A',
364 value: this.valA,
365 ratio: this.ratioA,
366 pin,
367 disabled,
368 handleKeyboard,
369 min,
370 max,
371 labelText
372 }), this.dualKnobs && renderKnob(isRTL, {
373 knob: 'B',
374 pressed: pressedKnob === 'B',
375 value: this.valB,
376 ratio: this.ratioB,
377 pin,
378 disabled,
379 handleKeyboard,
380 min,
381 max,
382 labelText
383 })), index.h("slot", { name: "end" })));
384 }
385 get el() { return index.getElement(this); }
386 static get watchers() { return {
387 "debounce": ["debounceChanged"],
388 "min": ["minChanged"],
389 "max": ["maxChanged"],
390 "disabled": ["disabledChanged"],
391 "value": ["valueChanged"]
392 }; }
393};
394const renderKnob = (isRTL, { knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard, labelText }) => {
395 const start = isRTL ? 'right' : 'left';
396 const knobStyle = () => {
397 const style = {};
398 style[start] = `${ratio * 100}%`;
399 return style;
400 };
401 return (index.h("div", { onKeyDown: (ev) => {
402 const key = ev.key;
403 if (key === 'ArrowLeft' || key === 'ArrowDown') {
404 handleKeyboard(knob, false);
405 ev.preventDefault();
406 ev.stopPropagation();
407 }
408 else if (key === 'ArrowRight' || key === 'ArrowUp') {
409 handleKeyboard(knob, true);
410 ev.preventDefault();
411 ev.stopPropagation();
412 }
413 }, class: {
414 'range-knob-handle': true,
415 'range-knob-a': knob === 'A',
416 'range-knob-b': knob === 'B',
417 'range-knob-pressed': pressed,
418 'range-knob-min': value === min,
419 'range-knob-max': value === max
420 }, style: knobStyle(), role: "slider", tabindex: disabled ? -1 : 0, "aria-label": labelText, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled ? 'true' : null, "aria-valuenow": value }, pin && index.h("div", { class: "range-pin", role: "presentation", part: "pin" }, Math.round(value)), index.h("div", { class: "range-knob", role: "presentation", part: "knob" })));
421};
422const ratioToValue = (ratio, min, max, step) => {
423 let value = (max - min) * ratio;
424 if (step > 0) {
425 value = Math.round(value / step) * step + min;
426 }
427 return helpers.clamp(min, value, max);
428};
429const valueToRatio = (value, min, max) => {
430 return helpers.clamp(0, (value - min) / (max - min), 1);
431};
432let rangeIds = 0;
433Range.style = {
434 ios: rangeIosCss,
435 md: rangeMdCss
436};
437
438exports.ion_range = Range;