Skip to content

Commit

Permalink
feat(player): new showMs prop on slider value component
Browse files Browse the repository at this point in the history
closes #1172
  • Loading branch information
mihar-22 committed Feb 20, 2024
1 parent e804c19 commit 4e23e26
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 44 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/hooks/options/use-chapter-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function useChapterOptions(): ChapterOptions {
cue,
label: cue.text,
value: i.toString(),
startTimeText: formatTime(Math.max(0, cue.startTime - $startTime), false),
startTimeText: formatTime(Math.max(0, cue.startTime - $startTime)),
durationText: formatSpokenTime(
Math.min($endTime, cue.endTime) - Math.max($startTime, cue.startTime),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class ChaptersRadioGroup extends Component<
cue,
value: i.toString(),
label: cue.text,
startTime: formatTime(Math.max(0, cue.startTime - startTime), false),
startTime: formatTime(Math.max(0, cue.startTime - startTime)),
duration: formatSpokenTime(
Math.min(endTime, cue.endTime) - Math.max(startTime, cue.startTime),
),
Expand Down
24 changes: 17 additions & 7 deletions packages/vidstack/src/components/ui/sliders/slider-value.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
Component,
computed,
effect,
method,
useContext,
useState,
Expand All @@ -27,6 +26,7 @@ export class SliderValue extends Component<SliderValueProps> {
type: 'pointer',
format: null,
showHours: false,
showMs: false,
padHours: null,
padMinutes: null,
decimalPlaces: 2,
Expand All @@ -47,7 +47,7 @@ export class SliderValue extends Component<SliderValueProps> {
*/
@method
getValueText() {
const { type, format, decimalPlaces, padHours, padMinutes, showHours } = this.$props,
const { type, format, decimalPlaces, padHours, padMinutes, showHours, showMs } = this.$props,
{ value: sliderValue, pointerValue, min, max } = this._slider,
_format = format() ?? this._format.default;

Expand All @@ -58,7 +58,12 @@ export class SliderValue extends Component<SliderValueProps> {
const percent = (value / range) * 100;
return (this._format.percent ?? round)(percent, decimalPlaces()) + '﹪';
} else if (_format === 'time') {
return (this._format.time ?? formatTime)(value, padHours(), padMinutes(), showHours());
return (this._format.time ?? formatTime)(value, {
padHrs: padHours(),
padMins: padMinutes(),
showHrs: showHours(),
showMs: showMs(),
});
} else {
return this._format.value?.(value) ?? value.toFixed(2);
}
Expand All @@ -77,28 +82,33 @@ export interface SliderValueProps {
format: 'value' | 'percent' | 'time' | null;
/**
* Whether the time should always show the hours unit, even if the time is less than
* 1 hour. Only available if the `format` attribute is set to `time`.
* 1 hour. Only available if the `format` prop is set to `time`.
*
* @example `20:30 -> 0:20:35`
*/
showHours: boolean;
/**
* Whether the time should display milliseconds. Only available if the `format` prop is set to
* `time`.
*/
showMs: boolean;
/**
* Whether the hours unit should be padded with zeroes to a length of 2. Only available if
* the `format` attribute is set to `time`.
* the `format` prop is set to `time`.
*
* @example `1:20:03 -> 01:20:03`
*/
padHours: boolean | null;
/**
* Whether the minutes unit should be padded with zeroes to a length of 2. Setting this to `null`
* will pad minutes when hours is >=1. Only available if the `format` attribute is set to `time`.
* will pad minutes when hours is >=1. Only available if the `format` prop is set to `time`.
*
* @example `5:22 -> 05:22`
*/
padMinutes: boolean | null;
/**
* Round the value when formatted as a percentage to the given number of decimal places. Only
* available if `format` attribute is `percent`.
* available if `format` prop is `percent`.
*/
decimalPlaces: number;
}
9 changes: 3 additions & 6 deletions packages/vidstack/src/components/ui/sliders/slider/format.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { createContext } from 'maverick.js';

import type { FormatTimeOptions } from '../../../../utils/time';

export const sliderValueFormatContext = createContext<SliderValueFormat>(() => ({}));

export interface SliderValueFormat {
default?: 'value' | 'percent' | 'time';
value?(value: number): string;
percent?(percent: number, decimalPlaces: number): string;
time?(
value: number,
padHours: boolean | null,
padMinutes: boolean | null,
showHours: boolean,
): string;
time?(value: number, options?: FormatTimeOptions): string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { TextTrack } from '../../../../core/tracks/text/text-track';
import { watchActiveTextTrack } from '../../../../core/tracks/text/utils';
import { setAttributeIfEmpty } from '../../../../utils/dom';
import { round } from '../../../../utils/number';
import { formatSpokenTime, formatTime } from '../../../../utils/time';
import { formatSpokenTime, formatTime, type FormatTimeOptions } from '../../../../utils/time';
import type { SliderCSSVars } from '../slider/api/cssvars';
import type {
SliderDragEndEvent,
Expand Down Expand Up @@ -261,18 +261,13 @@ export class TimeSlider extends Component<
return Number.isFinite(time) ? (live() ? time - duration() : time).toFixed(0) : 'LIVE';
}

private _formatTime(
percent: number,
padHours: boolean | null,
padMinutes: boolean | null,
showHours: boolean,
) {
private _formatTime(percent: number, options?: FormatTimeOptions) {
const time = this._percentToTime(percent),
{ live, duration } = this._media.$state,
value = live() ? time - duration() : time;

return Number.isFinite(time)
? `${value < 0 ? '-' : ''}${formatTime(Math.abs(value), padHours, padMinutes, showHours)}`
? `${value < 0 ? '-' : ''}${formatTime(Math.abs(value), options)}`
: 'LIVE';
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/vidstack/src/components/ui/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ export class Time extends Component<TimeProps, TimeState> {
}

const time = shouldInvert ? Math.max(0, duration - seconds) : seconds,
formattedTime = formatTime(time, padHours(), padMinutes(), showHours());
formattedTime = formatTime(time, {
padHrs: padHours(),
padMins: padMinutes(),
showHrs: showHours(),
});

this.$state.timeText.set((shouldInvert ? '-' : '') + formattedTime);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const icons = {
'kb-volume-up': volumeHigh,
'kb-volume-down': volumeLow,
'kb-fs-enter': fsEnter,
'kb-fs-exit': fsEnter,
'kb-fs-exit': fsExit,
'kb-pip-enter': pipEnter,
'kb-pip-exit': pipExit,
'kb-cc-on': ccOn,
Expand Down
14 changes: 9 additions & 5 deletions packages/vidstack/src/utils/time.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,17 @@ describe(formatTime.name, function () {
expect(formatTime(45296)).to.equal('12:34:56');
});

it('it should pad hours if `shouldPadHours` is true', function () {
expect(formatTime(3600, true)).to.equal('01:00:00');
it('it should pad hours', function () {
expect(formatTime(3600, { padHrs: true })).to.equal('01:00:00');
});

it('it should display hours if `shouldAlwaysShowHours` is true', function () {
expect(formatTime(3500, false, false, true)).to.equal('0:58:20');
expect(formatTime(3500, true, false, true)).to.equal('00:58:20');
it('it should display hours', function () {
expect(formatTime(3500, { showHrs: true })).to.equal('0:58:20');
expect(formatTime(3500, { showHrs: true, padHrs: true })).to.equal('00:58:20');
});

it('it should display ms', function () {
expect(formatTime(2501.5, { showMs: true })).to.equal('41:41.5');
});
});

Expand Down
29 changes: 15 additions & 14 deletions packages/vidstack/src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ export function parseTime(duration: number): ParsedTime {
};
}

export interface FormatTimeOptions {
padHrs?: boolean | null;
padMins?: boolean | null;
showHrs?: boolean;
showMs?: boolean;
}

/**
* Formats the given `duration` into a human readable form that can be displayed to the user.
*
Expand All @@ -65,23 +72,17 @@ export function parseTime(duration: number): ParsedTime {
*/
export function formatTime(
duration: number,
shouldPadHours: boolean | null = null,
shouldPadMinutes: boolean | null = null,
shouldAlwaysShowHours = false,
{ padHrs = null, padMins = null, showHrs = false, showMs = false }: FormatTimeOptions = {},
): string {
const { hours, minutes, seconds } = parseTime(duration),
paddedHours = shouldPadHours ? padNumberWithZeroes(hours, 2) : hours,
const { hours, minutes, seconds, fraction } = parseTime(duration),
paddedHours = padHrs ? padNumberWithZeroes(hours, 2) : hours,
paddedMinutes =
shouldPadMinutes || (isNull(shouldPadMinutes) && duration >= 3600)
? padNumberWithZeroes(minutes, 2)
: minutes,
paddedSeconds = padNumberWithZeroes(seconds, 2);

if (hours > 0 || shouldAlwaysShowHours) {
return `${paddedHours}:${paddedMinutes}:${paddedSeconds}`;
}
padMins || (isNull(padMins) && duration >= 3600) ? padNumberWithZeroes(minutes, 2) : minutes,
paddedSeconds = padNumberWithZeroes(seconds, 2),
paddedMs = showMs && fraction > 0 ? `.${String(fraction).replace(/^0?\./, '')}` : '',
time = `${paddedMinutes}:${paddedSeconds}${paddedMs}`;

return `${paddedMinutes}:${paddedSeconds}`;
return hours > 0 || showHrs ? `${paddedHours}:${time}` : time;
}

/**
Expand Down

0 comments on commit 4e23e26

Please sign in to comment.