Skip to content

Commit

Permalink
feat(Pills): add base pill (microsoft#17500)
Browse files Browse the repository at this point in the history
* feat(Pills): add base pill

* feat(Pills): add unstable comment

* Update packages/fluentui/react-northstar/src/components/Pill/Pill.tsx

Co-authored-by: Oleksandr Fediashov <[email protected]>

* feat(Pills): Address review comments

* Update packages/fluentui/docs/src/examples/components/Pill/Variations/PillExampleSizes.tsx

Co-authored-by: Oleksandr Fediashov <[email protected]>

* feat(Pills): Address review comments

* feat(Pills): Fix example

* Update packages/fluentui/react-northstar/src/components/Pill/Pill.tsx

Co-authored-by: ling1726 <[email protected]>

* feat(Pills): Export styles

* feat(Pills): Fix example

* feat(Pills): added disabled

* feat(Pills): added appearance variations

* feat(Pills): fix example

* Update packages/fluentui/react-northstar/src/themes/teams/components/Pill/pillStyles.ts

Co-authored-by: Oleksandr Fediashov <[email protected]>

* feat(Pills): rename example file

* feat(Pills):update content

* feat(Pills): update example

* Update packages/fluentui/react-northstar/src/components/Pill/PillContent.tsx

Co-authored-by: Oleksandr Fediashov <[email protected]>

* feat(Pills): update PillContent

* feat(Pills): update PillContent

* feat(Pills): update pillStyles

* feat(Pills): update rectangular instead rounded

* feat(Pills): Add changelog

* feat(Pills): update example

Co-authored-by: Oleksandr Fediashov <[email protected]>
Co-authored-by: ling1726 <[email protected]>
  • Loading branch information
3 people authored Mar 23, 2021
1 parent 097a7c3 commit 79a96df
Show file tree
Hide file tree
Showing 19 changed files with 536 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/fluentui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## Features
- Add `borderActive4` color slot @notandrew ([#17391](https://github.com/microsoft/fluentui/pull/17391))
- Add `Pill` base componet @assuncaocharles ([#17500](https://github.com/microsoft/fluentui/pull/17500))

## Documentation
- Update left nav in UI Builder to separate add components from navigator @codepretty ([#17002](https://github.com/microsoft/fluentui/pull/17002))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Pill } from '@fluentui/react-northstar';

const PillExampleDisabled = () => <Pill disabled>This is a disabled Pill</Pill>;

export default PillExampleDisabled;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from 'react';

import ComponentExample from '../../../../components/ComponentDoc/ComponentExample';
import ExampleSection from '../../../../components/ComponentDoc/ExampleSection';

const State = () => (
<ExampleSection title="State">
<ComponentExample
title="Disabled"
description="A disabled Pill."
examplePath="components/Pill/State/PillExampleDisabled"
/>
</ExampleSection>
);

export default State;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Pill } from '@fluentui/react-northstar';

const PillExample = () => <Pill>This is a default Pill</Pill>;

export default PillExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';

import ComponentExample from '../../../../components/ComponentDoc/ComponentExample';
import ExampleSection from '../../../../components/ComponentDoc/ExampleSection';

const Types = () => (
<ExampleSection title="Types">
<ComponentExample title="Default" description="A default Pill." examplePath="components/Pill/Types/PillExample" />
</ExampleSection>
);

export default Types;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react';
import { Pill, Flex } from '@fluentui/react-northstar';

const PillAppearanceExample = () => (
<Flex gap="gap.medium">
<Pill appearance="filled">Filled Pill (Default)</Pill>
<Pill appearance="inverted">Inverted Pill</Pill>
<Pill appearance="outline">Outlined Pill</Pill>
</Flex>
);

export default PillAppearanceExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as React from 'react';
import { Pill } from '@fluentui/react-northstar';

const PillRectangularExample = () => <Pill rectangular>Pill Content</Pill>;

export default PillRectangularExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';
import { Pill, Flex, PillProps } from '@fluentui/react-northstar';

const PillSizesExample = () => (
<Flex gap="gap.medium">
{['smaller', 'small', 'medium'].map((size: PillProps['size']) => (
<Pill key={size} size={size}>
{size} pill
</Pill>
))}
</Flex>
);

export default PillSizesExample;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';

import ComponentExample from '../../../../components/ComponentDoc/ComponentExample';
import ExampleSection from '../../../../components/ComponentDoc/ExampleSection';

const Variations = () => (
<ExampleSection title="Variations">
<ComponentExample
title="Sizes"
description="A Pill can be sized."
examplePath="components/Pill/Variations/PillExampleSizes"
/>
<ComponentExample
title="Appearance"
description="A Pill can be filled, inverted or outlined."
examplePath="components/Pill/Variations/PillExampleAppearance"
/>
<ComponentExample
title="Rounded"
description="A Pill can be rounded."
examplePath="components/Pill/Variations/PillExampleRounded"
/>
</ExampleSection>
);

export default Variations;
14 changes: 14 additions & 0 deletions packages/fluentui/docs/src/examples/components/Pill/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';
import Types from './Types';
import Variations from './Variations';
import State from './State';

const PillExamples = () => (
<>
<Types />
<Variations />
<State />
</>
);

export default PillExamples;
118 changes: 118 additions & 0 deletions packages/fluentui/react-northstar/src/components/Pill/Pill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as PropTypes from 'prop-types';
import * as React from 'react';
import * as customPropTypes from '@fluentui/react-proptypes';
import { UIComponentProps, ContentComponentProps, commonPropTypes, SizeValue, createShorthand } from '../../utils';
import { ShorthandValue, FluentComponentStaticProps } from '../../types';
import { BoxProps } from '../Box/Box';

import {
ComponentWithAs,
useAccessibility,
getElementType,
useStyles,
useTelemetry,
useFluentContext,
useUnhandledProps,
} from '@fluentui/react-bindings';
import { PillContent } from './PillContent';

export interface PillProps extends UIComponentProps, ContentComponentProps<ShorthandValue<BoxProps>> {
/**
* A Pill can be sized.
*/
size?: Extract<SizeValue, 'smaller' | 'small' | 'medium'>;

/**
* A Pill can be rectangular
*/
rectangular?: boolean;

/**
* A Pill can be filled, inverted or outline
*/
appearance?: 'filled' | 'inverted' | 'outline';

/**
* A Pill can be disbled
*/
disabled?: boolean;
}

export type PillStylesProps = Required<Pick<PillProps, 'appearance' | 'size' | 'rectangular' | 'disabled'>>;

export const pillClassName = 'ui-pill';

/**
* THIS COMPONENT IS STILL IN DEVELOPMENT AND IS NOT READY FOR PRODUCTION
* Pills should be used when representing an input, as a way to filter content, or to represent an attribute.
*/
export const Pill: ComponentWithAs<'span', PillProps> & FluentComponentStaticProps<PillProps> = props => {
const context = useFluentContext();
const { setStart, setEnd } = useTelemetry(Pill.displayName, context.telemetry);
setStart();

const { className, design, styles, variables, appearance, size, rectangular, children, content, disabled } = props;

const ElementType = getElementType(props);
const unhandledProps = useUnhandledProps(Pill.handledProps, props);

const getA11yProps = useAccessibility(props.accessibility, {
debugName: Pill.displayName,
mapPropsToBehavior: () => ({}),
rtl: context.rtl,
});

const { classes } = useStyles<PillStylesProps>(Pill.displayName, {
className: pillClassName,
mapPropsToStyles: () => ({
appearance,
size,
rectangular,
disabled,
}),
mapPropsToInlineStyles: () => ({
className,
design,
styles,
variables,
}),
rtl: context.rtl,
});

const element = getA11yProps.unstable_wrapWithFocusZone(
<ElementType
{...getA11yProps('root', {
className: classes.root,
...unhandledProps,
})}
>
{createShorthand(PillContent, content || {}, {
defaultProps: () => ({
children,
size,
}),
})}
</ElementType>,
);

setEnd();

return element;
};

Pill.defaultProps = {
as: 'span',
};

Pill.propTypes = {
...commonPropTypes.createCommon(),
content: customPropTypes.shorthandAllowingChildren,
size: PropTypes.oneOf(['small', 'smaller', 'medium']),
rectangular: PropTypes.bool,
disabled: PropTypes.bool,
appearance: PropTypes.oneOf(['filled', 'inverted', 'outline']),
};

Pill.displayName = 'Pill';

Pill.handledProps = Object.keys(Pill.propTypes) as any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as React from 'react';
import { Accessibility } from '@fluentui/accessibility';
import {
ComponentWithAs,
getElementType,
useUnhandledProps,
useAccessibility,
useFluentContext,
useStyles,
useTelemetry,
} from '@fluentui/react-bindings';
import {
childrenExist,
UIComponentProps,
ChildrenComponentProps,
ContentComponentProps,
commonPropTypes,
rtlTextContainer,
SizeValue,
} from '../../utils';

import { FluentComponentStaticProps } from '../../types';

export interface PillContentProps extends UIComponentProps, ChildrenComponentProps, ContentComponentProps {
/**
* Accessibility behavior if overridden by the user.
*/
accessibility?: Accessibility<never>;

/**
* A Pill can be sized.
*/
size?: Extract<SizeValue, 'smaller' | 'small' | 'medium'>;
}

export type PillContentStylesProps = Required<Pick<PillContentProps, 'size'>>;
export const pillContentClassName = 'ui-pillcontent';

/**
* A PillContent allows user to classify content.
*/
export const PillContent: ComponentWithAs<'span', PillContentProps> &
FluentComponentStaticProps<PillContentProps> = props => {
const context = useFluentContext();
const { setStart, setEnd } = useTelemetry(PillContent.displayName, context.telemetry);
setStart();

const { accessibility, children, className, content, design, styles, variables, size } = props;

const getA11Props = useAccessibility(accessibility, {
debugName: PillContent.displayName,
rtl: context.rtl,
});

const { classes } = useStyles<PillContentStylesProps>(PillContent.displayName, {
className: pillContentClassName,
mapPropsToStyles: () => ({ size }),
mapPropsToInlineStyles: () => ({ className, design, styles, variables }),
rtl: context.rtl,
});

const ElementType = getElementType(props);
const unhandledProps = useUnhandledProps(PillContent.handledProps, props);

const element = (
<ElementType
{...getA11Props('root', {
className: classes.root,
...rtlTextContainer.getAttributes({ forElements: [children] }),
...unhandledProps,
})}
>
{childrenExist(children) ? children : content}
</ElementType>
);

setEnd();

return element;
};

PillContent.displayName = 'PillContent';

PillContent.propTypes = {
...commonPropTypes.createCommon(),
};

PillContent.handledProps = Object.keys(PillContent.propTypes) as any;

PillContent.defaultProps = {
as: 'span',
};

PillContent.shorthandConfig = {
mappedProp: 'content',
};
3 changes: 3 additions & 0 deletions packages/fluentui/react-northstar/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export * from './components/Design/Design';

export * from './components/MenuButton/MenuButton';

export * from './components/Pill/Pill';
export * from './components/Pill/PillContent';

export * from './components/Divider/Divider';
export * from './components/Divider/DividerContent';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ export { menuDividerStyles as MenuDivider } from './components/Menu/menuDividerS

export { menuButtonStyles as MenuButton } from './components/MenuButton/menuButtonStyles';

export { pillStyles as Pill } from './components/Pill/pillStyles';
export { pillContentStyles as PillContent } from './components/Pill/pillContentStyles';

export { popupContentStyles as PopupContent } from './components/Popup/popupContentStyles';

export { providerStyles as Provider } from './components/Provider/providerStyles';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ export { menuItemContentVariables as MenuItemIndicator } from './components/Menu
export { menuItemWrapperVariables as MenuItemWrapper } from './components/Menu/menuItemWrapperVariables';
export { menuDividerVariables as MenuDivider } from './components/Menu/menuDividerVariables';

export { pillVariables as Pill } from './components/Pill/pillVariables';
export { pillVariables as PillContent } from './components/Pill/pillVariables';

export { popupContentVariables as PopupContent } from './components/Popup/popupContentVariables';

export { providerVariables as Provider } from './components/Provider/providerVariables';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ComponentSlotStylesPrepared, ICSSInJSStyle } from '@fluentui/styles';
import { PillContentStylesProps } from '../../../../components/Pill/PillContent';
import { PillVariables } from './pillVariables';

export const pillContentStyles: ComponentSlotStylesPrepared<PillContentStylesProps, PillVariables> = {
root: ({ props: p, variables: v }): ICSSInJSStyle => ({
fontSize: v.contentFontSize,
padding: v.contentPadding,

...(p.size === 'small' && {
fontSize: v.contentFontSizeSmall,
padding: v.contentPaddingSmall,
}),
...(p.size === 'smaller' && {
fontSize: v.contentFontSizeSmaller,
padding: v.contentPaddingSmaller,
}),
}),
};
Loading

0 comments on commit 79a96df

Please sign in to comment.