• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-webcomponents / 15753383816

19 Jun 2025 08:33AM UTC coverage: 98.266% (+0.009%) from 98.257%
15753383816

Pull #1746

github

web-flow
Merge f7f9c96b3 into 56a6e7062
Pull Request #1746: refactor: Dropped themes decorator for explicit initialization

4943 of 5189 branches covered (95.26%)

Branch coverage included in aggregate %.

435 of 447 new or added lines in 71 files covered. (97.32%)

8 existing lines in 1 file now uncovered.

31497 of 31894 relevant lines covered (98.76%)

1728.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.75
/src/components/slider/slider-base.ts
1
import { html, LitElement, nothing, type TemplateResult } from 'lit';
10✔
2
import {
10✔
3
  property,
10✔
4
  query,
10✔
5
  queryAssignedElements,
10✔
6
  state,
10✔
7
} from 'lit/decorators.js';
10✔
8
import { ifDefined } from 'lit/directives/if-defined.js';
10✔
9
import { type StyleInfo, styleMap } from 'lit/directives/style-map.js';
10✔
10

10✔
11
import { addThemingController } from '../../theming/theming-controller.js';
10✔
12
import {
10✔
13
  addKeybindings,
10✔
14
  arrowDown,
10✔
15
  arrowLeft,
10✔
16
  arrowRight,
10✔
17
  arrowUp,
10✔
18
  endKey,
10✔
19
  homeKey,
10✔
20
  pageDownKey,
10✔
21
  pageUpKey,
10✔
22
} from '../common/controllers/key-bindings.js';
10✔
23
import { blazorDeepImport } from '../common/decorators/blazorDeepImport.js';
10✔
24
import { watch } from '../common/decorators/watch.js';
10✔
25
import {
10✔
26
  asNumber,
10✔
27
  asPercent,
10✔
28
  clamp,
10✔
29
  formatString,
10✔
30
  isDefined,
10✔
31
  isLTR,
10✔
32
} from '../common/util.js';
10✔
33
import type {
10✔
34
  SliderTickLabelRotation,
10✔
35
  SliderTickOrientation,
10✔
36
} from '../types.js';
10✔
37
import { styles as shared } from './themes/shared/slider.common.css.js';
10✔
38
import { styles } from './themes/slider.base.css.js';
10✔
39
import { all } from './themes/themes.js';
10✔
40

