UNPKG

react-native-form-model

Version:

An easily testable and opinionated React Native form model builder written in pure JavaScript.

103 lines (92 loc) 2.67 kB
import moment, { Moment } from 'moment'; import { Observable, Subject } from 'rxjs'; import { finalize } from 'rxjs/operators'; import { safeKeyList } from './util'; export type DateUnit = | 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year'; export const kDateUnitsAsc = safeKeyList<DateUnit>({ millisecond: 1, second: 1, minute: 1, hour: 1, day: 1, month: 1, year: 1, }); export const kDateUnitsDes: typeof kDateUnitsAsc = kDateUnitsAsc .slice() .reverse(); export const isDateUnit = (unit: any): unit is DateUnit => { return kDateUnitsAsc.indexOf(unit as any) >= 0; }; /** * Triggers a callback on every `options.significantUnit` change * in the local time zone. * @param callback * @param options.significantUnit `day` by default. * @returns obj.cancel A cancel function */ export const significantTimeChanges = ( options: { significantUnit: moment.unitOfTime.Base; } = { significantUnit: 'day', } ): Observable<Moment> => { const { significantUnit } = options; if (!moment.normalizeUnits(significantUnit)) { throw new Error(`Invalid date unit: ${significantUnit}`); } let periodTimer: any; const stream = new Subject<Moment>(); let waitForNext = () => { const now = moment(); const periodEnd = now .clone() .startOf(significantUnit) .add(1, significantUnit); const msLeft = periodEnd.valueOf() - now.valueOf(); periodTimer = setTimeout(() => { periodTimer = 0; stream.next(periodEnd); waitForNext(); }, msLeft); }; waitForNext(); const cleanup = () => { periodTimer && clearTimeout(periodTimer); periodTimer = 0; (waitForNext as any) = undefined; }; return stream.pipe(finalize(() => cleanup())); }; export const destructureDuration = ( duration: moment.Duration ): [number, DateUnit] => { let dateUnit: DateUnit | undefined; let unitValue = 0; for (const calUnit of kDateUnitsDes) { const value = duration.get(calUnit); if (value === 0 || isNaN(value)) { continue; } if (isDateUnit(calUnit)) { if (dateUnit) { throw new Error( `Durations with multiple units is not supported` ); } dateUnit = calUnit; unitValue = value; } else { throw new Error(`Duration unit ${calUnit} is not supported`); } } return [unitValue, dateUnit || 'millisecond']; };