/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import {InjectionToken} from '@angular/core'; import {DateAdapter, MatDateFormats} from '@angular/material/core'; /** Pattern that interval strings have to match. */ const INTERVAL_PATTERN = /^(\d*\.?\d+)\s*(h|hour|hours|m|min|minute|minutes|s|second|seconds)?$/i; /** * Object that can be used to configure the default options for the timepicker component. */ export interface MatTimepickerConfig { /** Default interval for all time pickers. */ interval?: string | number; /** Whether ripples inside the timepicker should be disabled by default. */ disableRipple?: boolean; } /** * Injection token that can be used to configure the default options for the timepicker component. */ export const MAT_TIMEPICKER_CONFIG = new InjectionToken( 'MAT_TIMEPICKER_CONFIG', ); /** * Time selection option that can be displayed within a `mat-timepicker`. */ export interface MatTimepickerOption { /** Date value of the option. */ value: D; /** Label to show to the user. */ label: string; } /** Parses an interval value into seconds. */ export function parseInterval(value: number | string | null): number | null { let result: number; if (value === null) { return null; } else if (typeof value === 'number') { result = value; } else { if (value.trim().length === 0) { return null; } const parsed = value.match(INTERVAL_PATTERN); const amount = parsed ? parseFloat(parsed[1]) : null; const unit = parsed?.[2]?.toLowerCase() || null; if (!parsed || amount === null || isNaN(amount)) { return null; } if (unit === 'h' || unit === 'hour' || unit === 'hours') { result = amount * 3600; } else if (unit === 'm' || unit === 'min' || unit === 'minute' || unit === 'minutes') { result = amount * 60; } else { result = amount; } } return result; } /** * Generates the options to show in a timepicker. * @param adapter Date adapter to be used to generate the options. * @param formats Formatting config to use when displaying the options. * @param min Time from which to start generating the options. * @param max Time at which to stop generating the options. * @param interval Amount of seconds between each option. */ export function generateOptions( adapter: DateAdapter, formats: MatDateFormats, min: D, max: D, interval: number, ): MatTimepickerOption[] { const options: MatTimepickerOption[] = []; let current = adapter.compareTime(min, max) < 1 ? min : max; while ( adapter.sameDate(current, min) && adapter.compareTime(current, max) < 1 && adapter.isValid(current) ) { options.push({value: current, label: adapter.format(current, formats.display.timeOptionLabel)}); current = adapter.addSeconds(current, interval); } return options; } /** Checks whether a date adapter is set up correctly for use with the timepicker. */ export function validateAdapter( adapter: DateAdapter | null, formats: MatDateFormats | null, ) { function missingAdapterError(provider: string) { return Error( `MatTimepicker: No provider found for ${provider}. You must add one of the following ` + `to your app config: provideNativeDateAdapter, provideDateFnsAdapter, ` + `provideLuxonDateAdapter, provideMomentDateAdapter, or provide a custom implementation.`, ); } if (!adapter) { throw missingAdapterError('DateAdapter'); } if (!formats) { throw missingAdapterError('MAT_DATE_FORMATS'); } if ( formats.display.timeInput === undefined || formats.display.timeOptionLabel === undefined || formats.parse.timeInput === undefined ) { throw new Error( 'MatTimepicker: Incomplete `MAT_DATE_FORMATS` has been provided. ' + '`MAT_DATE_FORMATS` must provide `display.timeInput`, `display.timeOptionLabel` ' + 'and `parse.timeInput` formats in order to be compatible with MatTimepicker.', ); } }