From 0422bc7bb44ee0122485870980e5b13e4ad34670 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Fri, 25 Sep 2020 15:57:08 -0700 Subject: [PATCH 01/18] basic drop over input, still bugs --- .../DoubleUnifiedPeoplePicker.Example.tsx | 5 +++++ .../UnifiedPeoplePicker.Example.tsx | 5 +++++ .../UnifiedPeoplePicker.WithEdit.Example.tsx | 5 +++++ .../UnifiedPicker/UnifiedPicker.tsx | 19 +++++++++++++++++-- .../UnifiedPicker/hooks/useSelectedItems.ts | 6 ++++++ 5 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx index c634c90e76cfc..8b5a1fdca5f2d 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx @@ -162,6 +162,11 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach(draggedItem => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index df27f168a9d50..b6a38fb5e2ecc 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -143,6 +143,11 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach(draggedItem => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index d0534023fc9c5..d7d253adaffc1 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -173,6 +173,11 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach(draggedItem => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 524f84c52c6e2..9b444b940630b 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -118,8 +118,17 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. return !focusedItemIndices.includes(dropContext!.index); }; - const _onDrop = (item?: any, event?: DragEvent): void => { + const _onDropAutoFill = (event?: DragEvent) => { + insertIndex = selectedItems.length; + _onDropInner(event); + }; + + const _onDropList = (item?: any, event?: DragEvent): void => { insertIndex = selectedItems.indexOf(item); + _onDropInner(event); + }; + + const _onDropInner = (event?: DragEvent): void => { let isDropHandled = false; if (event?.dataTransfer) { event.preventDefault(); @@ -175,12 +184,16 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. setDraggedIndex(-1); }; + const _onDragOver = (event?: React.DragEvent) => { + event?.preventDefault(); + }; + const defaultDragDropEvents: IDragDropEvents = { canDrop: _canDrop, canDrag: () => true, onDragEnter: _onDragEnter, onDragLeave: () => undefined, - onDrop: _onDrop, + onDrop: _onDropList, onDragStart: _onDragStart, onDragEnd: _onDragEnd, }; @@ -364,6 +377,8 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. aria-haspopup="listbox" role="combobox" className={css('ms-BasePicker-div', classNames.pickerDiv)} + onDrop={_onDropAutoFill} + onDragOver={_onDragOver} > ( updatedItems.push(item); } } + // if the insert index is at the end, add them now + if (insertIndex === currentItems.length) { + itemsToAdd.forEach(draggedItem => { + updatedItems.push(draggedItem); + }); + } setSelectedItems(updatedItems); selection.setItems(updatedItems); }; From 0f8775a0726661557583d4036518dfe9809882d7 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Wed, 30 Sep 2020 14:53:46 -0700 Subject: [PATCH 02/18] check key to find index on drop instead of compare --- .../src/components/UnifiedPicker/UnifiedPicker.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 9b444b940630b..f7297f0b28f6a 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -20,8 +20,9 @@ import { IFloatingSuggestionItemProps } from '../../FloatingSuggestionsComposite import { getTheme } from 'office-ui-fabric-react/lib/Styling'; import { mergeStyles } from '@uifabric/merge-styles'; import { IDragDropContext } from 'office-ui-fabric-react/lib/utilities/dragdrop/interfaces'; +import { BaseSelectedItem } from '../SelectedItemsList/index'; -export const UnifiedPicker = (props: IUnifiedPickerProps): JSX.Element => { +export const UnifiedPicker = (props: IUnifiedPickerProps): JSX.Element => { const getClassNames = classNamesFunction(); const classNames = getClassNames(getStyles); @@ -124,7 +125,7 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. }; const _onDropList = (item?: any, event?: DragEvent): void => { - insertIndex = selectedItems.indexOf(item); + insertIndex = selectedItems.findIndex(currentItem => currentItem.key === item.key); _onDropInner(event); }; From 1ebf7ac5a8644f074f129d8ffaa6288e6c973974 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 11:12:23 -0700 Subject: [PATCH 03/18] add compare function prop --- .../DoubleUnifiedPeoplePicker.Example.tsx | 5 +++++ .../UnifiedPeoplePicker.Example.tsx | 5 +++++ .../UnifiedPeoplePicker.WithEdit.Example.tsx | 5 +++++ .../SelectedItemsList/SelectedItemsList.types.ts | 2 ++ .../src/components/UnifiedPicker/UnifiedPicker.tsx | 10 +++++++--- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx index 8b5a1fdca5f2d..6de5372ab6445 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx @@ -171,6 +171,10 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { } }; + const _itemsAreEqual = (item1?: any, item2?: any): boolean => { + return item1?.key == item2?.key; + }; + const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { // Updating the local copy as well at the parent level. const currentItems: IPersonaProps[] = [...peopleSelectedItems]; @@ -218,6 +222,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { serializeItemsForDrag: _serializeItemsForDrag, deserializeItemsFromDrop: _deserializeItemsFromDrop, dropItemsAt: _dropItemsAt, + itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index b6a38fb5e2ecc..a78d6e2c2fb3d 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -124,6 +124,10 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); }; + const _itemsAreEqual = (item1?: any, item2?: any): boolean => { + return item1?.key == item2?.key; + }; + const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { // Insert those items into the current list if (insertIndex > -1) { @@ -207,6 +211,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { onItemsRemoved: _onItemsRemoved, getItemCopyText: _getItemsCopyText, dropItemsAt: _dropItemsAt, + itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index d7d253adaffc1..574a72567b1e7 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -154,6 +154,10 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); }; + const _itemsAreEqual = (item1?: any, item2?: any): boolean => { + return item1?.key == item2?.key; + }; + const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { // Insert those items into the current list if (insertIndex > -1) { @@ -249,6 +253,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { dropItemsAt: _dropItemsAt, onRenderItem: SelectedItem, replaceItem: _replaceItem, + itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts b/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts index dded16bd4eabb..bbac6e2ea6a2b 100644 --- a/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts +++ b/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts @@ -134,4 +134,6 @@ export interface ISelectedItemsListProps extends React.ClassAttributes { * Callback for when an item needs to be replaced with another item or items */ replaceItem?: (newItem: T | T[], index: number) => void; + + itemsAreEqual?: (item1?: any, item2?: any) => boolean; } diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index f7297f0b28f6a..d2b46f2b07da2 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -20,9 +20,8 @@ import { IFloatingSuggestionItemProps } from '../../FloatingSuggestionsComposite import { getTheme } from 'office-ui-fabric-react/lib/Styling'; import { mergeStyles } from '@uifabric/merge-styles'; import { IDragDropContext } from 'office-ui-fabric-react/lib/utilities/dragdrop/interfaces'; -import { BaseSelectedItem } from '../SelectedItemsList/index'; -export const UnifiedPicker = (props: IUnifiedPickerProps): JSX.Element => { +export const UnifiedPicker = (props: IUnifiedPickerProps): JSX.Element => { const getClassNames = classNamesFunction(); const classNames = getClassNames(getStyles); @@ -125,7 +124,12 @@ export const UnifiedPicker = (props: IUnifiedPickerP }; const _onDropList = (item?: any, event?: DragEvent): void => { - insertIndex = selectedItems.findIndex(currentItem => currentItem.key === item.key); + insertIndex = selectedItems.findIndex(currentItem => + props.selectedItemsListProps.itemsAreEqual + ? props.selectedItemsListProps.itemsAreEqual(currentItem, item) + : false, + ); + _onDropInner(event); }; From 63fc0cbf063015fdb560e4e1ac5efc0096aa51f8 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 11:16:57 -0700 Subject: [PATCH 04/18] add indexof fallback --- .../UnifiedPeoplePicker.Example.tsx | 5 ----- .../components/UnifiedPicker/UnifiedPicker.tsx | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index a78d6e2c2fb3d..b6a38fb5e2ecc 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -124,10 +124,6 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); }; - const _itemsAreEqual = (item1?: any, item2?: any): boolean => { - return item1?.key == item2?.key; - }; - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { // Insert those items into the current list if (insertIndex > -1) { @@ -211,7 +207,6 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { onItemsRemoved: _onItemsRemoved, getItemCopyText: _getItemsCopyText, dropItemsAt: _dropItemsAt, - itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index d2b46f2b07da2..25e203d3e8bb5 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -124,11 +124,19 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. }; const _onDropList = (item?: any, event?: DragEvent): void => { - insertIndex = selectedItems.findIndex(currentItem => - props.selectedItemsListProps.itemsAreEqual - ? props.selectedItemsListProps.itemsAreEqual(currentItem, item) - : false, - ); + /* indexOf compares using strict equality + if the item is something where properties can change frequently, then the + itemsAreEqual prop should be overloaded + Otherwise it's possible for the indexOf check to fail and return -1 */ + if (props.selectedItemsListProps.itemsAreEqual) { + insertIndex = selectedItems.findIndex(currentItem => + props.selectedItemsListProps.itemsAreEqual + ? props.selectedItemsListProps.itemsAreEqual(currentItem, item) + : false, + ); + } else { + insertIndex = selectedItems.indexOf(item); + } _onDropInner(event); }; From cf623b02081bd67ffc1395951c3d347bf544539c Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 11:52:20 -0700 Subject: [PATCH 05/18] fix compile problem --- .../components/UnifiedPicker/UnifiedPicker.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 25e203d3e8bb5..822eb7fcfca2c 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -118,9 +118,10 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. return !focusedItemIndices.includes(dropContext!.index); }; - const _onDropAutoFill = (event?: DragEvent) => { + const _onDropAutoFill = (event?: React.DragEvent) => { insertIndex = selectedItems.length; - _onDropInner(event); + event?.preventDefault(); + _onDropInner(event?.dataTransfer); }; const _onDropList = (item?: any, event?: DragEvent): void => { @@ -138,14 +139,14 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. insertIndex = selectedItems.indexOf(item); } - _onDropInner(event); + event?.preventDefault(); + _onDropInner(event?.dataTransfer !== null ? event?.dataTransfer : undefined); }; - const _onDropInner = (event?: DragEvent): void => { + const _onDropInner = (dataTransfer?: DataTransfer): void => { let isDropHandled = false; - if (event?.dataTransfer) { - event.preventDefault(); - const data = event.dataTransfer.items; + if (dataTransfer) { + const data = dataTransfer.items; for (let i = 0; i < data.length; i++) { if (data[i].kind === 'string' && data[i].type === props.customClipboardType) { isDropHandled = true; From e516b018ac66a297066e35856b5e13941554abdd Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 14:02:20 -0700 Subject: [PATCH 06/18] add prop to disable drag drop --- .../UnifiedPeoplePicker.WithEdit.Example.tsx | 1 + .../SelectedPeopleList/Items/SelectedPersona.tsx | 2 +- .../src/components/UnifiedPicker/UnifiedPicker.tsx | 13 ++++++++++--- .../components/UnifiedPicker/UnifiedPicker.types.ts | 6 ++++++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index 574a72567b1e7..4883357cfaf7a 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -271,6 +271,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + defaultDragDropEnabled={false} /> ); diff --git a/packages/experiments/src/components/SelectedItemsList/SelectedPeopleList/Items/SelectedPersona.tsx b/packages/experiments/src/components/SelectedItemsList/SelectedPeopleList/Items/SelectedPersona.tsx index 5e8bc6825fe02..db96946463f3c 100644 --- a/packages/experiments/src/components/SelectedItemsList/SelectedPeopleList/Items/SelectedPersona.tsx +++ b/packages/experiments/src/components/SelectedItemsList/SelectedPeopleList/Items/SelectedPersona.tsx @@ -103,7 +103,7 @@ const SelectedPersonaInner = React.memo( ); const isDraggable = React.useMemo( - () => (dragDropEvents ? !!(dragDropEvents.canDrag && dragDropEvents.canDrop) : undefined), + () => (dragDropEvents && dragDropEvents.canDrag ? !!dragDropEvents.canDrag!() : undefined), [dragDropEvents], ); diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 822eb7fcfca2c..559e7d938b774 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -75,6 +75,11 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. onInputChange, } = props; + const defaultDragDropEnabled = React.useMemo( + () => (props.defaultDragDropEnabled != undefined ? props.defaultDragDropEnabled : true), + [props.defaultDragDropEnabled], + ); + React.useImperativeHandle(props.componentRef, () => ({ clearInput: () => { if (input.current) { @@ -115,7 +120,7 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. }; const _canDrop = (dropContext?: IDragDropContext, dragContext?: IDragDropContext): boolean => { - return !focusedItemIndices.includes(dropContext!.index); + return defaultDragDropEnabled && !focusedItemIndices.includes(dropContext!.index); }; const _onDropAutoFill = (event?: React.DragEvent) => { @@ -199,12 +204,14 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. }; const _onDragOver = (event?: React.DragEvent) => { - event?.preventDefault(); + if (defaultDragDropEnabled) { + event?.preventDefault(); + } }; const defaultDragDropEvents: IDragDropEvents = { canDrop: _canDrop, - canDrag: () => true, + canDrag: () => defaultDragDropEnabled, onDragEnter: _onDragEnter, onDragLeave: () => undefined, onDrop: _onDropList, diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts index e2f9cd8aaa647..eadc4d0efb81f 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts @@ -95,4 +95,10 @@ export interface IUnifiedPickerProps { * if this is used */ customClipboardType?: string; + + /** + * If dragDropEvents is set, this property will be ignored + * @defaultvalue true + */ + defaultDragDropEnabled?: boolean; } From e4070f368df4ac4249731e11852ee6dafd0a9abf Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 14:03:11 -0700 Subject: [PATCH 07/18] fix function name --- .../src/components/UnifiedPicker/UnifiedPicker.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 559e7d938b774..6347c095d5310 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -203,7 +203,7 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. setDraggedIndex(-1); }; - const _onDragOver = (event?: React.DragEvent) => { + const _onDragOverAutofill = (event?: React.DragEvent) => { if (defaultDragDropEnabled) { event?.preventDefault(); } @@ -399,7 +399,7 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. role="combobox" className={css('ms-BasePicker-div', classNames.pickerDiv)} onDrop={_onDropAutoFill} - onDragOver={_onDragOver} + onDragOver={_onDragOverAutofill} > Date: Thu, 1 Oct 2020 14:25:18 -0700 Subject: [PATCH 08/18] add props for the autofill drop --- .../UnifiedPeoplePicker.Example.tsx | 1 + .../UnifiedPicker/UnifiedPicker.tsx | 31 ++++++++++++------- .../UnifiedPicker/UnifiedPicker.types.ts | 13 ++++++++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index b6a38fb5e2ecc..49a01dbffb4c6 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -224,6 +224,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + autofillDragDropEnabled={false} /> ); diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 6347c095d5310..3a8fbfbd16b94 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -80,6 +80,11 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. [props.defaultDragDropEnabled], ); + const autofillDragDropEnabled = React.useMemo( + () => (props.autofillDragDropEnabled != undefined ? props.defaultDragDropEnabled : defaultDragDropEnabled), + [props.defaultDragDropEnabled, defaultDragDropEnabled], + ); + React.useImperativeHandle(props.componentRef, () => ({ clearInput: () => { if (input.current) { @@ -119,14 +124,24 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. insertIndex = -1; }; - const _canDrop = (dropContext?: IDragDropContext, dragContext?: IDragDropContext): boolean => { - return defaultDragDropEnabled && !focusedItemIndices.includes(dropContext!.index); + const _onDragOverAutofill = (event?: React.DragEvent) => { + if (autofillDragDropEnabled) { + event?.preventDefault(); + } }; const _onDropAutoFill = (event?: React.DragEvent) => { - insertIndex = selectedItems.length; - event?.preventDefault(); - _onDropInner(event?.dataTransfer); + if (props.onDropAutoFill) { + props.onDropAutoFill(event); + } else { + insertIndex = selectedItems.length; + event?.preventDefault(); + _onDropInner(event?.dataTransfer); + } + }; + + const _canDrop = (dropContext?: IDragDropContext, dragContext?: IDragDropContext): boolean => { + return defaultDragDropEnabled && !focusedItemIndices.includes(dropContext!.index); }; const _onDropList = (item?: any, event?: DragEvent): void => { @@ -203,12 +218,6 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. setDraggedIndex(-1); }; - const _onDragOverAutofill = (event?: React.DragEvent) => { - if (defaultDragDropEnabled) { - event?.preventDefault(); - } - }; - const defaultDragDropEvents: IDragDropEvents = { canDrop: _canDrop, canDrag: () => defaultDragDropEnabled, diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts index eadc4d0efb81f..f30cff30af86e 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.types.ts @@ -101,4 +101,17 @@ export interface IUnifiedPickerProps { * @defaultvalue true */ defaultDragDropEnabled?: boolean; + + /** + * If this property is not specified, defaultDragDropEnabled will be used + * @defaultvalue true + */ + autofillDragDropEnabled?: boolean; + + /** + * Function to customize drop behavior over the autofill portion + * If this is not set, but autofillDragDropEnabled is, the built + * in drop behavior will be used. + */ + onDropAutoFill?: (event?: React.DragEvent) => void; } From 41f89f63afe097da4beb0e7a67f86054ffae84bb Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 14:39:17 -0700 Subject: [PATCH 09/18] comments, fix lint failures --- .../DoubleUnifiedPeoplePicker.Example.tsx | 2 +- .../UnifiedPeoplePicker.WithEdit.Example.tsx | 34 ------------------- .../SelectedItemsList.types.ts | 4 +++ .../UnifiedPicker/UnifiedPicker.tsx | 6 ++-- 4 files changed, 8 insertions(+), 38 deletions(-) diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx index 6de5372ab6445..7591956aafce1 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx @@ -172,7 +172,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { }; const _itemsAreEqual = (item1?: any, item2?: any): boolean => { - return item1?.key == item2?.key; + return item1?.key === item2?.key; }; const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index 4883357cfaf7a..1ce5b62defcbe 100644 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -154,38 +154,6 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); }; - const _itemsAreEqual = (item1?: any, item2?: any): boolean => { - return item1?.key == item2?.key; - }; - - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { - // Insert those items into the current list - if (insertIndex > -1) { - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = []; - - for (let i = 0; i < currentItems.length; i++) { - const item = currentItems[i]; - // If this is the insert before index, insert the dragged items, then the current item - if (i === insertIndex) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - updatedItems.push(item); - } else if (!indicesToRemove.includes(i)) { - // only insert items into the new list that are not being dragged - updatedItems.push(item); - } - } - if (insertIndex === currentItems.length) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - } - setPeopleSelectedItems(updatedItems); - } - }; - const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { // Updating the local copy as well at the parent level. const currentItems: IPersonaProps[] = [...peopleSelectedItems]; @@ -250,10 +218,8 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { removeButtonAriaLabel: 'Remove', onItemsRemoved: _onItemsRemoved, getItemCopyText: _getItemsCopyText, - dropItemsAt: _dropItemsAt, onRenderItem: SelectedItem, replaceItem: _replaceItem, - itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts b/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts index bbac6e2ea6a2b..d9d5619968930 100644 --- a/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts +++ b/packages/experiments/src/components/SelectedItemsList/SelectedItemsList.types.ts @@ -135,5 +135,9 @@ export interface ISelectedItemsListProps extends React.ClassAttributes { */ replaceItem?: (newItem: T | T[], index: number) => void; + /** + * Callback to check to see if two items are equal + * Should be used if it's possible to change some properties on items so a strict compare will fail + */ itemsAreEqual?: (item1?: any, item2?: any) => boolean; } diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 3a8fbfbd16b94..ac2d895740079 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -76,13 +76,13 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. } = props; const defaultDragDropEnabled = React.useMemo( - () => (props.defaultDragDropEnabled != undefined ? props.defaultDragDropEnabled : true), + () => (props.defaultDragDropEnabled !== undefined ? props.defaultDragDropEnabled : true), [props.defaultDragDropEnabled], ); const autofillDragDropEnabled = React.useMemo( - () => (props.autofillDragDropEnabled != undefined ? props.defaultDragDropEnabled : defaultDragDropEnabled), - [props.defaultDragDropEnabled, defaultDragDropEnabled], + () => (props.autofillDragDropEnabled !== undefined ? props.autofillDragDropEnabled : defaultDragDropEnabled), + [props.autofillDragDropEnabled, defaultDragDropEnabled], ); React.useImperativeHandle(props.componentRef, () => ({ From fcf6d3229622d38cb0d7bda0b0d9ed7e4eebe773 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Thu, 1 Oct 2020 14:40:51 -0700 Subject: [PATCH 10/18] fix test failures --- .../__snapshots__/UnifiedPeoplePicker.test.tsx.snap | 4 ++++ .../UnifiedPicker/__snapshots__/UnifiedPicker.test.tsx.snap | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap b/packages/experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap index ebb7a71f801da..fa229df32ab92 100644 --- a/packages/experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap +++ b/packages/experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap @@ -69,6 +69,8 @@ exports[`UnifiedPeoplePicker renders correctly with no items 1`] = ` display: flex; flex: 1 1 auto; } + onDragOver={[Function]} + onDrop={[Function]} role="combobox" > Date: Tue, 6 Oct 2020 13:21:10 -0700 Subject: [PATCH 11/18] properly delete files --- .../DoubleUnifiedPeoplePicker.Example.tsx | 255 --------------- .../UnifiedPeoplePicker.Example.tsx | 231 -------------- .../UnifiedPeoplePicker.WithEdit.Example.tsx | 301 ------------------ 3 files changed, 787 deletions(-) delete mode 100644 packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx delete mode 100644 packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx delete mode 100644 packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx deleted file mode 100644 index 7591956aafce1..0000000000000 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import * as React from 'react'; -import { - IFloatingSuggestionItemProps, - IFloatingSuggestionItem, - IFloatingPeopleSuggestionsProps, -} from '@uifabric/experiments/lib/FloatingPeopleSuggestionsComposite'; -import { UnifiedPeoplePicker } from '@uifabric/experiments/lib/UnifiedPeoplePicker'; -import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona'; -import { mru, people } from '@uifabric/example-data'; -import { ISelectedPeopleListProps } from '@uifabric/experiments/lib/SelectedItemsList'; -import { IInputProps } from 'office-ui-fabric-react'; - -const _suggestions = [ - { - key: '1', - id: '1', - displayText: 'Suggestion 1', - item: mru[0], - isSelected: true, - showRemoveButton: true, - }, - { - key: '2', - id: '2', - displayText: 'Suggestion 2', - item: mru[1], - isSelected: false, - showRemoveButton: true, - }, - { - key: '3', - id: '3', - displayText: 'Suggestion 3', - item: mru[2], - isSelected: false, - showRemoveButton: true, - }, - { - key: '4', - id: '4', - displayText: 'Suggestion 4', - item: mru[3], - isSelected: false, - showRemoveButton: true, - }, - { - key: '5', - id: '5', - displayText: 'Suggestion 5', - item: mru[4], - isSelected: false, - showRemoveButton: true, - }, -] as IFloatingSuggestionItem[]; - -const UnifiedPeoplePickerExample = (): JSX.Element => { - const [peopleSuggestions, setPeopleSuggestions] = React.useState[]>([ - ..._suggestions, - ]); - - const [peopleSelectedItems, setPeopleSelectedItems] = React.useState([]); - - const _onSuggestionSelected = ( - ev: React.MouseEvent, - item: IFloatingSuggestionItemProps, - ) => { - _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); - }; - - const _onSuggestionRemoved = ( - ev: React.MouseEvent, - suggestionToRemove: IFloatingSuggestionItemProps, - ) => { - // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the - // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); - return modifiedSuggestions; - }); - }; - - const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => - suggestion.id === selectedSuggestion.id - ? { ...suggestion, isSelected: true } - : { ...suggestion, isSelected: false }, - ); - return modifiedSuggestions; - }); - }; - - const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { - let copyText = ''; - if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { - copyText = copyText.concat((item.text || '') + ','); - }); - } - - return copyText; - }; - - const _onPaste = (pastedValue: string, selectedItemsList: IPersonaProps[]): void => { - // Find the suggestion corresponding to the specific text name - // and update the selectedItemsList to re-render everything. - const newList: IPersonaProps[] = []; - if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { - if (textValue) { - people.forEach(suggestionItem => { - if (suggestionItem.text === textValue) { - selectedItemsList.push(suggestionItem); - newList.push(suggestionItem); - } - }); - } - }); - } - - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); - }; - - const _serializeItemsForDrag = (items: IPersonaProps[]): string => { - return _getItemsCopyText(items); - }; - - const _deserializeItemsFromDrop = (input: string): IPersonaProps[] => { - // Turn the dropped text into items - const newItems: IPersonaProps[] = []; - if (input !== null) { - input.split(',').forEach(textValue => { - if (textValue) { - people.forEach(suggestionItem => { - if (suggestionItem.text === textValue) { - newItems.push(suggestionItem); - } - }); - } - }); - } - return newItems; - }; - - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { - // Insert those items into the current list - if (insertIndex > -1) { - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = []; - - for (let i = 0; i < currentItems.length; i++) { - const item = currentItems[i]; - // If this is the insert before index, insert the dragged items, then the current item - if (i === insertIndex) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - updatedItems.push(item); - } else if (!indicesToRemove.includes(i)) { - // only insert items into the new list that are not being dragged - updatedItems.push(item); - } - } - if (insertIndex === currentItems.length) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - } - setPeopleSelectedItems(updatedItems); - } - }; - - const _itemsAreEqual = (item1?: any, item2?: any): boolean => { - return item1?.key === item2?.key; - }; - - const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { - // Updating the local copy as well at the parent level. - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = currentItems; - // Intentionally not using .filter here as we want to only remove a specific - // item in case of duplicates of same item. - itemsToRemove.forEach(item => { - const index: number = updatedItems.indexOf(item); - updatedItems.splice(index, 1); - }); - setPeopleSelectedItems(updatedItems); - }; - - const _onInputChange = (filterText: string): void => { - const allPeople = people; - const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { - return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; - }); - // We want to show top 5 results - setPeopleSuggestions(suggestionList.splice(0, 5)); - }; - - function _startsWith(text: string, filterText: string): boolean { - return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0; - } - - const floatingPeoplePickerProps = { - suggestions: [...peopleSuggestions], - isSuggestionsVisible: false, - targetElement: null, - onSuggestionSelected: _onSuggestionSelected, - onRemoveSuggestion: _onSuggestionRemoved, - suggestionsHeaderText: 'People suggestions', - noResultsFoundText: 'No suggestions', - onFloatingSuggestionsDismiss: undefined, - showSuggestionRemoveButton: true, - } as IFloatingPeopleSuggestionsProps; - - const selectedPeopleListProps = { - selectedItems: [...peopleSelectedItems], - removeButtonAriaLabel: 'Remove', - onItemsRemoved: _onItemsRemoved, - getItemCopyText: _getItemsCopyText, - serializeItemsForDrag: _serializeItemsForDrag, - deserializeItemsFromDrop: _deserializeItemsFromDrop, - dropItemsAt: _dropItemsAt, - itemsAreEqual: _itemsAreEqual, - } as ISelectedPeopleListProps; - - const inputProps = { - 'aria-label': 'Add people', - } as IInputProps; - - return ( - <> - - - ); -}; - -export const DoubleUnifiedPeoplePickerExample = (): JSX.Element => { - return ( - <> - To: - CC: - - ); -}; diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx deleted file mode 100644 index 49a01dbffb4c6..0000000000000 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import * as React from 'react'; -import { - IFloatingSuggestionItemProps, - IFloatingSuggestionItem, - IFloatingPeopleSuggestionsProps, -} from '@uifabric/experiments/lib/FloatingPeopleSuggestionsComposite'; -import { UnifiedPeoplePicker } from '@uifabric/experiments/lib/UnifiedPeoplePicker'; -import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona'; -import { mru, people } from '@uifabric/example-data'; -import { ISelectedPeopleListProps } from '@uifabric/experiments/lib/SelectedItemsList'; -import { IInputProps } from 'office-ui-fabric-react'; - -const _suggestions = [ - { - key: '1', - id: '1', - displayText: 'Suggestion 1', - item: mru[0], - isSelected: true, - showRemoveButton: true, - }, - { - key: '2', - id: '2', - displayText: 'Suggestion 2', - item: mru[1], - isSelected: false, - showRemoveButton: true, - }, - { - key: '3', - id: '3', - displayText: 'Suggestion 3', - item: mru[2], - isSelected: false, - showRemoveButton: true, - }, - { - key: '4', - id: '4', - displayText: 'Suggestion 4', - item: mru[3], - isSelected: false, - showRemoveButton: true, - }, - { - key: '5', - id: '5', - displayText: 'Suggestion 5', - item: mru[4], - isSelected: false, - showRemoveButton: true, - }, -] as IFloatingSuggestionItem[]; - -export const UnifiedPeoplePickerExample = (): JSX.Element => { - const [peopleSuggestions, setPeopleSuggestions] = React.useState[]>([ - ..._suggestions, - ]); - - const [peopleSelectedItems, setPeopleSelectedItems] = React.useState([]); - - const ref = React.useRef(); - - const _onSuggestionSelected = ( - ev: React.MouseEvent, - item: IFloatingSuggestionItemProps, - ) => { - _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); - }; - - const _onSuggestionRemoved = ( - ev: React.MouseEvent, - suggestionToRemove: IFloatingSuggestionItemProps, - ) => { - // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the - // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); - return modifiedSuggestions; - }); - }; - - const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => - suggestion.id === selectedSuggestion.id - ? { ...suggestion, isSelected: true } - : { ...suggestion, isSelected: false }, - ); - return modifiedSuggestions; - }); - }; - - const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { - let copyText = ''; - if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { - copyText = copyText.concat((item.text || '') + ','); - }); - } - - return copyText; - }; - - const _onPaste = (pastedValue: string, selectedItemsList: IPersonaProps[]): void => { - // Find the suggestion corresponding to the specific text name - // and update the selectedItemsList to re-render everything. - const newList: IPersonaProps[] = []; - if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { - if (textValue) { - people.forEach(suggestionItem => { - if (suggestionItem.text === textValue) { - selectedItemsList.push(suggestionItem); - newList.push(suggestionItem); - } - }); - } - }); - } - - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); - }; - - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { - // Insert those items into the current list - if (insertIndex > -1) { - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = []; - - for (let i = 0; i < currentItems.length; i++) { - const item = currentItems[i]; - // If this is the insert before index, insert the dragged items, then the current item - if (i === insertIndex) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - updatedItems.push(item); - } else if (!indicesToRemove.includes(i)) { - // only insert items into the new list that are not being dragged - updatedItems.push(item); - } - } - if (insertIndex === currentItems.length) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - } - setPeopleSelectedItems(updatedItems); - } - }; - - const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { - // Updating the local copy as well at the parent level. - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = currentItems; - // Intentionally not using .filter here as we want to only remove a specific - // item in case of duplicates of same item. - itemsToRemove.forEach(item => { - const index: number = updatedItems.indexOf(item); - updatedItems.splice(index, 1); - }); - setPeopleSelectedItems(updatedItems); - }; - - const _onInputChange = (filterText: string): void => { - // Clear the input if the user types a semicolon or comma - // This is meant to be an example of using the forward ref, - // feel free to comment out if it impacts your testing - const lastCharIndex = filterText.length - 1; - const lastChar = filterText[lastCharIndex]; - if (lastChar === ';' || lastChar === ',') { - ref.current?.clearInput(); - } - - const allPeople = people; - const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { - return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; - }); - // We want to show top 5 results - setPeopleSuggestions(suggestionList.splice(0, 5)); - }; - - function _startsWith(text: string, filterText: string): boolean { - return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0; - } - - const floatingPeoplePickerProps = { - suggestions: [...peopleSuggestions], - isSuggestionsVisible: false, - targetElement: null, - onSuggestionSelected: _onSuggestionSelected, - onRemoveSuggestion: _onSuggestionRemoved, - suggestionsHeaderText: 'People suggestions', - noResultsFoundText: 'No suggestions', - onFloatingSuggestionsDismiss: undefined, - showSuggestionRemoveButton: true, - pickerWidth: '300px', - } as IFloatingPeopleSuggestionsProps; - - const selectedPeopleListProps = { - selectedItems: [...peopleSelectedItems], - removeButtonAriaLabel: 'Remove', - onItemsRemoved: _onItemsRemoved, - getItemCopyText: _getItemsCopyText, - dropItemsAt: _dropItemsAt, - } as ISelectedPeopleListProps; - - const inputProps = { - 'aria-label': 'Add people', - } as IInputProps; - - return ( - <> - - - ); -}; diff --git a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx deleted file mode 100644 index 1ce5b62defcbe..0000000000000 --- a/packages/examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ /dev/null @@ -1,301 +0,0 @@ -import * as React from 'react'; -import { - IFloatingSuggestionItemProps, - IFloatingSuggestionItem, - IFloatingPeopleSuggestionsProps, -} from '@uifabric/experiments/lib/FloatingPeopleSuggestionsComposite'; -import { UnifiedPeoplePicker } from '@uifabric/experiments/lib/UnifiedPeoplePicker'; -import { IPersonaProps, IPersona } from 'office-ui-fabric-react/lib/Persona'; -import { mru, people } from '@uifabric/example-data'; -import { - ISelectedPeopleListProps, - SelectedPersona, - TriggerOnContextMenu, - EditableItem, - DefaultEditingItem, - EditingItemInnerFloatingPickerProps, -} from '@uifabric/experiments/lib/SelectedItemsList'; -import { IInputProps } from 'office-ui-fabric-react'; -import { SuggestionsStore } from '@uifabric/experiments/lib/FloatingSuggestions'; -import { FloatingPeopleSuggestions } from '@uifabric/experiments/lib/FloatingPeopleSuggestions'; - -const _suggestions = [ - { - key: '1', - id: '1', - displayText: 'Suggestion 1', - item: mru[0], - isSelected: true, - showRemoveButton: true, - }, - { - key: '2', - id: '2', - displayText: 'Suggestion 2', - item: mru[1], - isSelected: false, - showRemoveButton: true, - }, - { - key: '3', - id: '3', - displayText: 'Suggestion 3', - item: mru[2], - isSelected: false, - showRemoveButton: true, - }, - { - key: '4', - id: '4', - displayText: 'Suggestion 4', - item: mru[3], - isSelected: false, - showRemoveButton: true, - }, - { - key: '5', - id: '5', - displayText: 'Suggestion 5', - item: mru[4], - isSelected: false, - showRemoveButton: true, - }, -] as IFloatingSuggestionItem[]; - -export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { - const [peopleSuggestions, setPeopleSuggestions] = React.useState[]>([ - ..._suggestions, - ]); - - const [peopleSelectedItems, setPeopleSelectedItems] = React.useState([]); - - const ref = React.useRef(); - - // Used to resolve suggestions on the editableItem - const model = new ExampleSuggestionsModel(people); - const suggestionsStore = new SuggestionsStore(); - - /** - * Build a custom selected item capable of being edited when the item is right clicked - */ - const SelectedItem = EditableItem({ - itemComponent: TriggerOnContextMenu(SelectedPersona), - editingItemComponent: DefaultEditingItem({ - getEditingItemText: persona => persona.text || '', - onRenderFloatingPicker: (props: EditingItemInnerFloatingPickerProps) => ( - - ), - }), - }); - - const _onSuggestionSelected = ( - ev: React.MouseEvent, - item: IFloatingSuggestionItemProps, - ) => { - _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); - }; - - const _onSuggestionRemoved = ( - ev: React.MouseEvent, - suggestionToRemove: IFloatingSuggestionItemProps, - ) => { - // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the - // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); - return modifiedSuggestions; - }); - }; - - const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => - suggestion.id === selectedSuggestion.id - ? { ...suggestion, isSelected: true } - : { ...suggestion, isSelected: false }, - ); - return modifiedSuggestions; - }); - }; - - const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { - let copyText = ''; - if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { - copyText = copyText.concat((item.text || '') + ','); - }); - } - - return copyText; - }; - - const _onPaste = (pastedValue: string, selectedItemsList: IPersonaProps[]): void => { - // Find the suggestion corresponding to the specific text name - // and update the selectedItemsList to re-render everything. - const newList: IPersonaProps[] = []; - if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { - if (textValue) { - people.forEach(suggestionItem => { - if (suggestionItem.text === textValue) { - selectedItemsList.push(suggestionItem); - newList.push(suggestionItem); - } - }); - } - }); - } - - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); - }; - - const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { - // Updating the local copy as well at the parent level. - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = currentItems; - // Intentionally not using .filter here as we want to only remove a specific - // item in case of duplicates of same item. - itemsToRemove.forEach(item => { - const index: number = updatedItems.indexOf(item); - updatedItems.splice(index, 1); - }); - setPeopleSelectedItems(updatedItems); - }; - - const _replaceItem = (newItem: IPersonaProps | IPersona[], index: number): void => { - const newItemsArray = !Array.isArray(newItem) ? [newItem] : newItem; - - if (index >= 0) { - const newItems: IPersonaProps[] = [...peopleSelectedItems]; - newItems.splice(index, 1, ...newItemsArray); - setPeopleSelectedItems(newItems); - } - }; - - const _onInputChange = (filterText: string): void => { - // Clear the input if the user types a semicolon or comma - // This is meant to be an example of using the forward ref, - // feel free to comment out if it impacts your testing - const lastCharIndex = filterText.length - 1; - const lastChar = filterText[lastCharIndex]; - if (lastChar === ';' || lastChar === ',') { - ref.current?.clearInput(); - } - - const allPeople = people; - const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { - return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; - }); - // We want to show top 5 results - setPeopleSuggestions(suggestionList.splice(0, 5)); - }; - - function _startsWith(text: string, filterText: string): boolean { - return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0; - } - - const floatingPeoplePickerProps = { - suggestions: [...peopleSuggestions], - isSuggestionsVisible: false, - targetElement: null, - onSuggestionSelected: _onSuggestionSelected, - onRemoveSuggestion: _onSuggestionRemoved, - suggestionsHeaderText: 'People suggestions', - noResultsFoundText: 'No suggestions', - onFloatingSuggestionsDismiss: undefined, - showSuggestionRemoveButton: true, - pickerWidth: '300px', - } as IFloatingPeopleSuggestionsProps; - - const selectedPeopleListProps = { - selectedItems: [...peopleSelectedItems], - removeButtonAriaLabel: 'Remove', - onItemsRemoved: _onItemsRemoved, - getItemCopyText: _getItemsCopyText, - onRenderItem: SelectedItem, - replaceItem: _replaceItem, - } as ISelectedPeopleListProps; - - const inputProps = { - 'aria-label': 'Add people', - } as IInputProps; - - return ( - <> - - - ); -}; - -type IBaseExampleType = { - text?: string; - name?: string; -}; - -class ExampleSuggestionsModel { - private suggestionsData: T[]; - - public constructor(data: T[]) { - this.suggestionsData = [...data]; - } - - public resolveSuggestions = (filterText: string, currentItems?: T[]): Promise => { - let filteredItems: T[] = []; - if (filterText) { - filteredItems = this._filterItemsByText(filterText); - filteredItems = this._removeDuplicates(filteredItems, currentItems || []); - } - - return this._convertResultsToPromise(filteredItems); - }; - - public removeSuggestion(item: T) { - const index = this.suggestionsData.indexOf(item); - console.log('removing', item, 'at', index); - if (index !== -1) { - this.suggestionsData.splice(index, 1); - } - } - - private _filterItemsByText(filterText: string): T[] { - return this.suggestionsData.filter((item: T) => { - const itemText = item.text || item.name; - return itemText ? this._doesTextStartWith(itemText, filterText) : false; - }); - } - - private _doesTextStartWith(text: string, filterText: string): boolean { - return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0; - } - - private _removeDuplicates(items: T[], possibleDupes: T[]): T[] { - return items.filter((item: T) => !this._listContainsItem(item, possibleDupes)); - } - - private _listContainsItem(item: T, Items: T[]): boolean { - if (!Items || !Items.length || Items.length === 0) { - return false; - } - return Items.filter((i: T) => (i.text || i.name) === (item.text || item.name)).length > 0; - } - - private _convertResultsToPromise(results: T[]): Promise { - return new Promise(resolve => setTimeout(() => resolve(results), 150)); - } -} From be61ad6bb5264f17350998b7061df2fd5d2ff026 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Tue, 6 Oct 2020 13:24:04 -0700 Subject: [PATCH 12/18] re-add code to examples in correct location --- .../DoubleUnifiedPeoplePicker.Example.tsx | 38 +++++++++----- .../UnifiedPeoplePicker.Example.tsx | 30 ++++++----- .../UnifiedPeoplePicker.WithEdit.Example.tsx | 51 +++++-------------- 3 files changed, 56 insertions(+), 63 deletions(-) diff --git a/packages/react-examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/react-examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx index 89ca76bd10dde..befa8b1941d24 100644 --- a/packages/react-examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ b/packages/react-examples/src/experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx @@ -65,7 +65,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { item: IFloatingSuggestionItemProps, ) => { _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, item.item]); }; const _onSuggestionRemoved = ( @@ -74,15 +74,15 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { ) => { // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.filter((suggestion) => suggestion.item !== suggestionToRemove.item); return modifiedSuggestions; }); }; const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.map((suggestion) => suggestion.id === selectedSuggestion.id ? { ...suggestion, isSelected: true } : { ...suggestion, isSelected: false }, @@ -94,7 +94,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { let copyText = ''; if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { + itemsToCopy.forEach((item) => { copyText = copyText.concat((item.text || '') + ','); }); } @@ -107,9 +107,9 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { // and update the selectedItemsList to re-render everything. const newList: IPersonaProps[] = []; if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { + pastedValue.split(',').forEach((textValue) => { if (textValue) { - people.forEach(suggestionItem => { + people.forEach((suggestionItem) => { if (suggestionItem.text === textValue) { selectedItemsList.push(suggestionItem); newList.push(suggestionItem); @@ -119,7 +119,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { }); } - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, ...newList]); }; const _serializeItemsForDrag = (items: IPersonaProps[]): string => { @@ -130,9 +130,9 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { // Turn the dropped text into items const newItems: IPersonaProps[] = []; if (input !== null) { - input.split(',').forEach(textValue => { + input.split(',').forEach((textValue) => { if (textValue) { - people.forEach(suggestionItem => { + people.forEach((suggestionItem) => { if (suggestionItem.text === textValue) { newItems.push(suggestionItem); } @@ -153,7 +153,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { const item = currentItems[i]; // If this is the insert before index, insert the dragged items, then the current item if (i === insertIndex) { - newItems.forEach(draggedItem => { + newItems.forEach((draggedItem) => { updatedItems.push(draggedItem); }); updatedItems.push(item); @@ -162,17 +162,26 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach((draggedItem) => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; + const _itemsAreEqual = (item1?: any, item2?: any): boolean => { + return item1?.key === item2?.key; + }; + const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { // Updating the local copy as well at the parent level. const currentItems: IPersonaProps[] = [...peopleSelectedItems]; const updatedItems: IPersonaProps[] = currentItems; // Intentionally not using .filter here as we want to only remove a specific // item in case of duplicates of same item. - itemsToRemove.forEach(item => { + itemsToRemove.forEach((item) => { const index: number = updatedItems.indexOf(item); updatedItems.splice(index, 1); }); @@ -182,7 +191,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { const _onInputChange = (filterText: string): void => { const allPeople = people; const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { + const suggestionList = suggestions.map((item) => { return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; }); // We want to show top 5 results @@ -213,6 +222,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { serializeItemsForDrag: _serializeItemsForDrag, deserializeItemsFromDrop: _deserializeItemsFromDrop, dropItemsAt: _dropItemsAt, + itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index 115e65cc8c294..03342cf45146e 100644 --- a/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -67,7 +67,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { item: IFloatingSuggestionItemProps, ) => { _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, item.item]); }; const _onSuggestionRemoved = ( @@ -76,15 +76,15 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { ) => { // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.filter((suggestion) => suggestion.item !== suggestionToRemove.item); return modifiedSuggestions; }); }; const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.map((suggestion) => suggestion.id === selectedSuggestion.id ? { ...suggestion, isSelected: true } : { ...suggestion, isSelected: false }, @@ -96,7 +96,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { let copyText = ''; if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { + itemsToCopy.forEach((item) => { copyText = copyText.concat((item.text || '') + ','); }); } @@ -109,9 +109,9 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { // and update the selectedItemsList to re-render everything. const newList: IPersonaProps[] = []; if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { + pastedValue.split(',').forEach((textValue) => { if (textValue) { - people.forEach(suggestionItem => { + people.forEach((suggestionItem) => { if (suggestionItem.text === textValue) { selectedItemsList.push(suggestionItem); newList.push(suggestionItem); @@ -121,7 +121,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { }); } - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, ...newList]); }; const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { @@ -134,7 +134,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { const item = currentItems[i]; // If this is the insert before index, insert the dragged items, then the current item if (i === insertIndex) { - newItems.forEach(draggedItem => { + newItems.forEach((draggedItem) => { updatedItems.push(draggedItem); }); updatedItems.push(item); @@ -143,6 +143,11 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach((draggedItem) => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; @@ -153,7 +158,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { const updatedItems: IPersonaProps[] = currentItems; // Intentionally not using .filter here as we want to only remove a specific // item in case of duplicates of same item. - itemsToRemove.forEach(item => { + itemsToRemove.forEach((item) => { const index: number = updatedItems.indexOf(item); updatedItems.splice(index, 1); }); @@ -172,7 +177,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { const allPeople = people; const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { + const suggestionList = suggestions.map((item) => { return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; }); // We want to show top 5 results @@ -219,6 +224,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + autofillDragDropEnabled={false} /> ); diff --git a/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index 0f790d864acad..d664102a36e93 100644 --- a/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/react-examples/src/experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -81,7 +81,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { const SelectedItem = EditableItem({ itemComponent: TriggerOnContextMenu(SelectedPersona), editingItemComponent: DefaultEditingItem({ - getEditingItemText: persona => persona.text || '', + getEditingItemText: (persona) => persona.text || '', onRenderFloatingPicker: (props: EditingItemInnerFloatingPickerProps) => ( { item: IFloatingSuggestionItemProps, ) => { _markSuggestionSelected(item); - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, item.item]); + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, item.item]); }; const _onSuggestionRemoved = ( @@ -106,15 +106,15 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { ) => { // Intentionally checking on complete item object to ensure it is removed. Id cannot be used as the // property is not populated for all the suggestions, and key does not exist on type checking. - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.filter(suggestion => suggestion.item !== suggestionToRemove.item); + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.filter((suggestion) => suggestion.item !== suggestionToRemove.item); return modifiedSuggestions; }); }; const _markSuggestionSelected = (selectedSuggestion: IFloatingSuggestionItemProps) => { - setPeopleSuggestions(suggestions => { - const modifiedSuggestions = suggestions.map(suggestion => + setPeopleSuggestions((suggestions) => { + const modifiedSuggestions = suggestions.map((suggestion) => suggestion.id === selectedSuggestion.id ? { ...suggestion, isSelected: true } : { ...suggestion, isSelected: false }, @@ -126,7 +126,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { const _getItemsCopyText = (itemsToCopy: IPersonaProps[]): string => { let copyText = ''; if (itemsToCopy && itemsToCopy.length > 0) { - itemsToCopy.forEach(item => { + itemsToCopy.forEach((item) => { copyText = copyText.concat((item.text || '') + ','); }); } @@ -139,9 +139,9 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { // and update the selectedItemsList to re-render everything. const newList: IPersonaProps[] = []; if (pastedValue !== null) { - pastedValue.split(',').forEach(textValue => { + pastedValue.split(',').forEach((textValue) => { if (textValue) { - people.forEach(suggestionItem => { + people.forEach((suggestionItem) => { if (suggestionItem.text === textValue) { selectedItemsList.push(suggestionItem); newList.push(suggestionItem); @@ -151,30 +151,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { }); } - setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); - }; - - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { - // Insert those items into the current list - if (insertIndex > -1) { - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = []; - - for (let i = 0; i < currentItems.length; i++) { - const item = currentItems[i]; - // If this is the insert before index, insert the dragged items, then the current item - if (i === insertIndex) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - updatedItems.push(item); - } else if (!indicesToRemove.includes(i)) { - // only insert items into the new list that are not being dragged - updatedItems.push(item); - } - } - setPeopleSelectedItems(updatedItems); - } + setPeopleSelectedItems((prevPeopleSelectedItems) => [...prevPeopleSelectedItems, ...newList]); }; const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { @@ -183,7 +160,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { const updatedItems: IPersonaProps[] = currentItems; // Intentionally not using .filter here as we want to only remove a specific // item in case of duplicates of same item. - itemsToRemove.forEach(item => { + itemsToRemove.forEach((item) => { const index: number = updatedItems.indexOf(item); updatedItems.splice(index, 1); }); @@ -212,7 +189,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { const allPeople = people; const suggestions = allPeople.filter((item: IPersonaProps) => _startsWith(item.text || '', filterText)); - const suggestionList = suggestions.map(item => { + const suggestionList = suggestions.map((item) => { return { item: item, isSelected: false, key: item.key } as IFloatingSuggestionItem; }); // We want to show top 5 results @@ -241,7 +218,6 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { removeButtonAriaLabel: 'Remove', onItemsRemoved: _onItemsRemoved, getItemCopyText: _getItemsCopyText, - dropItemsAt: _dropItemsAt, onRenderItem: SelectedItem, replaceItem: _replaceItem, } as ISelectedPeopleListProps; @@ -261,6 +237,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + defaultDragDropEnabled={false} /> ); @@ -319,6 +296,6 @@ class ExampleSuggestionsModel { } private _convertResultsToPromise(results: T[]): Promise { - return new Promise(resolve => setTimeout(() => resolve(results), 150)); + return new Promise((resolve) => setTimeout(() => resolve(results), 150)); } } From 2b87f55bd02a5a9dc8e15c5b39f76f18a42580c5 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Fri, 16 Oct 2020 11:19:05 -0700 Subject: [PATCH 13/18] Change files --- ...-react-examples-2020-10-16-11-19-05-uppdroptarget.json | 8 ++++++++ ...ric-experiments-2020-10-16-11-19-05-uppdroptarget.json | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 change/@fluentui-react-examples-2020-10-16-11-19-05-uppdroptarget.json create mode 100644 change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json diff --git a/change/@fluentui-react-examples-2020-10-16-11-19-05-uppdroptarget.json b/change/@fluentui-react-examples-2020-10-16-11-19-05-uppdroptarget.json new file mode 100644 index 0000000000000..d7827a008424b --- /dev/null +++ b/change/@fluentui-react-examples-2020-10-16-11-19-05-uppdroptarget.json @@ -0,0 +1,8 @@ +{ + "type": "none", + "comment": "Updating the UPP examples to have different drag drop abilities", + "packageName": "@fluentui/react-examples", + "email": "elvonspa@microsoft.com", + "dependentChangeType": "none", + "date": "2020-10-16T18:19:05.441Z" +} diff --git a/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json b/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json new file mode 100644 index 0000000000000..4a36b03dcab9f --- /dev/null +++ b/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json @@ -0,0 +1,8 @@ +{ + "type": "minor", + "comment": "Add props to UPP to disable drag drop, drop to end of list", + "packageName": "@uifabric/experiments", + "email": "elvonspa@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-10-16T18:18:51.868Z" +} From 82fc13575e0e06f954d34a2acf4246ac1abe9afe Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Mon, 19 Oct 2020 10:54:36 -0700 Subject: [PATCH 14/18] fix examples after merge --- .../DoubleUnifiedPeoplePicker.Example.tsx | 10 ++++++++ .../UnifiedPeoplePicker.Example.tsx | 1 + .../UnifiedPeoplePicker.WithEdit.Example.tsx | 25 +------------------ 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx index 2bcf549b953fc..0df5780b4bb30 100644 --- a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx +++ b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/DoubleUnifiedPeoplePicker.Example.tsx @@ -162,10 +162,19 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { updatedItems.push(item); } } + if (insertIndex === currentItems.length) { + newItems.forEach(draggedItem => { + updatedItems.push(draggedItem); + }); + } setPeopleSelectedItems(updatedItems); } }; + const _itemsAreEqual = (item1?: any, item2?: any): boolean => { + return item1?.key === item2?.key; + }; + const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { // Updating the local copy as well at the parent level. const currentItems: IPersonaProps[] = [...peopleSelectedItems]; @@ -213,6 +222,7 @@ const UnifiedPeoplePickerExample = (): JSX.Element => { serializeItemsForDrag: _serializeItemsForDrag, deserializeItemsFromDrop: _deserializeItemsFromDrop, dropItemsAt: _dropItemsAt, + itemsAreEqual: _itemsAreEqual, } as ISelectedPeopleListProps; const inputProps = { diff --git a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx index 936b8e8005071..5c5347d43a032 100644 --- a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx +++ b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.Example.tsx @@ -219,6 +219,7 @@ export const UnifiedPeoplePickerExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + autofillDragDropEnabled={false} /> ); diff --git a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx index 59d74c368e867..cc20c882bd675 100644 --- a/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx +++ b/packages/react-examples/src/react-experiments/UnifiedPeoplePicker/UnifiedPeoplePicker.WithEdit.Example.tsx @@ -154,29 +154,6 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { setPeopleSelectedItems(prevPeopleSelectedItems => [...prevPeopleSelectedItems, ...newList]); }; - const _dropItemsAt = (insertIndex: number, newItems: IPersonaProps[], indicesToRemove: number[]): void => { - // Insert those items into the current list - if (insertIndex > -1) { - const currentItems: IPersonaProps[] = [...peopleSelectedItems]; - const updatedItems: IPersonaProps[] = []; - - for (let i = 0; i < currentItems.length; i++) { - const item = currentItems[i]; - // If this is the insert before index, insert the dragged items, then the current item - if (i === insertIndex) { - newItems.forEach(draggedItem => { - updatedItems.push(draggedItem); - }); - updatedItems.push(item); - } else if (!indicesToRemove.includes(i)) { - // only insert items into the new list that are not being dragged - updatedItems.push(item); - } - } - setPeopleSelectedItems(updatedItems); - } - }; - const _onItemsRemoved = (itemsToRemove: IPersonaProps[]): void => { // Updating the local copy as well at the parent level. const currentItems: IPersonaProps[] = [...peopleSelectedItems]; @@ -241,7 +218,6 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { removeButtonAriaLabel: 'Remove', onItemsRemoved: _onItemsRemoved, getItemCopyText: _getItemsCopyText, - dropItemsAt: _dropItemsAt, onRenderItem: SelectedItem, replaceItem: _replaceItem, } as ISelectedPeopleListProps; @@ -261,6 +237,7 @@ export const UnifiedPeoplePickerWithEditExample = (): JSX.Element => { onInputChange={_onInputChange} // eslint-disable-next-line react/jsx-no-bind onPaste={_onPaste} + defaultDragDropEnabled={false} /> ); From a6af9cf7648b38a6685768e4f3f2da81128c8ad0 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Mon, 19 Oct 2020 11:00:53 -0700 Subject: [PATCH 15/18] remove old change file --- ...ric-experiments-2020-10-16-11-19-05-uppdroptarget.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json diff --git a/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json b/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json deleted file mode 100644 index 4a36b03dcab9f..0000000000000 --- a/change/@uifabric-experiments-2020-10-16-11-19-05-uppdroptarget.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "minor", - "comment": "Add props to UPP to disable drag drop, drop to end of list", - "packageName": "@uifabric/experiments", - "email": "elvonspa@microsoft.com", - "dependentChangeType": "patch", - "date": "2020-10-16T18:18:51.868Z" -} From eae62fb23e756bfebae76ced1a7f03fee4fe2f92 Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Mon, 19 Oct 2020 11:03:03 -0700 Subject: [PATCH 16/18] Change files --- ...act-experiments-2020-10-19-11-03-03-uppdroptarget.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 change/@fluentui-react-experiments-2020-10-19-11-03-03-uppdroptarget.json diff --git a/change/@fluentui-react-experiments-2020-10-19-11-03-03-uppdroptarget.json b/change/@fluentui-react-experiments-2020-10-19-11-03-03-uppdroptarget.json new file mode 100644 index 0000000000000..8992caab7d8a0 --- /dev/null +++ b/change/@fluentui-react-experiments-2020-10-19-11-03-03-uppdroptarget.json @@ -0,0 +1,8 @@ +{ + "type": "minor", + "comment": "Add props to UPP to disable drag drop, drop to end of list", + "packageName": "@fluentui/react-experiments", + "email": "elvonspa@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-10-19T18:03:03.534Z" +} From dfbff0e619b3984627fa411ab31f4be70aee87ca Mon Sep 17 00:00:00 2001 From: Elisabeth von Spakovsky Date: Tue, 20 Oct 2020 12:56:23 -0700 Subject: [PATCH 17/18] generate snapshots --- .../__snapshots__/UnifiedPeoplePicker.test.tsx.snap | 4 ++++ .../__snapshots__/UnifiedPicker.test.tsx.snap | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/react-experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap b/packages/react-experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap index fe595be8eba02..967213ae426b3 100644 --- a/packages/react-experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap +++ b/packages/react-experiments/src/components/UnifiedPicker/UnifiedPeoplePicker/__snapshots__/UnifiedPeoplePicker.test.tsx.snap @@ -61,6 +61,8 @@ exports[`UnifiedPeoplePicker renders correctly with no items 1`] = ` display: flex; flex: 1 1 auto; } + onDragOver={[Function]} + onDrop={[Function]} role="combobox" >
- + red - +
- + green - +
Date: Wed, 21 Oct 2020 11:23:30 -0700 Subject: [PATCH 18/18] address PR comments --- .../src/components/UnifiedPicker/UnifiedPicker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-experiments/src/components/UnifiedPicker/UnifiedPicker.tsx b/packages/react-experiments/src/components/UnifiedPicker/UnifiedPicker.tsx index 12c6947ab6190..fe66000729543 100644 --- a/packages/react-experiments/src/components/UnifiedPicker/UnifiedPicker.tsx +++ b/packages/react-experiments/src/components/UnifiedPicker/UnifiedPicker.tsx @@ -122,11 +122,11 @@ export const UnifiedPicker = (props: IUnifiedPickerProps): JSX. }; const _onDropAutoFill = (event?: React.DragEvent) => { + event?.preventDefault(); if (props.onDropAutoFill) { props.onDropAutoFill(event); } else { insertIndex = selectedItems.length; - event?.preventDefault(); _onDropInner(event?.dataTransfer); } };