Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 9 additions & 31 deletions packages/react-components/react-tags/etc/react-tags.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

/// <reference types="react" />

import { ARIAButtonSlotProps } from '@fluentui/react-aria';
import { AvatarShape } from '@fluentui/react-avatar';
import { AvatarSize } from '@fluentui/react-avatar';
import type { ComponentProps } from '@fluentui/react-utilities';
Expand All @@ -18,27 +19,9 @@ import type { SlotClassNames } from '@fluentui/react-utilities';
// @public
export const renderTag_unstable: (state: TagState, contextValues: TagContextValues) => JSX.Element;

// @public
export const renderTagButton_unstable: (state: TagButtonState, contextValues: TagButtonContextValues) => JSX.Element;

// @public
export const Tag: ForwardRefComponent<TagProps>;

// @public
export const TagButton: ForwardRefComponent<TagButtonProps>;

// @public (undocumented)
export const tagButtonClassNames: SlotClassNames<TagButtonSlots>;

// @public
export type TagButtonProps = TagProps;

// @public (undocumented)
export type TagButtonSlots = TagSlots;

// @public
export type TagButtonState = TagState;

// @public (undocumented)
export const tagClassNames: SlotClassNames<TagSlots>;

Expand All @@ -47,36 +30,31 @@ export type TagProps = ComponentProps<Partial<TagSlots>> & {
appearance?: 'filled-darker' | 'filled-lighter' | 'tint' | 'outline';
disabled?: boolean;
dismissible?: boolean;
interactive?: boolean;
shape?: 'rounded' | 'circular';
size?: 'extra-small' | 'small' | 'medium';
};

// @public (undocumented)
export type TagSlots = {
root: NonNullable<Slot<'div'>>;
media: Slot<'span'>;
content: Slot<'div'>;
icon: Slot<'span'>;
primaryText: Slot<'span'>;
secondaryText: Slot<'span'>;
dismissButton: Slot<'button'>;
media?: Slot<'span'>;
content: NonNullable<Slot<ARIAButtonSlotProps<'div'>>>;
icon?: Slot<'span'>;
primaryText: NonNullable<Slot<'span'>>;
secondaryText?: Slot<'span'>;
dismissButton?: Slot<'button'>;
};

// @public
export type TagState = ComponentState<TagSlots> & Required<Pick<TagProps, 'appearance' | 'disabled' | 'dismissible' | 'shape' | 'size'> & {
export type TagState = ComponentState<TagSlots> & Required<Pick<TagProps, 'appearance' | 'disabled' | 'dismissible' | 'interactive' | 'shape' | 'size'> & {
avatarSize: AvatarSize | undefined;
avatarShape: AvatarShape | undefined;
}>;

// @public
export const useTag_unstable: (props: TagProps, ref: React_2.Ref<HTMLElement>) => TagState;

// @public
export const useTagButton_unstable: (props: TagButtonProps, ref: React_2.Ref<HTMLElement>) => TagButtonState;

// @public
export const useTagButtonStyles_unstable: (state: TagButtonState) => TagButtonState;

// @public
export const useTagStyles_unstable: (state: TagState) => TagState;

Expand Down
3 changes: 2 additions & 1 deletion packages/react-components/react-tags/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"type-check": "tsc -b tsconfig.json",
"generate-api": "just-scripts generate-api",
"storybook": "start-storybook",
"start": "yarn storybook"
"start": "yarn storybook",
"test-ssr": "test-ssr ./stories/**/*.stories.tsx"
},
"devDependencies": {
"@fluentui/eslint-plugin": "*",
Expand Down
1 change: 0 additions & 1 deletion packages/react-components/react-tags/src/TagButton.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ describe('Tag', () => {
displayName: 'Tag',
requiredProps,
});

// TODO add more tests here, and create visual regression tests in /apps/vr-tests
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import { renderTag_unstable } from './renderTag';
import { useTagStyles_unstable } from './useTagStyles.styles';
import type { TagProps } from './Tag.types';
import type { ForwardRefComponent } from '@fluentui/react-utilities';
import { useTagContextValues_unstable } from '../../utils/useTagContextValues';
import { useTagContextValues_unstable } from './useTagContextValues';

/**
* Tag component - TODO: add more docs
*/
export const Tag: ForwardRefComponent<TagProps> = React.forwardRef((props, ref) => {
const state = useTag_unstable(props, ref);

const contextValues = useTagContextValues_unstable(state);
useTagStyles_unstable(state);
return renderTag_unstable(state, useTagContextValues_unstable(state));
return renderTag_unstable(state, contextValues);
});

Tag.displayName = 'Tag';
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ARIAButtonSlotProps } from '@fluentui/react-aria';
import { AvatarSize, AvatarShape } from '@fluentui/react-avatar';
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';