10✔
41
@blazorDeepImport
10✔
42
export class IgcSliderBaseComponent extends LitElement {
10✔
43
  public static override styles = [styles, shared];
10✔
44

10✔
45
  @query(`[part~='thumb']`)
10✔
46
  protected thumb!: HTMLElement;
10✔
47

10✔
48
  @query(`[part='base']`, true)
10✔
49
  protected base!: HTMLDivElement;
10✔
50

10✔
51
  @queryAssignedElements({ selector: 'igc-slider-label' })
10✔
52
  private labelElements!: HTMLElement[];
10✔
53

10✔
54
  private _min = 0;
10✔
55
  private _max = 100;
10✔
56
  private _lowerBound?: number;
10✔
57
  private _upperBound?: number;
10✔
58
  private _step = 1;
10✔
59
  private startValue?: number;
10✔
60
  private pointerCaptured = false;
10✔
61
  private thumbHoverTimer: any;
10✔
62
  protected activeThumb?: HTMLElement;
10✔
63

10✔
64
  @state()
10✔
65
  protected thumbLabelsVisible = false;
10✔
66

10✔
67
  @state()
10✔
68
  protected labels: string[] = [];
10✔
69

10✔
70
  protected get hasLabels() {
10✔
71
    return this.labels?.length > 0;
10✔
72
  }
10✔
73

10✔
74
  protected get distance() {
10✔
75
    return this.max - this.min;
632✔
76
  }
632✔
77

10✔
78
  /**
10✔
79
   * The minimum value of the slider scale. Defaults to 0.
10✔
80
   *
10✔
81
   * If `min` is greater than `max` the call is a no-op.
10✔
82
   *
10✔
83
   * If `labels` are provided (projected), then `min` is always set to 0.
10✔
84
   *
10✔
85
   * If `lowerBound` ends up being less than than the current `min` value,
10✔
86
   * it is automatically assigned the new `min` value.
10✔
87
   * @attr
10✔
88
   */
10✔
89
  @property({ type: Number })
10✔
90
  public set min(value: number) {
10✔
91
    if (!isDefined(value) || value > this.max) {
12✔
92
      return;
1✔
93
    }
1✔
94

11✔
95
    this._min = this.hasLabels ? 0 : value;
12✔
96

12✔
97
    if (isDefined(this._lowerBound) && this._lowerBound! < value) {
12✔
98
      this._lowerBound = value;
1✔
99
    }
1✔
100
  }
12✔
101

10✔
102
  public get min(): number {
10✔
103
    return this._min;
2,006✔
104
  }
2,006✔
105

10✔
106
  /**
10✔
107
   * The maximum value of the slider scale. Defaults to 100.
10✔
108
   *
10✔
109
   * If `max` is less than `min` the call is a no-op.
10✔
110
   *
10✔
111
   * If `labels` are provided (projected), then `max` is always set to
10✔
112
   * the number of labels.
10✔
113
   *
10✔
114
   * If `upperBound` ends up being greater than than the current `max` value,
10✔
115
   * it is automatically assigned the new `max` value.
10✔
116
   * @attr
10✔
117
   */
10✔
118
  @property({ type: Number })
10✔
119
  public set max(value: number) {
10✔
120
    if (!isDefined(value) || value < this._min) {
11✔
121
      return;
1✔
122
    }
1✔
123

10✔
124
    this._max = this.hasLabels ? this.labels.length - 1 : value;
11✔
125

11✔
126
    if (isDefined(this._upperBound) && this._upperBound! > value) {
11✔
127
      this._upperBound = value;
1✔
128
    }
1✔
129
  }
11✔
130

10✔
131
  public get max(): number {
10✔
132
    return this._max;
798✔
133
  }
798✔
134

10✔
135
  /**
10✔
136
   * The lower bound of the slider value. If not set, the `min` value is applied.
10✔
137
   * @attr lower-bound
10✔
138
   */
10✔
139
  @property({ type: Number, attribute: 'lower-bound' })
10✔
140
  public set lowerBound(value: number) {
10✔
141
    if (!isDefined(value)) return;
10!
142
    this._lowerBound = Math.min(this._upperBound ?? value, value);
10✔
143
  }
10✔
144

10✔
145
  public get lowerBound(): number {
10✔
146
    const current = this._lowerBound ?? this._min;
783✔
147
    const upper = Math.min(this._upperBound ?? this._max, this._max);
783✔
148

783✔
149
    return clamp(current, this._min, upper);
783✔
150
  }
783✔
151

10✔
152
  /**
10✔
153
   * The upper bound of the slider value. If not set, the `max` value is applied.
10✔
154
   * @attr upper-bound
10✔
155
   */
10✔
156
  @property({ type: Number, attribute: 'upper-bound' })
10✔
157
  public set upperBound(value: number) {
10✔
158
    if (!isDefined(value)) return;
9!
159
    this._upperBound = Math.max(this._lowerBound ?? value, value);
9✔
160
  }
9✔
161

10✔
162
  public get upperBound(): number {
10✔
163
    const current = this._upperBound ?? this._max;
606✔
164
    const lower = Math.max(this._lowerBound ?? this._min, this.min);
606✔
165

606✔
166
    return clamp(current, lower, this._max);
606✔
167
  }
606✔
168

10✔
169
  /**
10✔
170
   * Disables the UI interactions of the slider.
10✔
171
   * @attr
10✔
172
   */
10✔
173
  @property({ type: Boolean, reflect: true })
10✔
174
  public disabled = false;
10✔
175

10✔
176
  /**
10✔
177
   * Marks the slider track as discrete so it displays the steps.
10✔
178
   * If the `step` is 0, the slider will remain continuos even if `discreteTrack` is `true`.
10✔
179
   * @attr discrete-track
10✔
180
   */
10✔
181
  @property({ type: Boolean, attribute: 'discrete-track' })
10✔
182
  public discreteTrack = false;
10✔
183

10✔
184
  /**
10✔
185
   * Hides the thumb tooltip.
10✔
186
   * @attr hide-tooltip
10✔
187
   */
10✔
188
  @property({ type: Boolean, attribute: 'hide-tooltip' })
10✔
189
  public hideTooltip = false;
10✔
190

10✔
191
  /**
10✔
192
   * Specifies the granularity that the value must adhere to.
10✔
193
   *
10✔
194
   * If set to 0 no stepping is implied and any value in the range is allowed.
10✔
195
   * If `labels` are provided (projected) then the step is always assumed to be 1 since it is a discrete slider.
10✔
196
   *
10✔
197
   * @attr
10✔
198
   */
10✔
199
  @property({ type: Number })
10✔
200
  public set step(value: number) {
10✔
201
    this._step = this.hasLabels ? 1 : asNumber(value, this._step);
11✔
202
  }
11✔
203

10✔
204
  public get step(): number {
10✔
205
    return this._step;
591✔
206
  }
591✔
207

10✔
208
  /**
10✔
209
   * The number of primary ticks. It defaults to 0 which means no primary ticks are displayed.
10✔
210
   * @attr primary-ticks
10✔
211
   */
10✔
212
  @property({ type: Number, attribute: 'primary-ticks' })
10✔
213
  public primaryTicks = 0;
10✔
214

10✔
215
  /**
10✔
216
   * The number of secondary ticks. It defaults to 0 which means no secondary ticks are displayed.
10✔
217
   * @attr secondary-ticks
10✔
218
   */
10✔
219
  @property({ type: Number, attribute: 'secondary-ticks' })
10✔
220
  public secondaryTicks = 0;
10✔
221

10✔
222
  /**
10✔
223
   * Changes the orientation of the ticks.
10✔
224
   * @attr tick-orientation
10✔
225
   */
10✔
226
  @property({ attribute: 'tick-orientation' })
10✔
227
  public tickOrientation: SliderTickOrientation = 'end';
10✔
228

10✔
229
  /**
10✔
230
   * Hides the primary tick labels.
10✔
231
   * @attr hide-primary-labels
10✔
232
   */
10✔
233
  @property({ type: Boolean, attribute: 'hide-primary-labels' })
10✔
234
  public hidePrimaryLabels = false;
10✔
235

10✔
236
  /**
10✔
237
   * Hides the secondary tick labels.
10✔
238
   * @attr hide-secondary-labels
10✔
239
   */
10✔
240
  @property({ type: Boolean, attribute: 'hide-secondary-labels' })
10✔
241
  public hideSecondaryLabels = false;
10✔
242

10✔
243
  /**
10✔
244
   * The locale used to format the thumb and tick label values in the slider.
10✔
245
   * @attr
10✔
246
   */
10✔
247
  @property()
10✔
248
  public locale = 'en';
10✔
249

10✔
250
  /**
10✔
251
   * String format used for the thumb and tick label values in the slider.
10✔
252
   * @attr value-format
10✔
253
   */
10✔
254
  @property({ attribute: 'value-format' })
10✔
255
  public valueFormat?: string;
10✔
256

10✔
257
  /**
10✔
258
   * Number format options used for the thumb and tick label values in the slider.
10✔
259
   */
10✔
260
  /* blazorSuppress */
10✔
261
  @property({ attribute: false })
10✔
262
  public valueFormatOptions?: Intl.NumberFormatOptions;
10✔
263

10✔
264
  /**
10✔
265
   * The degrees for the rotation of the tick labels. Defaults to 0.
10✔
266
   * @attr tick-label-rotation
10✔
267
   */
10✔
268
  @property({ type: Number, reflect: true, attribute: 'tick-label-rotation' })
10✔
269
  public tickLabelRotation: SliderTickLabelRotation = 0;
10✔
270

10✔
271
  @watch('min', { waitUntilFirstUpdate: true })
10✔
272
  @watch('max', { waitUntilFirstUpdate: true })
10✔
273
  @watch('lowerBound', { waitUntilFirstUpdate: true })
10✔
274
  @watch('upperBound', { waitUntilFirstUpdate: true })
10✔
275
  @watch('step', { waitUntilFirstUpdate: true })
10✔
276
  protected constraintsChange() {
10✔
277
    this.normalizeValue();
43✔
278
  }
43✔
279

10✔
280
  constructor() {
10✔
281
    super();
60✔
282

60✔
283
    addThemingController(this, all);
60✔
284

60✔
285
    this.addEventListener('pointerdown', this.pointerDown);
60✔
286
    this.addEventListener('pointermove', this.pointerMove);
60✔
287
    this.addEventListener('lostpointercapture', this.lostPointerCapture);
60✔
288
    this.addEventListener('keyup', this.handleKeyUp);
60✔
289

60✔
290
    addKeybindings(this, {
60✔
291
      skip: () => this.disabled,
60✔
292
      bindingDefaults: { preventDefault: true },
60✔
293
    })
60✔
294
      .set(arrowLeft, () => this.handleArrowKeys(isLTR(this) ? -1 : 1))
60✔
295
      .set(arrowRight, () => this.handleArrowKeys(isLTR(this) ? 1 : -1))
60✔
296
      .set(arrowUp, () => this.handleArrowKeys(1))
60✔
297
      .set(arrowDown, () => this.handleArrowKeys(-1))
60✔
298
      .set(homeKey, () =>
60✔
299
        this.handleKeyboardIncrement(this.lowerBound - this.activeValue)
3✔
300
      )
60✔
301
      .set(endKey, () =>
60✔
302
        this.handleKeyboardIncrement(this.upperBound - this.activeValue)
3✔
303
      )
60✔
304
      .set(pageUpKey, () => this.handlePageKeys(1))
60✔
305
      .set(pageDownKey, () => this.handlePageKeys(-1));
60✔
306
  }
60✔
307

10✔
308
  private handleArrowKeys(delta: -1 | 1) {
10✔
309
    const step = this.step ? this.step : 1;
8✔
310
    this.handleKeyboardIncrement(step * delta);
8✔
311
  }
8✔
312

10✔
313
  private handlePageKeys(delta: -1 | 1) {
10✔
314
    const step = this.step ? this.step : 1;
2!
315
    this.handleKeyboardIncrement(
2✔
316
      delta * Math.max((this.upperBound - this.lowerBound) / 10, step)
2✔
317
    );
2✔
318
  }
2✔
319

10✔
320
  private handleKeyboardIncrement(increment: number) {
10✔
321
    if (increment) {
16✔
322
      const updated = this.updateValue(increment);
14✔
323
      this.showThumbLabels();
14✔
324
      this.hideThumbLabels();
14✔
325

14✔
326
      if (updated) {
14✔
327
        this.emitChangeEvent();
14✔
328
      }
14✔
329
    }
14✔
330
  }
16✔
331

10✔
332
  private handleKeyUp() {
10✔
333
    this.activeThumb?.part.add('focused');
14!
334
  }
14✔
335

10✔
336
  protected handleSlotChange() {
10✔
337
    this.labels = this.labelElements.map((label) => label.textContent ?? '');
1✔
338
    if (this.hasLabels) {
1✔
339
      this.min = 0;
1✔
340
      this.max = this.labels.length - 1;
1✔
341
      this.step = 1;
1✔
342
    }
1✔
343
  }
1✔
344

10✔
345
  /* c8 ignore next 3 */
10✔
346
  protected get activeValue() {
10✔
347
    return 0;
10✔
348
  }
10✔
349

10✔
350
  /* c8 ignore next */
10✔
351
  protected normalizeValue(): void {}
10✔
352

10✔
353
  /* c8 ignore next 3 */
10✔
354
  protected getTrackStyle(): StyleInfo {
10✔
355
    return {};
10✔
356
  }
10✔
357

10✔
358
  /* c8 ignore next 3 */
10✔
359
  protected updateValue(_increment: number): boolean {
10✔
360
    return false;
10✔
361
  }
10✔
362

10✔
363
  /* c8 ignore next 3 */
10✔
364
  protected renderThumbs(): TemplateResult<1> {
10✔
365
    return html``;
10✔
366
  }
10✔
367

10✔
368
  /* c8 ignore next */
10✔
369
  protected emitInputEvent() {}
10✔
370

10✔
371
  /* c8 ignore next */
10✔
372
  protected emitChangeEvent() {}
10✔
373

10✔
374
  protected validateValue(value: number) {
10✔
375
    return this.normalizeByStep(clamp(value, this.lowerBound, this.upperBound));
183✔
376
  }
183✔
377

10✔
378
  protected formatValue(value: number) {
10✔
379
    const strValue = value.toLocaleString(this.locale, this.valueFormatOptions);
381✔
380
    return this.valueFormat
381✔
381
      ? formatString(this.valueFormat, strValue)
13✔
382
      : strValue;
368✔
383
  }
381✔
384

10✔
385
  private normalizeByStep(value: number) {
10✔
386
    return this.step ? value - ((value - this.lowerBound) % this.step) : value;
183✔
387
  }
183✔
388

10✔
389
  protected closestHandle(_event: PointerEvent): HTMLElement {
10✔
390
    return this.thumb;
3✔
391
  }
3✔
392

10✔
393
  private totalTickCount() {
10✔
394
    const primaryTicks = this.hasLabels
320✔
395
      ? this.primaryTicks > 0
2✔
396
        ? this.labels.length
2!
UNCOV
397
        : 0
✔
398
      : this.primaryTicks === 1
318!
UNCOV
399
        ? 2
×
400
        : this.primaryTicks;
318✔
401

320✔
402
    return primaryTicks > 0
320✔
403
      ? (primaryTicks - 1) * this.secondaryTicks + primaryTicks
150✔
404
      : this.secondaryTicks > 0
170!
UNCOV
405
        ? this.secondaryTicks
×
406
        : 0;
170✔
407
  }
320✔
408

10✔
409
  private tickValue(idx: number) {
10✔
410
    const tickCount = this.totalTickCount();
133✔
411
    const distance = this.distance;
133✔
412
    const labelStep = tickCount > 1 ? distance / (tickCount - 1) : distance;
133!
413
    const labelVal = labelStep * idx;
133✔
414

133✔
415
    return this.min + labelVal;
133✔
416
  }
133✔
417

10✔
418
  private isPrimary(idx: number) {
10✔
419
    return this.primaryTicks <= 0
139!
UNCOV
420
      ? false
×
421
      : idx % (this.secondaryTicks + 1) === 0;
139✔
422
  }
139✔
423

10✔
424
  protected showThumbLabels() {
10✔
425
    if (this.disabled || this.hideTooltip) {
22✔
426
      return;
1✔
427
    }
1✔
428

21✔
429
    if (this.thumbHoverTimer) {
22✔
430
      clearTimeout(this.thumbHoverTimer);
8✔
431
      this.thumbHoverTimer = null;
8✔
432
    }
8✔
433

21✔
434
    this.thumbLabelsVisible = true;
21✔
435
  }
22✔
436

10✔
437
  protected hideThumbLabels() {
10✔
438
    if (this.pointerCaptured || !this.thumbLabelsVisible) {
20!
439
      return;
×
UNCOV
440
    }
×
441

20✔
442
    this.thumbHoverTimer = setTimeout(() => {
20✔
443
      this.thumbLabelsVisible = false;
3✔
444
    }, 750);
20✔
445
  }
20✔
446

10✔
447
  private calculateTrackUpdate(mouseX: number): number {
10✔
448
    const { width, left } = this.activeThumb!.getBoundingClientRect();
20✔
449
    const { width: trackWidth } = this.base.getBoundingClientRect();
20✔
450

20✔
451
    const thumbX = left + width / 2;
20✔
452
    const scale = trackWidth / this.distance;
20✔
453
    const change = isLTR(this) ? mouseX - thumbX : thumbX - mouseX;
20!
454

20✔
455
    if (this.step) {
20✔
456
      const stepDistance = scale * this.step;
19✔
457

19✔
458
      // If the thumb scale range (slider update) is less than a half step,
19✔
459
      // the position stays the same.
19✔
460
      if (Math.abs(change) < stepDistance / 2) {
19!
461
        return 0;
×
UNCOV
462
      }
×
463

19✔
464
      return Math.round(change / stepDistance) * this.step;
19✔
465
    }
19✔
466
    return change / scale;
1✔
467
  }
20✔
468

10✔
469
  private updateSlider(mouseX: number) {
10✔
470
    if (this.disabled || !this.activeThumb) {
20!
471
      return;
×
UNCOV
472
    }
×
473

20✔
474
    const increment = this.calculateTrackUpdate(mouseX);
20✔
475
    if (increment !== 0) {
20✔
476
      this.updateValue(increment);
20✔
477
    }
20✔
478
  }
20✔
479

10✔
480
  private pointerDown(event: PointerEvent) {
10✔
481
    const thumb = this.closestHandle(event);
6✔
482
    thumb.focus();
6✔
483

6✔
484
    this.startValue = this.activeValue;
6✔
485
    this.updateSlider(event.clientX);
6✔
486

6✔
487
    this.setPointerCapture(event.pointerId);
6✔
488
    this.pointerCaptured = true;
6✔
489
    this.showThumbLabels();
6✔
490
    event.preventDefault();
6✔
491
    this.activeThumb?.part.remove('focused');
6✔
492
  }
6✔
493

10✔
494
  private pointerMove(event: PointerEvent) {
10✔
495
    if (this.pointerCaptured) {
14✔
496
      this.updateSlider(event.clientX);
14✔
497
    }
14✔
498
  }
14✔
499

10✔
500
  private lostPointerCapture() {
10✔
501
    this.pointerCaptured = false;
5✔
502
    this.hideThumbLabels();
5✔
503

5✔
504
    if (this.startValue! !== this.activeValue) {
5✔
505
      this.emitChangeEvent();
5✔
506
    }
5✔
507
    this.startValue = undefined;
5✔
508
  }
5✔
509

10✔
510
  protected handleThumbFocus(event: FocusEvent) {
10✔
511
    this.activeThumb = event.target as HTMLElement;
3✔
512
  }
3✔
513

10✔
514
  protected handleThumbBlur() {
10✔
515
    this.activeThumb?.part.remove('focused');
7✔
516
    this.activeThumb = undefined;
7✔
517
  }
7✔
518

10✔
519
  protected *_renderTicks() {
10✔
520
    const total = this.totalTickCount();
187✔
521
    const secondaryTicks = this.secondaryTicks + 1;
187✔
522

187✔
523
    for (let i = 0; i < total; i++) {
187✔
524
      const primary = this.isPrimary(i);
139✔
525
      const shown = primary ? this.hidePrimaryLabels : this.hideSecondaryLabels;
139✔
526
      const labelInner = this.hasLabels
139✔
527
        ? primary
6✔
528
          ? this.labels[Math.round(i / secondaryTicks)]
6!
UNCOV
529
          : nothing
✔
530
        : this.formatValue(this.tickValue(i));
133✔
531

139✔
532
      yield html`<div part="tick-group">
139✔
533
        <div part="tick" data-primary=${primary}>
139✔
534
          ${shown
139✔
535
            ? nothing
11✔
536
            : html`
128✔
537
                <div part="tick-label">
128✔
538
                  <span part="tick-label-inner">${labelInner}</span>
128✔
539
                </div>
139✔
540
              `}
139✔
541
        </div>
139✔
542
      </div>`;
139✔
543
    }
139✔
544
  }
187✔
545

10✔
546
  protected renderTicks() {
10✔
547
    return html`<div part="ticks">${this._renderTicks()}</div>`;
187✔
548
  }
187✔
549

10✔
550
  protected renderThumb(value: number, ariaLabel?: string, thumbId?: string) {
10✔
551
    const percent = `${asPercent(value - this.min, this.distance)}%`;
133✔
552
    const thumbStyles = { insetInlineStart: percent };
133✔
553
    const tooltipStyles = {
133✔
554
      insetInlineStart: percent,
133✔
555
      opacity: this.thumbLabelsVisible ? 1 : 0,
133✔
556
    };
133✔
557

133✔
558
    const textValue = this.hasLabels
133✔
559
      ? this.labels[value]
2✔
560
      : this.valueFormat || this.valueFormatOptions
131✔
561
        ? this.formatValue(value)
2✔
562
        : undefined;
129✔
563

133✔
564
    return html`
133✔
565
      <div
133✔
566
        part="thumb"
133✔
567
        id=${ifDefined(thumbId)}
133✔
568
        tabindex=${this.disabled ? -1 : 0}
133✔
569
        style=${styleMap(thumbStyles)}
133✔
570
        role="slider"
133✔
571
        aria-valuemin=${this.lowerBound}
133✔
572
        aria-valuemax=${this.upperBound}
133✔
573
        aria-valuenow=${value}
133✔
574
        aria-valuetext=${ifDefined(textValue)}
133✔
575
        aria-label=${ifDefined(ariaLabel)}
133✔
576
        aria-disabled=${this.disabled}
133✔
577
        @pointerenter=${this.showThumbLabels}
133✔
578
        @pointerleave=${this.hideThumbLabels}
133✔
579
        @focus=${this.handleThumbFocus}
133✔
580
        @blur=${this.handleThumbBlur}
133✔
581
      ></div>
133✔
582
      ${this.hideTooltip
133✔
583
        ? nothing
1✔
584
        : html`
132✔
585
            <div part="thumb-label" style=${styleMap(tooltipStyles)}>
132✔
586
              <div part="thumb-label-inner">
132✔
587
                ${this.hasLabels ? this.labels[value] : this.formatValue(value)}
132✔
588
              </div>
133✔
589
            </div>
133✔
590
          `}
133✔
591
    `;
133✔
592
  }
133✔
593

10✔
594
  private renderSteps() {
10✔
595
    if (!this.discreteTrack || !this.step) {
186✔
596
      return nothing;
185✔
597
    }
185✔
598

1✔
599
    const interval = (100 * Math.SQRT2 * this.step) / this.distance;
1✔
600

1✔
601
    return html`
1✔
602
      <div part="steps">
1✔
603
        <svg width="100%" height="100%" style="display: flex">
1✔
604
          <line
1✔
605
            x1="0"
1✔
606
            y1="1"
1✔
607
            x2="100%"
1✔
608
            y2="1"
1✔
609
            stroke="currentColor"
1✔
610
            stroke-dasharray="0, calc(${interval}%)"
1✔
611
            stroke-linecap="round"
186✔
612
            stroke-width="2px"
186✔
613
          ></line>
186✔
614
        </svg>
186✔
615
      </div>
186✔
616
    `;
186✔
617
  }
186✔
618

10✔
619
  protected override render() {
10✔
620
    const isStart = this.tickOrientation === 'start';
186✔
621
    const isMirrored = this.tickOrientation === 'mirror';
186✔
622

186✔
623
    return html`
186✔
624
      <div part="base">
186✔
625
        ${isStart || isMirrored ? html`${this.renderTicks()}` : nothing}
186✔
626
        <div part="track">
186✔
627
          <div part="inactive"></div>
186✔
628
          <div part="fill" style=${styleMap(this.getTrackStyle())}></div>
186✔
629
          ${this.renderSteps()}
186✔
630
        </div>
186✔
631
        ${!isStart ? html`${this.renderTicks()}` : nothing}
186✔
632
        <div part="thumbs">${this.renderThumbs()}</div>
186✔
633
        <slot @slotchange=${this.handleSlotChange}></slot>
186✔
634
      </div>
186✔
635
    `;
186✔
636
  }
186✔
637
}
10✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc