Skip to content

Commit

Permalink
chore: ass tests and noPopover to context
Browse files Browse the repository at this point in the history
  • Loading branch information
bsunderhus committed Aug 9, 2024
1 parent 979c4da commit 4e1da64
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export type TagPickerProps = ComponentProps<TagPickerSlots> & Pick<ComboboxProps
noPopover?: boolean;
onOpenChange?: EventHandler<TagPickerOnOpenChangeData>;
onOptionSelect?: EventHandler<TagPickerOnOptionSelectData>;
children: [JSX.Element, JSX.Element] | JSX.Element;
children: [JSX.Element, JSX.Element | undefined | false] | JSX.Element;
inline?: boolean;
};

Expand All @@ -231,7 +231,7 @@ export type TagPickerSize = 'medium' | 'large' | 'extra-large';
export type TagPickerSlots = {};

// @public
export type TagPickerState = ComponentState<TagPickerSlots> & Pick<ComboboxState, 'open' | 'activeDescendantController' | 'mountNode' | 'onOptionClick' | 'registerOption' | 'selectedOptions' | 'selectOption' | 'value' | 'setValue' | 'setOpen' | 'setHasFocus' | 'appearance' | 'clearSelection' | 'getOptionById' | 'getOptionsMatchingValue' | 'disabled'> & Pick<TagPickerContextValue, 'triggerRef' | 'secondaryActionRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'tagPickerGroupRef' | 'size'> & {
export type TagPickerState = ComponentState<TagPickerSlots> & Pick<ComboboxState, 'open' | 'activeDescendantController' | 'mountNode' | 'onOptionClick' | 'registerOption' | 'selectedOptions' | 'selectOption' | 'value' | 'setValue' | 'setOpen' | 'setHasFocus' | 'appearance' | 'clearSelection' | 'getOptionById' | 'getOptionsMatchingValue' | 'disabled'> & Pick<TagPickerContextValue, 'triggerRef' | 'secondaryActionRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'tagPickerGroupRef' | 'size' | 'noPopover'> & {
trigger: React_2.ReactNode;
popover?: React_2.ReactNode;
inline: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TagPickerOption } from '../TagPickerOption/TagPickerOption';
import { Avatar } from '@fluentui/react-avatar';
import { Button } from '@fluentui/react-button';