Expand All @@ -14,26 +15,26 @@ export type TagSlots = {
/**
* Slot for an icon or other visual element
*/
media: Slot<'span'>;
media?: Slot<'span'>;

/**
* A layout wrapper for the icon slot, the primaryText and secondaryText slots
*/
content: Slot<'div'>;
content: NonNullable<Slot<ARIAButtonSlotProps<'div'>>>;

icon: Slot<'span'>;
icon?: Slot<'span'>;

/**
* Main text for the Tag. Children of the root slot are automatically rendered here
*/
primaryText: Slot<'span'>;
primaryText: NonNullable<Slot<'span'>>;

/**
* Secondary text that describes or complements the main text
*/
secondaryText: Slot<'span'>;
secondaryText?: Slot<'span'>;

dismissButton: Slot<'button'>;
dismissButton?: Slot<'button'>;
};

/**
Expand All @@ -45,6 +46,7 @@ export type TagProps = ComponentProps<Partial<TagSlots>> & {
// checked?: boolean;
disabled?: boolean;
dismissible?: boolean;
Comment thread
YuanboXue-Amber marked this conversation as resolved.
interactive?: boolean;
shape?: 'rounded' | 'circular';
size?: 'extra-small' | 'small' | 'medium';
};
Expand All @@ -54,7 +56,7 @@ export type TagProps = ComponentProps<Partial<TagSlots>> & {
*/
export type TagState = ComponentState<TagSlots> &
Required<
Pick<TagProps, 'appearance' | 'disabled' | 'dismissible' | 'shape' | 'size'> & {
Pick<TagProps, 'appearance' | 'disabled' | 'dismissible' | 'interactive' | 'shape' | 'size'> & {
avatarSize: AvatarSize | undefined;
avatarShape: AvatarShape | undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,16 @@ export const renderTag_unstable = (state: TagState, contextValues: TagContextVal

return (
<slots.root {...slotProps.root}>
{slots.content && (
<slots.content {...slotProps.content}>
{slots.media && (
<AvatarContextProvider value={contextValues.avatar}>
<slots.media {...slotProps.media} />
</AvatarContextProvider>
)}
{slots.icon && <slots.icon {...slotProps.icon} />}
{slots.primaryText && (
Comment thread
YuanboXue-Amber marked this conversation as resolved.
<slots.primaryText {...slotProps.primaryText}>{slotProps.root.children}</slots.primaryText>
)}
{slots.secondaryText && <slots.secondaryText {...slotProps.secondaryText} />}
</slots.content>
)}
<slots.content {...slotProps.content}>
{slots.media && (
<AvatarContextProvider value={contextValues.avatar}>
<slots.media {...slotProps.media} />
</AvatarContextProvider>
)}
{slots.icon && <slots.icon {...slotProps.icon} />}
<slots.primaryText {...slotProps.primaryText} />
{slots.secondaryText && <slots.secondaryText {...slotProps.secondaryText} />}
</slots.content>
{slots.dismissButton && state.dismissible && <slots.dismissButton {...slotProps.dismissButton} />}
</slots.root>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,49 @@ export const useTag_unstable = (props: TagProps, ref: React.Ref<HTMLElement>): T
appearance = 'filled-lighter',
disabled = false,
dismissible = false,
interactive = false,
shape = 'rounded',
size = 'medium',
} = props;

const contentButton = useARIAButtonShorthand(props.content, {
required: true,
defaultProps: {
disabled,
type: 'button',
},
});

return {
appearance,
avatarShape: tagAvatarShapeMap[shape],
avatarSize: tagAvatarSizeMap[size],
disabled,
dismissible,
interactive,
shape,
size,

components: {
root: 'div',
content: 'div',
content: interactive ? 'button' : 'div',
media: 'span',
icon: 'span',
primaryText: 'span',
secondaryText: 'span',
dismissButton: 'button',
},

root: getNativeElementProps('div', {
ref,
...props,
}),

content: resolveShorthand(props.content, { required: true }),
content: interactive ? contentButton : resolveShorthand(props.content, { required: true }),
media: resolveShorthand(props.media),
icon: resolveShorthand(props.icon),
primaryText: resolveShorthand(props.primaryText, { required: true }),
primaryText: resolveShorthand(props.primaryText, { required: true, defaultProps: { children: props.children } }),
secondaryText: resolveShorthand(props.secondaryText),
dismissButton: useARIAButtonShorthand(props.dismissButton, {
dismissButton: resolveShorthand(props.dismissButton, {
required: props.dismissible,
defaultProps: {
disabled,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { TagContextValues, TagState } from '../components/Tag/index';
import { TagState, TagContextValues } from './Tag.types';

export function useTagContextValues_unstable(state: TagState): TagContextValues {
const { avatarSize, avatarShape } = state;
Expand Down
Loading