UNPKG

ng-voice-inputs

Version:

This library provides Voice Recognition service to fill the form input fields (text, datepicker, textarea, button-click) for Angular application.

989 lines (980 loc) 34.2 kB
import { Subject } from 'rxjs'; import * as moment_ from 'moment/moment'; import { CommonModule } from '@angular/common'; import { Injectable, Directive, ElementRef, Input, ChangeDetectorRef, Component, EventEmitter, Output, ViewEncapsulation, defineInjectable, NgModule } from '@angular/core'; /** * @fileoverview added by tsickle * Generated from: lib/ng-voice-inputs.service.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const moment = moment_; /** @type {?} */ const UNIT = { zero: 0, first: 1, one: 1, second: 2, two: 2, third: 3, thirteenth: 13, thirteen: 13, three: 3, fourth: 4, fourteenth: 14, fourteen: 14, four: 4, fifteenth: 15, fifteen: 15, fifth: 5, five: 5, sixth: 6, sixteenth: 16, sixteen: 16, six: 6, seventeenth: 17, seventeen: 17, seventh: 7, seven: 7, eighteenth: 18, eighteen: 18, eighth: 8, eight: 8, nineteenth: 19, nineteen: 19, ninth: 9, nine: 9, tenth: 10, ten: 10, eleventh: 11, eleven: 11, twelfth: 12, twelve: 12, a: 1, }; /** @type {?} */ const TWOS = { ten: 10, eleven: 11, twelve: 12, thirteen: 13, fourteen: 14, fifteen: 15, sixteen: 16, seventeen: 17, eighteen: 18, nineteen: 19 }; /** @type {?} */ const TEN = { twenty: 20, twentieth: 20, thirty: 30, thirtieth: 30, forty: 40, fortieth: 40, fifty: 50, fiftieth: 50, sixty: 60, sixtieth: 60, seventy: 70, seventieth: 70, eighty: 80, eightieth: 80, ninety: 90, ninetieth: 90, }; /** @type {?} */ const MAGNITUDE = { hundred: 100, hundredth: 100, thousand: 1000, million: 1000000, billion: 1000000000, trillion: 1000000000000, quadrillion: 1000000000000000, quintillion: 1000000000000000000, sextillion: 1000000000000000000000, septillion: 1000000000000000000000000, octillion: 1000000000000000000000000000, nonillion: 1000000000000000000000000000000, decillion: 1000000000000000000000000000000000, }; /** @type {?} */ const NUMBER = Object.assign({}, UNIT, TEN, MAGNITUDE); /** @type {?} */ const SUFFIXES = ['st', 'nd', 'rd', 'th']; /** @type {?} */ const MONTHS = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"]; /** @type {?} */ const KEY_WORDS_FWD_NAV = ['forward', 'next']; /** @type {?} */ const KEY_WORDS_BCK_NAV = ['back', 'backward', 'previous']; /** @type {?} */ const KEY_WORDS_CLEAR = ['clear', 'clean', 'delete', 'remove']; /** @type {?} */ const KEY_WORDS_CLICK = ['click', 'submit', 'expand', 'open', 'show']; /** @type {?} */ const KEY_WORDS_STOP = ['stop', 'end', 'done']; /** @type {?} */ const KEY_WORDS_SCROLL_UP = ['scroll up', 'go up', 'up']; /** @type {?} */ const KEY_WORDS_SCROLL_DOWN = ['scroll down', 'go down', 'down']; /** @type {?} */ const KEY_WORDS_SCROLL_RIGHT = ['scroll right', 'go right', 'right']; /** @type {?} */ const KEY_WORDS_SCROLL_LEFT = ['scroll left', 'go left', 'left']; /** @type {?} */ const KEY_WORDS_SCROLL_TOP = ['scroll top', 'go top', 'top']; /** @type {?} */ const KEY_WORDS_SCROLL_BOTTOM = ['scroll bottom', 'go bottom', 'bottom']; /** @type {?} */ const KEY_WORDS_SCROLL_CONTINUE = ['keep scrolling', 'scroll', 'scrolling', 'continue scrolling']; /** @type {?} */ const KEY_WORDS_SCROLL = [ ...KEY_WORDS_SCROLL_UP, ...KEY_WORDS_SCROLL_DOWN, ...KEY_WORDS_SCROLL_RIGHT, ...KEY_WORDS_SCROLL_LEFT, ...KEY_WORDS_SCROLL_TOP, ...KEY_WORDS_SCROLL_BOTTOM, ...KEY_WORDS_SCROLL_CONTINUE ]; /** @type {?} */ const KEY_WORDS_INST = ['goto', 'switch', 'go', ...KEY_WORDS_CLEAR, ...KEY_WORDS_CLICK, ...KEY_WORDS_SCROLL]; // Instruction types /** @type {?} */ const KEY_WORDS_NAV = [ ...KEY_WORDS_FWD_NAV, ...KEY_WORDS_BCK_NAV, ...KEY_WORDS_STOP, ...KEY_WORDS_SCROLL, 'first', 'last', ]; // Navigation types /** @type {?} */ const KEY_WORDS = [...KEY_WORDS_INST, ...KEY_WORDS_NAV]; /** @type {?} */ const INST_MAPPINGS = { next: KEY_WORDS_FWD_NAV, previous: KEY_WORDS_BCK_NAV, first: ['first'], last: ['last'], clear: KEY_WORDS_CLEAR, click: KEY_WORDS_CLICK, stop: KEY_WORDS_STOP, scrollUp: KEY_WORDS_SCROLL_UP, scrollDown: KEY_WORDS_SCROLL_DOWN, scrollLeft: KEY_WORDS_SCROLL_LEFT, scrollRight: KEY_WORDS_SCROLL_RIGHT, scrollTop: KEY_WORDS_SCROLL_TOP, scrollBottom: KEY_WORDS_SCROLL_BOTTOM, scrollContinue: KEY_WORDS_SCROLL_CONTINUE }; class VuiVoiceRecognitionService { constructor() { this.response = new Subject(); this.inputRefs = []; this.currentRef = 0; } /** * @param {?} speechKeys * @param {?} inputType * @return {?} */ isInputSwitch(speechKeys, inputType) { if (inputType == 'address' && !speechKeys.some((/** * @param {?} key * @return {?} */ key => KEY_WORDS_INST.includes(key)))) { return false; } if (speechKeys.some((/** * @param {?} key * @return {?} */ key => KEY_WORDS.includes(key)))) { return true; } return false; } /** * @param {?} speechText * @param {?} inputType * @return {?} */ findInstructionType(speechText, inputType) { /** @type {?} */ let type = ''; speechText = speechText.trim().toLocaleLowerCase(); /** @type {?} */ let speechKeys = speechText.trim().toLocaleLowerCase().split(' '); if (this.isInputSwitch(speechKeys, inputType)) { /** @type {?} */ const foundKey = Object.keys(INST_MAPPINGS).find((/** * @param {?} instType * @return {?} */ (instType) => speechKeys.some((/** * @param {?} key * @return {?} */ key => INST_MAPPINGS[instType].includes(key))))); type = foundKey ? `COMMAND_${foundKey.toUpperCase()}` : ''; } else { type = 'INPUT'; } return type; } /** * @param {?} speechText * @param {?} inputType * @return {?} */ interpretSpeech(speechText, inputType) { /** @type {?} */ let instType = this.findInstructionType(speechText, inputType); if (instType != 'INPUT') { return instType; } if (inputType == 'text' || inputType == 'address') { return speechText; } if (inputType == 'number') { return this.wordsToNumber(speechText); } if (inputType == 'date') { speechText = speechText.replace('from', ''); /** @type {?} */ let dates = speechText.trim().split('to '); /** @type {?} */ let parsedDates = []; dates.forEach((/** * @param {?} dateStr * @return {?} */ (dateStr) => { parsedDates.push(this.dateParser(dateStr)); })); if (parsedDates[0].isValid()) { return parsedDates; } } return null; } /** * @param {?} dateStr * @return {?} */ dateParser(dateStr) { /** @type {?} */ let parsedDate; /** @type {?} */ let cleanDateStr = dateStr; /** @type {?} */ let dateParts = dateStr.trim().split(' '); /** @type {?} */ let datePartObj = {}; /** @type {?} */ let isPureNumber = false; /** @type {?} */ let cleanDateParts = []; if (dateParts.length == 3) { cleanDateParts = dateParts.map((/** * @param {?} dateStr * @return {?} */ (dateStr) => this.eliminateString(dateStr))); isPureNumber = cleanDateParts.every((/** * @param {?} dateStr * @return {?} */ (dateStr) => Number.isInteger(dateStr))); } if (isPureNumber) { cleanDateStr = cleanDateParts.join('-'); } else { /** @type {?} */ const currentDate = moment(); dateParts.forEach((/** * @param {?} dateStr * @return {?} */ (dateStr) => { datePartObj = this.parseDatePart(dateStr, datePartObj); })); /** @type {?} */ const availableKeys = Object.keys(datePartObj).join('-'); switch (availableKeys) { case 'date': datePartObj.month = currentDate.format('MM'); case 'date-month': datePartObj.year = currentDate.format('YYYY'); break; case 'year': datePartObj.month = '01'; case 'month-year': datePartObj.date = '01'; break; case 'month': datePartObj.year = currentDate.format('YYYY'); datePartObj.date = '01'; } cleanDateStr = this.dateBuilder(datePartObj); } parsedDate = moment(cleanDateStr).toDate(); return parsedDate; } /** * @param {?} datePartObj * @return {?} */ dateBuilder(datePartObj) { /** @type {?} */ let dateStr = ''; dateStr = `${datePartObj.year}-${datePartObj.month}-${datePartObj.date}`; return dateStr; } /** * * @param {?} datePart Incomplete date part eg, '21st' is the date part for the date '21st July 2020' * @param {?} datePartObj // Inherited from caller & updated with parsed object. Can be year, month or date * @return {?} */ parseDatePart(datePart, datePartObj) { if (this.isYearType(datePart)) { /** @type {?} */ const year = this.wordsToNumber(datePart); datePartObj.year = year; } else if (this.isDateType(datePart)) { /** @type {?} */ const date = this.wordsToNumber(datePart); datePartObj.date = date; } else if (this.isMonthType(datePart)) { /** @type {?} */ const month = MONTHS.indexOf(datePart.toUpperCase()) + 1; datePartObj.month = month < 10 ? '0' + month : month; } return datePartObj; } /** * @param {?} datePart * @return {?} */ isDateType(datePart) { /** @type {?} */ let isDatePart = false; isDatePart = (/\d/.test(datePart) && SUFFIXES.includes(datePart.substr(datePart.length - 2))); if (!isDatePart) { /** @type {?} */ const number = this.wordsToNumber(datePart); if (number > 0 && number <= 31) { isDatePart = true; } } return isDatePart; } /** * @param {?} datePart * @param {?} datePartObj * @return {?} */ parseDateVal(datePart, datePartObj) { /** @type {?} */ let isDatePart = false; /** @type {?} */ let convertedNum = 0; isDatePart = SUFFIXES.some((/** * @param {?} key * @return {?} */ (key) => { return datePart.includes(key); })); if (!isDatePart) { convertedNum = this.wordsToNumber(datePart); if (convertedNum > 0 && convertedNum <= 31) { isDatePart = true; } } if (isDatePart) { datePartObj.date = convertedNum; } } /** * @param {?} datePart * @return {?} */ isMonthType(datePart) { /** @type {?} */ const month = MONTHS.indexOf(datePart.toUpperCase()); return month > -1; } /** * @param {?} datePart * @param {?} datePartObj * @return {?} */ parseMonthVal(datePart, datePartObj) { /** @type {?} */ const month = MONTHS.indexOf(datePart.toUpperCase()); if (month > -1) { datePartObj.month = month < 10 ? '0' + month : month; } } /** * @param {?} datePart * @return {?} */ isYearType(datePart) { /** @type {?} */ let year = this.wordsToNumber(datePart); return year > 1000; } /** * @param {?} datePart * @param {?} datePartObj * @return {?} */ parseYearVal(datePart, datePartObj) { /** @type {?} */ const year = this.wordsToNumber(datePart); if (year > 1000) { datePartObj.year = year; } } /** * @param {?} word * @return {?} */ wordsToNumber(word) { // Returning integer if it is not actual word if (!Number.isNaN(parseInt(word))) { return parseInt(word); } word = word.replace(/and/g, ''); // Replace joiners // Replace joiners /** @type {?} */ let words = word.toLowerCase().trim().split(' '); /** @type {?} */ let num = 0; words = this.parseColloquialWords(words); words.forEach((/** * @param {?} wordStr * @return {?} */ wordStr => { wordStr = this.eliminateString(wordStr); if (typeof wordStr == 'number') { num = wordStr; } else { if (UNIT[wordStr]) { num = num + NUMBER[wordStr]; } else if (TEN[wordStr]) { num = num + TEN[wordStr]; } else if (MAGNITUDE[wordStr]) { num = num * MAGNITUDE[wordStr]; } } })); return num; } /** * @param {?} wordsArr * @return {?} */ parseColloquialWords(wordsArr) { if (wordsArr.length == 2) { if (TEN[wordsArr[0]] && (TEN[wordsArr[1]] || TWOS[wordsArr[1]])) { wordsArr.splice(1, 0, 'hundred'); } } if (MAGNITUDE[wordsArr[0]]) { wordsArr.splice(0, 0, 'one'); } return wordsArr; } /** * @param {?} word * @return {?} */ eliminateString(word) { if (/\d/.test(word) && SUFFIXES.includes(word.substr(word.length - 2))) { word = word.substr(0, word.length - 2); // Remove last suffixes such as 'st', 'th' from 1st, 10th word = parseInt(word); } return word; } } VuiVoiceRecognitionService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ VuiVoiceRecognitionService.ngInjectableDef = defineInjectable({ factory: function VuiVoiceRecognitionService_Factory() { return new VuiVoiceRecognitionService(); }, token: VuiVoiceRecognitionService, providedIn: "root" }); /** * @fileoverview added by tsickle * Generated from: lib/vui-input.directive.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const moment$1 = moment_; /** @type {?} */ const DEFAULT_OPTS = { type: 'text', format: 'DD/MM/YYYY' } /** * Options for VuiInput directive * @param type Data type for input. Possible values are: 'text', 'address', 'date', 'number'. Default: 'text' * @param format (Optional) Date format for datepicker input. eg, 'MM/DD/YYYY'. Default: 'DD/MM/YYYY'. */ ; class VuiInputDirective { /** * @param {?} vuiService * @param {?} el */ constructor(vuiService, el) { this.vuiService = vuiService; this.el = el; this.el.nativeElement.setAttribute('vui-ref', this.vuiService.inputRefs.length); this.vuiService.inputRefs.push(this.el); this.el.nativeElement.addEventListener('focus', (/** * @param {?} evt * @return {?} */ (evt) => { this.vuiService.currentRef = parseInt(evt.target.getAttribute('vui-ref')); })); } /** * @return {?} */ ngOnInit() { this.options = Object.assign({}, DEFAULT_OPTS, this.options); this.el['options'] = this.options; } /** * @param {?} date * @return {?} */ formatDate(date) { return moment$1(date).format(this.options.format); } } VuiInputDirective.decorators = [ { type: Directive, args: [{ selector: '[vuiInput]' },] } ]; /** @nocollapse */ VuiInputDirective.ctorParameters = () => [ { type: VuiVoiceRecognitionService }, { type: ElementRef } ]; VuiInputDirective.propDecorators = { options: [{ type: Input, args: ['vuiInput',] }] }; /** * @fileoverview added by tsickle * Generated from: lib/vui-response.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @param type Type of response * Possible values for type are: * 'date-range', 'date', 'text', 'number' * @param value Response value which can be text, number, date * */ class VuiResponse { /** * @param {?=} type * @param {?=} value */ constructor(type, value) { this.type = type || 'text'; this.value = value; } } /** * @fileoverview added by tsickle * Generated from: lib/ng-voice-inputs.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** @type {?} */ const moment$2 = moment_; /** @type {?} */ const DEFAULT_STYLE = { containerClass: 'centered', iconStart: 'icon icon-mic', iconParse: 'icon icon-mic', iconStop: 'icon icon-mic', animationParse: 'parsing', animationListen: 'listening' }; /** @type {?} */ const DEFAULT_SCROLL_OFFSET = 200; /** @type {?} */ const DEFAULT_SCROLL_DURATION = 300; /** @type {?} */ const DEFAULT_SCROLL_DIRECTION = 'vertical'; class NgVoiceInputsComponent { /** * @param {?} vuiService * @param {?} ref */ constructor(vuiService, ref) { this.vuiService = vuiService; this.ref = ref; this.onValueChange = new EventEmitter(); /** * Decides direction of scroll movement ( Up or Down ) or ( Left or Right) * +ve value indicates Down/Right and -ve value idicates Up/Left */ this.activeDirection = +1; /** * Decides direction of Scroll ( Vertical or Horizontal ) */ this.scrollDirection = DEFAULT_SCROLL_DIRECTION; this.scrollToTop = (/** * @param {?} duration * @return {?} */ (duration) => { /** @type {?} */ let interval = setInterval((/** * @return {?} */ () => { /** @type {?} */ var pos = Math.abs(Math.round((window.pageYOffset / (duration / 100)))); if (pos > 0) { window.scrollTo(0, pos - 20); // how far to scroll on each step } else { clearInterval(interval); } }), 100); }); this.scrollBy = (/** * @param {?} offset * @param {?} duration * @param {?=} direction * @return {?} */ (offset, duration, direction) => { this.activeDirection = (offset / offset); this.scrollDirection = direction || DEFAULT_SCROLL_DIRECTION; if (offset == 1) { offset = window.outerHeight; } /** @type {?} */ let val = Math.abs(Math.round((offset / (duration / 100)))); /** @type {?} */ let totalOffset = 0; /** @type {?} */ let interval = setInterval((/** * @return {?} */ () => { if (totalOffset >= Math.abs(offset)) { clearInterval(interval); } else { /** @type {?} */ let opt = { top: offset < 0 ? -1 * val : val, left: 0 }; if (direction == 'horizontal') { opt = { top: 0, left: offset < 0 ? -1 * val : val }; } window.scrollBy(Object.assign({}, opt, { behavior: 'smooth' })); totalOffset = totalOffset + val; } }), 100); }); this.scroll = { SCROLLDOWN: (/** * @return {?} */ () => { this.scrollBy(this.scrollOffset, this.scrollDuration); }), SCROLLUP: (/** * @return {?} */ () => { this.scrollBy(-1 * this.scrollOffset, this.scrollDuration); }), SCROLLRIGHT: (/** * @return {?} */ () => { this.scrollBy(this.scrollOffset, this.scrollDuration, 'horizontal'); }), SCROLLLEFT: (/** * @return {?} */ () => { this.scrollBy(-1 * this.scrollOffset, this.scrollDuration, 'horizontal'); }), SCROLLBOTTOM: (/** * @return {?} */ () => { this.scrollBy(1, this.scrollDuration); }), SCROLLTOP: (/** * @return {?} */ () => { this.scrollToTop(this.scrollDuration); }), SCROLLCONTINUE: (/** * @return {?} */ () => { /** @type {?} */ const factor = Math.ceil(window.outerHeight / this.scrollDuration); console.log(factor * this.scrollDuration, factor); this.scrollBy(window.outerHeight, factor * 1000); }) }; } /** * @return {?} */ ngOnInit() { this.style = Object.assign({}, DEFAULT_STYLE, this.style); this.scrollOffset = this.scrollOffset || DEFAULT_SCROLL_OFFSET; this.scrollDuration = this.scrollDuration || DEFAULT_SCROLL_DURATION; try { this.initVoiceRecognition(); } catch (e) { console.error('Failed to initialize or parse'); this.stopRecognition(); } this.vuiService.response.subscribe(this.vuiResponseSubscription.bind(this)); } /** * @param {?} data * @return {?} */ vuiResponseSubscription(data) { this.transcript = ''; /** @type {?} */ let currentRef = this.vuiService.currentRef; if (data.type == 'COMMAND_NEXT') { currentRef = ++this.vuiService.currentRef; } else if (data.type == 'COMMAND_PREVIOUS') { currentRef = --this.vuiService.currentRef; } else if (data.type == 'COMMAND_FIRST') { currentRef = 0; } else if (data.type == 'COMMAND_LAST') { currentRef = this.vuiService.inputRefs.length - 1; } else if (data.type == 'COMMAND_CLEAR') { this.vuiService.inputRefs[currentRef].nativeElement.value = ''; } else if (data.type == 'COMMAND_CLICK') { this.vuiService.inputRefs[currentRef].nativeElement.click(); } else if (data.type.includes('COMMAND_SCROLL')) { this.scroll[data.type.replace('COMMAND_', '')].call(); } else if (data.type == 'COMMAND_STOP') { this.stopRecognition(); } else { /** @type {?} */ const currentInputObj = this.vuiService.inputRefs[currentRef]; /** @type {?} */ const currentEl = currentInputObj.nativeElement; /** @type {?} */ const opts = currentInputObj['options']; if (data.value && data.value[0] instanceof Date) { if (currentEl.type == 'date' || currentEl.type == 'datetime') { currentEl.value = this.formatDate(data.value[0], 'YYYY-MM-DD'); } else { currentEl.value = this.formatDate(data.value[0], opts && opts.format); } } else { currentEl.value = data.value; } currentEl.dispatchEvent(new Event('input')); this.onValueChange.emit(data); } this.vuiService.inputRefs[currentRef].nativeElement.focus(); this.setProcess('listening'); } /** * @param {?} processType * @return {?} */ setProcess(processType) { this.process = processType; this.ref.detectChanges(); } /** * @param {?} date * @param {?=} format * @return {?} */ formatDate(date, format) { return moment$2(date).format(format || 'DD/MM/YYYY'); } /** * @return {?} */ initVoiceRecognition() { this.recognition = new window['webkitSpeechRecognition'](); this.recognition.continuous = true; this.recognition.interimResults = true; this.recognition.onstart = (/** * @param {?} event * @return {?} */ (event) => { this.setProcess('listening'); }); this.recognition.onresult = (/** * @param {?} event * @return {?} */ (event) => { /** @type {?} */ const currentInputObj = this.vuiService.inputRefs[this.vuiService.currentRef]; /** @type {?} */ const opts = currentInputObj['options']; this.setProcess('parsing'); for (var i = event.resultIndex; i < event.results.length; ++i) { if (event.results[i].isFinal) { this.transcript += event.results[i][0].transcript; /** @type {?} */ let data = this.vuiService.interpretSpeech(this.transcript, opts && opts.type); /** @type {?} */ let resp = new VuiResponse('invalid', data); if (data) { resp = new VuiResponse('date-range', data); if (typeof data == 'string') { resp = new VuiResponse(data, data.includes('_') ? '' : data); } } this.vuiService.response.next(resp); } } }); this.recognition.onerror = (/** * @return {?} */ () => { this.setProcess(null); }); this.recognition.onend = (/** * @return {?} */ () => { this.setProcess(null); }); } /** * @return {?} */ startRecognition() { this.transcript = ''; this.recognition.start(); } /** * @return {?} */ stopRecognition() { this.transcript = ''; this.recognition.stop(); this.setProcess(null); } } NgVoiceInputsComponent.decorators = [ { type: Component, args: [{ selector: 'ng-voice-input', template: ` <div [class]="style.containerClass"> <i [class]="style.iconStart" mat-raised-button (click)="startRecognition()" *ngIf="!process"></i> <i [ngClass]="process == 'parsing' ? style.iconParse + ' ' + style.animationParse : style.iconStop + ' ' + style.animationListen" (click)="stopRecognition()" *ngIf="process"></i> </div> `, encapsulation: ViewEncapsulation.None, styles: [".centered{margin:auto;text-align:center}.listening{color:red}.parsing{color:green}.icon{position:relative;width:45px;height:45px;display:inline-block;background-size:26px 26px;background-position:7px 7px;background-repeat:no-repeat;cursor:pointer}.icon.parsing::after{opacity:0;position:absolute;top:-5px;left:-5px;right:0;bottom:0;content:'';border:3px solid #42c0fb;border-radius:100%;-webkit-animation-name:ripple;animation-name:ripple;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-delay:0s;animation-delay:0s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-timing-function:cubic-bezier(.65,0,.34,1);animation-timing-function:cubic-bezier(.65,0,.34,1);z-index:-1}.icon.parsing::before{opacity:0;position:absolute;top:-5px;left:-5px;right:0;bottom:0;content:'';border:3px solid #42c0fb;border-radius:100%;-webkit-animation-name:ripple;animation-name:ripple;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-timing-function:cubic-bezier(.65,0,.34,1);animation-timing-function:cubic-bezier(.65,0,.34,1);z-index:-1}.icon.listening::after{opacity:0;position:absolute;top:-5px;left:-5px;right:0;bottom:0;content:'';border:3px solid #42c0fb44;border-radius:100%;-webkit-animation-name:ripple;animation-name:ripple;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-delay:0s;animation-delay:0s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-timing-function:cubic-bezier(.65,0,.34,1);animation-timing-function:cubic-bezier(.65,0,.34,1);z-index:-1}.icon-small{width:25px;height:25px;background-size:15px 15px;background-position:5px 10px}.icon-mic{background-image:url(\"data:image/svg+xml;utf8,<svg version='1.0' xmlns='http://www.w3.org/2000/svg' width='853.000000pt' height='1280.000000pt' viewBox='0 0 853.000000 1280.000000' preserveAspectRatio='xMidYMid meet'> <metadata> Created by potrace 1.15, written by Peter Selinger 2001-2017 </metadata> <g transform='translate(0.000000,1280.000000) scale(0.100000,-0.100000)' fill='rgb(66,192,251)' > <path d='M4060 12789 c-194 -22 -402 -81 -577 -164 -472 -224 -789 -626 -894 -1135 l-24 -115 0 -2575 c0 -2452 1 -2579 18 -2665 145 -710 755 -1260 1492 -1345 327 -37 671 21 975 166 473 226 789 629 892 1137 l23 112 0 2575 c0 2448 -1 2579 -18 2665 -116 576 -556 1066 -1134 1264 -227 78 -508 108 -753 80z'/><path d='M301 8004 c-158 -42 -262 -156 -292 -319 -7 -38 -9 -312 -6 -839 3 -648 7 -805 21 -921 64 -538 177 -928 391 -1350 184 -361 380 -630 670 -920 529 -528 1216 -906 2020 -1110 116 -29 231 -56 258 -60 l47 -7 0 -854 0 -854 -657 0 c-717 0 -743 -2 -851 -57 -69 -35 -155 -127 -176 -189 -53 -155 36 -357 203 -463 103 -66 -69 -61 2341 -61 2377 0 2235 -3 2349 54 64 33 144 122 173 194 19 49 23 75 23 182 0 120 -1 128 -32 192 -36 76 -100 146 -165 179 -95 48 -100 49 -820 49 l-678 0 0 854 c0 805 1 855 18 860 9 2 33 7 52 11 406 77 934 271 1313 484 1088 609 1778 1567 1971 2736 48 288 51 352 51 1150 l0 760 -23 58 c-63 155 -190 243 -367 254 -147 10 -260 -32 -350 -129 -32 -34 -63 -80 -76 -115 l-24 -58 -6 -785 c-6 -737 -11 -850 -39 -1050 -100 -705 -417 -1330 -913 -1794 -538 -505 -1229 -810 -2052 -908 -146 -17 -674 -17 -820 0 -663 79 -1253 297 -1735 642 -683 489 -1111 1202 -1230 2050 -28 194 -33 327 -39 1060 l-6 785 -24 58 c-44 111 -161 208 -282 236 -62 15 -175 12 -238 -5z'/></g> </svg>\")}.icon-mic-blue{background-image:url(../../assets/icons/mic-blue-solid.png)}.icon-mic-red{background-image:url(../../assets/icons/mic-red-solid.png)}.icon-mic-green{background-image:url(../../assets/icons/mic-green-solid.png)}@-webkit-keyframes ripple{from{opacity:1;transform:scale3d(.75,.75,1)}to{opacity:0;transform:scale3d(1.5,1.5,1)}}@keyframes ripple{from{opacity:1;transform:scale3d(.75,.75,1)}to{opacity:0;transform:scale3d(1.5,1.5,1)}}"] }] } ]; /** @nocollapse */ NgVoiceInputsComponent.ctorParameters = () => [ { type: VuiVoiceRecognitionService }, { type: ChangeDetectorRef } ]; NgVoiceInputsComponent.propDecorators = { style: [{ type: Input }], scrollOffset: [{ type: Input }], scrollDuration: [{ type: Input }], onValueChange: [{ type: Output }] }; Date.prototype['isValid'] = (/** * @return {?} */ function () { // If the date object is invalid it // will return 'NaN' on getTime() // and NaN is never equal to itself. return this.getTime() === this.getTime(); }); /** * @fileoverview added by tsickle * Generated from: lib/ng-voice-inputs.module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class NgVoiceInputsModule { } NgVoiceInputsModule.decorators = [ { type: NgModule, args: [{ declarations: [ NgVoiceInputsComponent, VuiInputDirective ], imports: [CommonModule], exports: [ NgVoiceInputsComponent, VuiInputDirective ] },] } ]; /** * @fileoverview added by tsickle * Generated from: public_api.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * Generated from: ng-voice-inputs.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { VuiInputDirective, NgVoiceInputsComponent, NgVoiceInputsModule, VuiVoiceRecognitionService as ɵa }; //# sourceMappingURL=ng-voice-inputs.js.map