import 'cypress-real-events';
/**
* This error means that ResizeObserver
* was not able to deliver all observations within a single animation frame.
Expand Down Expand Up @@ -40,9 +41,14 @@ const options = [
'Maria Rossi',
];

type TagPickerControlledProps = Pick<TagPickerProps, 'open' | 'defaultOpen' | 'defaultSelectedOptions'>;
type TagPickerControlledProps = Pick<TagPickerProps, 'open' | 'defaultOpen' | 'defaultSelectedOptions' | 'noPopover'>;

const TagPickerControlled = ({ open, defaultOpen, defaultSelectedOptions = [] }: TagPickerControlledProps) => {
const TagPickerControlled = ({
open,
defaultOpen,
defaultSelectedOptions = [],
noPopover = false,
}: TagPickerControlledProps) => {
const [selectedOptions, setSelectedOptions] = React.useState<string[]>(defaultSelectedOptions);
const onOptionSelect: TagPickerProps['onOptionSelect'] = (e, data) => {
setSelectedOptions(data.selectedOptions);
Expand All @@ -54,6 +60,7 @@ const TagPickerControlled = ({ open, defaultOpen, defaultSelectedOptions = [] }:
return (
<div style={{ maxWidth: 400 }}>
<TagPicker
noPopover={noPopover}
onOptionSelect={onOptionSelect}
selectedOptions={selectedOptions}
open={open}
Expand Down Expand Up @@ -89,22 +96,24 @@ const TagPickerControlled = ({ open, defaultOpen, defaultSelectedOptions = [] }:
</TagPickerGroup>
<TagPickerInput data-testid="tag-picker-input" />
</TagPickerControl>
<TagPickerList data-testid="tag-picker-list">
{options
.filter(option => !selectedOptions.includes(option))
.map((option, index) => (
<TagPickerOption
id={`tag-picker-option--${index}`}
data-testid={`tag-picker-option--${option}`}
secondaryContent="Microsoft FTE"
media={<Avatar name={option} color="colorful" />}
value={option}
key={option}
>
{option}
</TagPickerOption>
))}
</TagPickerList>
{noPopover ? undefined : (
<TagPickerList data-testid="tag-picker-list">
{options
.filter(option => !selectedOptions.includes(option))
.map((option, index) => (
<TagPickerOption
id={`tag-picker-option--${index}`}
data-testid={`tag-picker-option--${option}`}
secondaryContent="Microsoft FTE"
media={<Avatar name={option} color="colorful" />}
value={option}
key={option}
>
{option}
</TagPickerOption>
))}
</TagPickerList>
)}
</TagPicker>
</div>
);
Expand Down Expand Up @@ -305,4 +314,11 @@ describe('TagPicker', () => {
});
});
});
it('should not render popover when "noPopover"', () => {
mount(<TagPickerControlled noPopover />);
cy.get('[data-testid="tag-picker-control"]').should('exist');
cy.get('[data-testid="tag-picker-list"]').should('not.exist');
cy.get('[data-testid="tag-picker-input"]').realClick();
cy.get('[data-testid="tag-picker-list"]').should('not.exist');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export type TagPickerProps = ComponentProps<TagPickerSlots> &
/**
* Can contain two children including a trigger and a popover
*/
children: [JSX.Element, JSX.Element] | JSX.Element;
children: [JSX.Element, JSX.Element | undefined | false] | JSX.Element;
/**
* TagPickers are rendered out of DOM order on `document.body` by default,
* use this to render the popover in DOM order
Expand Down Expand Up @@ -81,7 +81,14 @@ export type TagPickerState = ComponentState<TagPickerSlots> &
> &
Pick<
TagPickerContextValue,
'triggerRef' | 'secondaryActionRef' | 'popoverId' | 'popoverRef' | 'targetRef' | 'tagPickerGroupRef' | 'size'
| 'triggerRef'
| 'secondaryActionRef'
| 'popoverId'
| 'popoverRef'
| 'targetRef'
| 'tagPickerGroupRef'
| 'size'
| 'noPopover'
> & {
trigger: React.ReactNode;
popover?: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const useTagPicker_unstable = (props: TagPickerProps): TagPickerState =>
trigger,
popover: comboboxState.open || comboboxState.hasFocus ? popover : undefined,
popoverId,
noPopover,
disabled: comboboxState.disabled,
triggerRef: useMergedRefs(triggerInnerRef, activeParentRef),
popoverRef: useMergedRefs(listboxRef, containerRef),
Expand Down Expand Up @@ -120,17 +121,19 @@ const childrenToTriggerAndPopover = (children: React.ReactNode, noPopover: boole
}
}

if (noPopover) {
return { trigger: childrenArray[0] };
}

let trigger: React.ReactElement | undefined = undefined;
let popover: React.ReactElement | undefined = undefined;

if (childrenArray.length === 2) {
trigger = childrenArray[0];
popover = childrenArray[1];
} else if (childrenArray.length === 1) {
if (noPopover) {
trigger = childrenArray[0];
} else {
popover = childrenArray[0];
}
popover = childrenArray[0];
}

return { trigger, popover };
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function useTagPickerContextValues(state: TagPickerState): TagPickerConte
open,
popoverId,
disabled,
noPopover,
} = state;
return {
activeDescendant: React.useMemo(
Expand Down Expand Up @@ -59,6 +60,7 @@ export function useTagPickerContextValues(state: TagPickerState): TagPickerConte
open,
popoverId,
disabled,
noPopover,
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const useTagPickerControl_unstable = (
const appearance = useTagPickerContext_unstable(ctx => ctx.appearance);
const disabled = useTagPickerContext_unstable(ctx => ctx.disabled);
const invalid = useFieldContext_unstable()?.validationState === 'error';
const noPopover = useTagPickerContext_unstable(ctx => ctx.noPopover ?? false);

const innerRef = React.useRef<HTMLDivElement>(null);
const expandIconRef = React.useRef<HTMLSpanElement>(null);
Expand All @@ -53,7 +54,7 @@ export const useTagPickerControl_unstable = (
}

const expandIcon = slot.optional(props.expandIcon, {
renderByDefault: true,
renderByDefault: !noPopover,
defaultProps: {
'aria-expanded': open,
children: <ChevronDownRegular />,
Expand Down Expand Up @@ -107,7 +108,7 @@ export const useTagPickerControl_unstable = (
root: slot.always(
getIntrinsicElementProps('div', {
ref: useMergedRefs(ref, targetRef, innerRef),
'aria-owns': open ? popoverId : undefined,
'aria-owns': open && !noPopover ? popoverId : undefined,
...props,
onMouseDown: handleMouseDown,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const useTagPickerInput_unstable = (
const setHasFocus = useTagPickerContext_unstable(ctx => ctx.setHasFocus);
const clearSelection = useTagPickerContext_unstable(ctx => ctx.clearSelection);
const open = useTagPickerContext_unstable(ctx => ctx.open);
const popoverId = useTagPickerContext_unstable(ctx => ctx.popoverId);
const popoverId = useTagPickerContext_unstable(ctx => (ctx.noPopover ? undefined : ctx.popoverId));
const selectOption = useTagPickerContext_unstable(ctx => ctx.selectOption);
const getOptionById = useTagPickerContext_unstable(ctx => ctx.getOptionById);
const contextValue = useTagPickerContext_unstable(ctx => ctx.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface TagPickerContextValue
secondaryActionRef: React.RefObject<HTMLSpanElement>;
tagPickerGroupRef: React.RefObject<HTMLDivElement>;
size: TagPickerSize;
noPopover?: boolean;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Tag, Avatar, Field } from '@fluentui/react-components';

export const NoPopover = () => {
const [selectedOptions, setSelectedOptions] = React.useState<string[]>([]);
const [inputValue, setInputValue] = React.useState('');

const onOptionSelect: TagPickerProps['onOptionSelect'] = (_, data) => {
setSelectedOptions(data.selectedOptions);
Expand All @@ -20,16 +21,14 @@ export const NoPopover = () => {
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' && inputValue) {
setInputValue('');
setSelectedOptions(curr => [...curr, inputValue]);
setSelectedOptions(curr => (curr.includes(inputValue) ? curr : [...curr, inputValue]));
}
};

const [inputValue, setInputValue] = React.useState('');

return (
<Field label="Add Employees" style={{ maxWidth: 400 }}>
<TagPicker noPopover onOptionSelect={onOptionSelect} selectedOptions={selectedOptions}>
<TagPickerControl expandIcon={null}>
<TagPickerControl>
<TagPickerGroup>
{selectedOptions.map((option, index) => (
<Tag
Expand Down

0 comments on commit 4e1da64

Please sign in to comment.