Skip to content

Commit

Permalink
feat(react-tags): Adds disabled property to TagGroup (#32317)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmayjiang authored Aug 19, 2024
1 parent 4f4e54e commit 0a88822
Show file tree
Hide file tree
Showing 14 changed files with 126 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix(react-tag-picker): allows TagPickerGroup to be disabled",
"packageName": "@fluentui/react-tag-picker",
"email": "jiangemma@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix(react-tags): allows TagGroup to be disabled",
"packageName": "@fluentui/react-tags",
"email": "jiangemma@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const useTagPickerGroup_unstable = (
const selectOption = useTagPickerContext_unstable(ctx => ctx.selectOption);
const size = useTagPickerContext_unstable(ctx => tagPickerSizeToTagSize(ctx.size));
const appearance = useTagPickerContext_unstable(ctx => ctx.appearance);
const disabled = useTagPickerContext_unstable(ctx => ctx.disabled);

const arrowNavigationProps = useArrowNavigationGroup({
circular: false,
Expand All @@ -37,6 +38,7 @@ export const useTagPickerGroup_unstable = (
const state = useTagGroup_unstable(
{
role: 'listbox',
disabled,
...props,
...arrowNavigationProps,
size,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const Disabled = () => {
<TagPickerGroup>
{selectedOptions.map(option => (
<Tag
disabled
key={option}
shape="rounded"
media={<Avatar aria-hidden name={option} color="colorful" />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export type TagGroupContextValues = {
// @public
export type TagGroupProps<Value = TagValue> = ComponentProps<TagGroupSlots> & {
onDismiss?: TagDismissHandler<Value>;
disabled?: boolean;
size?: TagSize;
appearance?: TagAppearance;
dismissible?: boolean;
Expand All @@ -144,7 +145,7 @@ export type TagGroupSlots = {
};

// @public
export type TagGroupState<Value = TagValue> = ComponentState<TagGroupSlots> & Required<Pick<TagGroupProps, 'size' | 'appearance' | 'dismissible'>> & {
export type TagGroupState<Value = TagValue> = ComponentState<TagGroupSlots> & Required<Pick<TagGroupProps, 'disabled' | 'size' | 'appearance' | 'dismissible'>> & {
handleTagDismiss: TagDismissHandler<Value>;
role?: React_2.AriaRole;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ export const useInteractionTag_unstable = (
props: InteractionTagProps,
ref: React.Ref<HTMLDivElement>,
): InteractionTagState => {
const { handleTagDismiss, size: contextSize, appearance: contextAppearance } = useTagGroupContext_unstable();
const {
handleTagDismiss,
size: contextSize,
disabled: contextDisabled,
appearance: contextAppearance,
} = useTagGroupContext_unstable();

const id = useId('fui-InteractionTag-', props.id);

Expand All @@ -32,7 +37,7 @@ export const useInteractionTag_unstable = (

return {
appearance,
disabled,
disabled: contextDisabled ? true : disabled,
handleTagDismiss,
interactionTagPrimaryId,
shape,
Expand All @@ -47,6 +52,7 @@ export const useInteractionTag_unstable = (
getIntrinsicElementProps('div', {
ref,
...props,
disabled: contextDisabled ? true : disabled,
id,
}),
{ elementType: 'div' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const useTag_unstable = (props: TagProps, ref: React.Ref<HTMLSpanElement
const {
handleTagDismiss,
size: contextSize,
disabled: contextDisabled,
appearance: contextAppearance,
dismissible: contextDismissible,
role: tagGroupRole,
Expand Down Expand Up @@ -65,7 +66,7 @@ export const useTag_unstable = (props: TagProps, ref: React.Ref<HTMLSpanElement
appearance,
avatarShape: tagAvatarShapeMap[shape],
avatarSize: tagAvatarSizeMap[size],
disabled,
disabled: contextDisabled ? true : disabled,
dismissible,
shape,
size,
Expand All @@ -84,6 +85,7 @@ export const useTag_unstable = (props: TagProps, ref: React.Ref<HTMLSpanElement
ref,
role: tagGroupRole === 'listbox' ? 'option' : undefined,
...props,
disabled: contextDisabled ? true : disabled,
id,
...(dismissible && { onClick: dismissOnClick, onKeyDown: dismissOnKeyDown }),
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import '@testing-library/jest-dom';
import * as React from 'react';
import { TagGroup } from './TagGroup';
import { isConformant } from '../../testing/isConformant';
Expand Down Expand Up @@ -35,4 +36,24 @@ describe('TagGroup', () => {

expect(onDismiss).toHaveBeenCalledWith(expect.anything(), { value: '1' });
});

it('if disabled, should disable children Tags', () => {
const { getByRole } = render(
<TagGroup disabled>
<Tag value={'1'} dismissible />
</TagGroup>,
);

expect(getByRole('button')).toBeDisabled();
});

it('if disabled, should override children Tags disabled prop', () => {
const { getByRole } = render(
<TagGroup disabled>
<Tag value={'1'} disabled={false} dismissible />
</TagGroup>,
);

expect(getByRole('button')).toBeDisabled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export type TagGroupProps<Value = TagValue> = ComponentProps<TagGroupSlots> & {
// eslint-disable-next-line @nx/workspace-consistent-callback-type -- can't change type of existing callback
onDismiss?: TagDismissHandler<Value>;

/**
* A TagGroup can show that it cannot be interacted with.
*
* @default false
*/
disabled?: boolean;

size?: TagSize;
appearance?: TagAppearance;
dismissible?: boolean;
Expand All @@ -30,7 +37,7 @@ export type TagGroupProps<Value = TagValue> = ComponentProps<TagGroupSlots> & {
* State used in rendering TagGroup
*/
export type TagGroupState<Value = TagValue> = ComponentState<TagGroupSlots> &
Required<Pick<TagGroupProps, 'size' | 'appearance' | 'dismissible'>> & {
Required<Pick<TagGroupProps, 'disabled' | 'size' | 'appearance' | 'dismissible'>> & {
handleTagDismiss: TagDismissHandler<Value>;
role?: React.AriaRole;
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ import { interactionTagSecondaryClassNames } from '../InteractionTagSecondary/us
* @param ref - reference to root HTMLDivElement of TagGroup
*/
export const useTagGroup_unstable = (props: TagGroupProps, ref: React.Ref<HTMLDivElement>): TagGroupState => {
const { onDismiss, size = 'medium', appearance = 'filled', dismissible = false, role = 'toolbar' } = props;
const {
onDismiss,
disabled = false,
size = 'medium',
appearance = 'filled',
dismissible = false,
role = 'toolbar',
} = props;

const innerRef = React.useRef<HTMLElement>();
const { targetDocument } = useFluent();
Expand Down Expand Up @@ -55,6 +62,7 @@ export const useTagGroup_unstable = (props: TagGroupProps, ref: React.Ref<HTMLDi
handleTagDismiss,
role,
size,
disabled,
appearance,
dismissible,
components: {
Expand All @@ -68,6 +76,7 @@ export const useTagGroup_unstable = (props: TagGroupProps, ref: React.Ref<HTMLDi
// but since it would be a breaking change to fix it, we are casting ref to it's proper type
ref: useMergedRefs(ref, innerRef) as React.Ref<HTMLDivElement>,
role,
'aria-disabled': disabled,
...arrowNavigationProps,
...props,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import * as React from 'react';
import type { TagGroupContextValues, TagGroupState } from './TagGroup.types';

export function useTagGroupContextValues_unstable(state: TagGroupState): TagGroupContextValues {
const { handleTagDismiss, size, appearance, dismissible, role } = state;
const { handleTagDismiss, size, disabled, appearance, dismissible, role } = state;
return {
tagGroup: React.useMemo(
() => ({ handleTagDismiss, size, appearance, dismissible, role }),
[handleTagDismiss, size, appearance, dismissible, role],
() => ({ handleTagDismiss, size, disabled, appearance, dismissible, role }),
[handleTagDismiss, size, disabled, appearance, dismissible, role],
),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const tagGroupContextDefaultValue: TagGroupContextValue = {
* Context shared between TagGroup and its children components
*/
export type TagGroupContextValue = Required<Pick<TagGroupState, 'handleTagDismiss' | 'size'>> &
Partial<Pick<TagGroupState, 'appearance' | 'dismissible' | 'role'>>;
Partial<Pick<TagGroupState, 'disabled' | 'appearance' | 'dismissible' | 'role'>>;

export const TagGroupContextProvider = TagGroupContext.Provider;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from 'react';
import { TagGroup, InteractionTag, InteractionTagPrimary, Tag, makeStyles } from '@fluentui/react-components';

const WithTags = () => (
<TagGroup disabled aria-label="Disabled tag group with Tag" role="list">
<Tag role="listitem">Tag 1</Tag>
<Tag role="listitem">Tag 2</Tag>
<Tag role="listitem">Tag 3</Tag>
</TagGroup>
);

const WithInteractionTags = () => (
<TagGroup disabled aria-label="Disabled tag group with InteractionTag">
<InteractionTag>
<InteractionTagPrimary>Tag 1</InteractionTagPrimary>
</InteractionTag>
<InteractionTag>
<InteractionTagPrimary>Tag 2</InteractionTagPrimary>
</InteractionTag>
<InteractionTag>
<InteractionTagPrimary>Tag 3</InteractionTagPrimary>
</InteractionTag>
</TagGroup>
);

const useStyles = makeStyles({
container: {
display: 'flex',
flexDirection: 'column',
rowGap: '10px',
},
});

export const Disabled = () => {
const styles = useStyles();
return (
<div className={styles.container}>
Disabled example with Tag:
<WithTags />
Disabled example with InteractionTag:
<WithInteractionTags />
</div>
);
};

Disabled.storyName = 'Disabled';
Disabled.parameters = {
docs: {
description: {
story: 'A TagGroup can be disabled. The collection of Tag/InteractionTag will also be disabled.',
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { Default } from './TagGroupDefault.stories';
export { Dismiss } from './TagGroupDismiss.stories';
export { Sizes } from './TagGroupSizes.stories';
export { WithOverflow } from './TagGroupOverflow.stories';
export { Disabled } from './TagGroupDisabled.stories';

export default {
title: 'Components/Tag/TagGroup',
Expand Down

0 comments on commit 0a88822

Please sign in to comment.