@@ -16,7 +16,7 @@ import { IDynamicPerson, ViewType } from '../../graph/types';
1616import { Providers , ProviderState , MgtTemplatedComponent } from '@microsoft/mgt-element' ;
1717import '../../styles/style-helper' ;
1818import '../sub-components/mgt-spinner/mgt-spinner' ;
19- import { debounce } from '../../utils/Utils' ;
19+ import { debounce , isValidEmail } from '../../utils/Utils' ;
2020import { MgtPerson , PersonViewType } from '../mgt-person/mgt-person' ;
2121import { PersonCardInteraction } from '../PersonCardInteraction' ;
2222import { MgtFlyout } from '../sub-components/mgt-flyout/mgt-flyout' ;
@@ -299,6 +299,18 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
299299 } )
300300 public disabled : boolean ;
301301
302+ /**
303+ * Determines if a user can enter an email without selecting a person
304+ *
305+ * @type {boolean }
306+ * @memberof MgtPeoplePicker
307+ */
308+ @property ( {
309+ attribute : 'allow-any-email' ,
310+ type : Boolean
311+ } )
312+ public allowAnyEmail : boolean ;
313+
302314 /**
303315 * Determines whether component allows multiple or single selection of people
304316 *
@@ -361,6 +373,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
361373 this . showMax = 6 ;
362374
363375 this . disabled = false ;
376+ this . allowAnyEmail = false ;
364377 }
365378
366379 /**
@@ -520,15 +533,17 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
520533 if ( ! this . selectedPeople || ! this . selectedPeople . length ) {
521534 return null ;
522535 }
523-
524536 return html `
525537 ${ selectedPeople . slice ( 0 , selectedPeople . length ) . map (
526538 person =>
527539 html `
528540 < div class ="selected-list__person-wrapper ">
529541 ${
530- this . renderTemplate ( 'selected-person' , { person } , `selected-${ person . id } ` ) ||
531- this . renderSelectedPerson ( person )
542+ this . renderTemplate (
543+ 'selected-person' ,
544+ { person } ,
545+ `selected-${ person . id ? person . id : person . displayName } `
546+ ) || this . renderSelectedPerson ( person )
532547 }
533548
534549 < div class ="selected-list__person-wrapper__overflow ">
@@ -849,6 +864,9 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
849864 protected removePerson ( person : IDynamicPerson , e : MouseEvent ) : void {
850865 e . stopPropagation ( ) ;
851866 const filteredPersonArr = this . selectedPeople . filter ( p => {
867+ if ( ! person . id && p . displayName ) {
868+ return p . displayName !== person . displayName ;
869+ }
852870 return p . id !== person . id ;
853871 } ) ;
854872 this . selectedPeople = filteredPersonArr ;
@@ -865,7 +883,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
865883 if ( person ) {
866884 this . clearInput ( ) ;
867885 const duplicatePeople = this . selectedPeople . filter ( p => {
868- if ( ! person . id ) {
886+ if ( ! person . id && p . displayName ) {
869887 return p . displayName === person . displayName ;
870888 }
871889 return p . id === person . id ;
@@ -964,10 +982,14 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
964982 // keyCodes capture: down arrow (40), right arrow (39), up arrow (38) and left arrow (37)
965983 return ;
966984 }
967- if ( event . keyCode === 9 && ! this . flyout . isOpen ) {
985+
986+ if ( event . code === 'Tab' && ! this . flyout . isOpen ) {
968987 // keyCodes capture: tab (9)
969- this . gainedFocus ( ) ;
988+ if ( this . allowAnyEmail ) {
989+ this . gainedFocus ( ) ;
990+ }
970991 }
992+
971993 if ( event . shiftKey ) {
972994 this . gainedFocus ( ) ;
973995 }
@@ -984,9 +1006,35 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
9841006 this . hideFlyout ( ) ;
9851007 // fire selected people changed event
9861008 this . fireCustomEvent ( 'selectionChanged' , this . selectedPeople ) ;
1009+ } else if ( event . code === 'Comma' || event . code === 'Semicolon' ) {
1010+ if ( this . allowAnyEmail ) {
1011+ event . preventDefault ( ) ;
1012+ event . stopPropagation ( ) ;
1013+ }
1014+ return ;
9871015 } else {
9881016 this . userInput = input . value ;
989- this . handleUserSearch ( ) ;
1017+ const validEmail = isValidEmail ( this . userInput ) ;
1018+ if ( ! validEmail ) {
1019+ this . handleUserSearch ( ) ;
1020+ }
1021+ }
1022+ }
1023+
1024+ private handleAnyEmail ( ) {
1025+ this . _showLoading = false ;
1026+ this . _arrowSelectionCount = 0 ;
1027+ if ( isValidEmail ( this . userInput ) ) {
1028+ const anyMailUser = {
1029+ mail : this . userInput ,
1030+ displayName : this . userInput
1031+ } ;
1032+ this . addPerson ( anyMailUser ) ;
1033+ }
1034+ this . hideFlyout ( ) ;
1035+ if ( this . input ) {
1036+ this . input . focus ( ) ;
1037+ this . _isFocused = true ;
9901038 }
9911039 }
9921040
@@ -1044,17 +1092,33 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
10441092 event . preventDefault ( ) ;
10451093 }
10461094 }
1047- if ( event . keyCode === 9 || event . keyCode === 13 ) {
1095+
1096+ const input = event . target as HTMLInputElement ;
1097+ if ( event . code === 'Tab' || event . code === 'Enter' ) {
10481098 if ( ! event . shiftKey && this . _foundPeople ) {
10491099 // keyCodes capture: tab (9) and enter (13)
1100+ event . preventDefault ( ) ;
1101+ event . stopPropagation ( ) ;
10501102 if ( this . _foundPeople . length ) {
10511103 this . fireCustomEvent ( 'blur' ) ;
1052- event . preventDefault ( ) ;
10531104 }
1054- this . addPerson ( this . _foundPeople [ this . _arrowSelectionCount ] ) ;
1105+
1106+ const foundPerson = this . _foundPeople [ this . _arrowSelectionCount ] ;
1107+ if ( foundPerson ) {
1108+ this . addPerson ( foundPerson ) ;
1109+ } else if ( this . allowAnyEmail ) {
1110+ this . handleAnyEmail ( ) ;
1111+ }
10551112 }
10561113 this . hideFlyout ( ) ;
10571114 ( event . target as HTMLInputElement ) . value = '' ;
1115+ } else if ( event . code === 'Comma' || event . code === 'Semicolon' ) {
1116+ if ( this . allowAnyEmail ) {
1117+ event . preventDefault ( ) ;
1118+ event . stopPropagation ( ) ;
1119+ this . userInput = input . value ;
1120+ this . handleAnyEmail ( ) ;
1121+ }
10581122 }
10591123 }
10601124
0 commit comments