From fe72af448322e883349586c4dd209f0052d87367 Mon Sep 17 00:00:00 2001 From: Dan Hedgecock <8461733+DHedgecock@users.noreply.github.com> Date: Sat, 8 Oct 2022 19:35:42 -0700 Subject: [PATCH] Update: Badge ready for production use (#501) --- src/api-types.ts | 5 ++ src/components/Badge/Badge.spec.js | 8 ++- src/components/Badge/Badge.stories.mdx | 10 ++-- src/components/Badge/Badge.styles.ts | 23 ++++++--- src/components/Badge/Badge.ts | 49 ++++++++++++------- .../transforms-components/code.js | 3 +- .../transforms-components/output.js | 6 ++- src/plugin-babel/plugin.ts | 3 +- 8 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/api-types.ts b/src/api-types.ts index 8cc020c9..d7bcface 100644 --- a/src/api-types.ts +++ b/src/api-types.ts @@ -4,6 +4,11 @@ * creating documentation. */ +export { + type BadgePropsDefaults, + type BadgePropsOverrides, +} from './components/Badge/Badge' +export { type BadgeStyles } from './components/Badge/Badge.styles' export { type ButtonPropsDefaults, type ButtonPropsOverrides, diff --git a/src/components/Badge/Badge.spec.js b/src/components/Badge/Badge.spec.js index f8b145d7..89e3b27e 100644 --- a/src/components/Badge/Badge.spec.js +++ b/src/components/Badge/Badge.spec.js @@ -6,11 +6,17 @@ import { Badge } from './Badge' describe('', () => { elementTests(Badge) - it('When color is passed, then badge-color className is rendered', () => { + it('When color is passed, then badge color className is rendered', () => { render(Badge) expect(screen.getByText('Badge')).toHaveClass('C9Y-Badge-primaryColor') }) + + it('When size is passed, then badge size className is rendered', () => { + render(Badge) + + expect(screen.getByText('Badge')).toHaveClass('C9Y-Badge-largeSize') + }) }) // Snapshots diff --git a/src/components/Badge/Badge.stories.mdx b/src/components/Badge/Badge.stories.mdx index 814e04d2..f5ff0613 100644 --- a/src/components/Badge/Badge.stories.mdx +++ b/src/components/Badge/Badge.stories.mdx @@ -13,8 +13,12 @@ Badges provide status information. Badge -## Empty badges +## Sizes -The `:empty` selector is used to hide empty badges by default: +Pass a `size` to set a badge size: - +
+ Badge + Badge + Badge +
diff --git a/src/components/Badge/Badge.styles.ts b/src/components/Badge/Badge.styles.ts index 39da96c2..a343a7fa 100644 --- a/src/components/Badge/Badge.styles.ts +++ b/src/components/Badge/Badge.styles.ts @@ -5,17 +5,14 @@ import { Theme } from '../../theme/theme' // -------------------------------------------------------- export const badgeStyles = (theme: Theme): BadgeStyles => ({ + // BASE '.C9Y-Badge-base': { display: 'inline-flex', alignItems: 'center', whiteSpace: 'nowrap', - - // Empty badges collapse automatically - '&:empty': { - display: 'none', - }, }, + // VARIANTS '.C9Y-Badge-filled': { padding: '4px 8px', color: theme.colors.inverse, @@ -26,11 +23,21 @@ export const badgeStyles = (theme: Theme): BadgeStyles => ({ lineHeight: 1, // 💡 Use em with font-size and padding to auto-scale with text }, + + // SIZES + '.C9Y-Badge-smallSize': { + fontSize: theme.fontSize.sm, + padding: '2px 6px', + }, + '.C9Y-Badge-largeSize': { + fontSize: theme.fontSize.body, + padding: '6px 12px', + }, }) export interface BadgeStyles { - '.C9Y-Badge-base': { - '&:empty': CSSProperties - } & CSSProperties + '.C9Y-Badge-base': CSSProperties '.C9Y-Badge-filled': CSSProperties + '.C9Y-Badge-smallSize': CSSProperties + '.C9Y-Badge-largeSize': CSSProperties } diff --git a/src/components/Badge/Badge.ts b/src/components/Badge/Badge.ts index 45590ac6..65986299 100644 --- a/src/components/Badge/Badge.ts +++ b/src/components/Badge/Badge.ts @@ -1,36 +1,47 @@ -import React from 'react' +import React, { forwardRef } from 'react' import { element } from '../../utils/element-creator' -import { MergeTypes, Resolve } from '../../utils/types' +import { DistributiveOmit, MergeTypes } from '../../utils/types' import { UtilityProps } from '../../utils/utility-classes' import { useThemeProps } from '../Provider/Provider' -// Module augmentation interface for overriding component props' types +/** Module augmentation interface for overriding component props' types */ export interface BadgePropsOverrides {} export interface BadgePropsDefaults { - /** Variant color */ color?: 'primary' - /** Display variant */ + size?: 'small' | 'large' + /** Display style */ variant?: 'filled' } -export type BadgeProps = Resolve> & - Omit & - React.ComponentPropsWithoutRef<'div'> +export type BadgePropsBase = Omit< + UtilityProps, + 'color' +> & + MergeTypes & { as?: Elem } -// ✨ Nice display type for IntelliSense +export type BadgeProps = BadgePropsBase & + DistributiveOmit, keyof BadgePropsBase> + +/** + * Badge provides a label for describing elements. + * @example + * ```tsx + * + * Delightful + * + * ``` + * @see [📝 Badge docs](https://componentry.design/docs/components/badge) + */ export interface Badge { - (props: BadgeProps): React.ReactElement | null + (props: BadgeProps): React.ReactElement displayName?: string } -/** - * [Badge component 📝](https://componentry.design/components/badge) - * @experimental - */ -export const Badge: Badge = (props) => { +export const Badge = forwardRef((props, ref) => { const { color, + size, variant = 'filled', ...rest } = { @@ -39,11 +50,15 @@ export const Badge: Badge = (props) => { } return element({ + ref, componentCx: [ `C9Y-Badge-base C9Y-Badge-${variant}`, - { [`C9Y-Badge-${color}Color`]: color }, + { + [`C9Y-Badge-${color}Color`]: color, + [`C9Y-Badge-${size}Size`]: size, + }, ], ...rest, }) -} +}) as Badge Badge.displayName = 'Badge' diff --git a/src/plugin-babel/__fixtures__/transforms-components/code.js b/src/plugin-babel/__fixtures__/transforms-components/code.js index b92655be..27ced3a1 100644 --- a/src/plugin-babel/__fixtures__/transforms-components/code.js +++ b/src/plugin-babel/__fixtures__/transforms-components/code.js @@ -1,4 +1,4 @@ -import { Block, Flex, Grid, Paper, Text } from 'componentry' +import { Badge, Block, Flex, Grid, Paper, Text } from 'componentry' export default function Test() { // Test that: @@ -10,6 +10,7 @@ export default function Test() { Precompiled for SPEED + Delightful ) diff --git a/src/plugin-babel/__fixtures__/transforms-components/output.js b/src/plugin-babel/__fixtures__/transforms-components/output.js index d3fb8b87..33f417ab 100644 --- a/src/plugin-babel/__fixtures__/transforms-components/output.js +++ b/src/plugin-babel/__fixtures__/transforms-components/output.js @@ -1,4 +1,4 @@ -import { Block, Flex, Grid, Paper, Text } from 'componentry' +import { Badge, Block, Flex, Grid, Paper, Text } from 'componentry' import { jsx as _jsx } from 'react/jsx-runtime' import { jsxs as _jsxs } from 'react/jsx-runtime' export default function Test() { @@ -19,6 +19,10 @@ export default function Test() { /*#__PURE__*/ _jsx('div', { children: 'SPEED', }), + /*#__PURE__*/ _jsx('div', { + className: 'C9Y-Badge-base C9Y-Badge-filled', + children: 'Delightful', + }), ], }), }) diff --git a/src/plugin-babel/plugin.ts b/src/plugin-babel/plugin.ts index 676254e7..d7fac830 100644 --- a/src/plugin-babel/plugin.ts +++ b/src/plugin-babel/plugin.ts @@ -1,5 +1,6 @@ import { NodePath, PluginObj, PluginPass, types as t } from '@babel/core' +import { Badge } from '../components/Badge/Badge' import { Block } from '../components/Block/Block' import { Flex } from '../components/Flex/Flex' import { Grid } from '../components/Grid/Grid' @@ -11,7 +12,7 @@ import { loadConfig } from '../config/load-config' import { parseAttributes } from './parse-attributes' import { prepareAttributes } from './prepare-attributes' -const components = { Block, Flex, Grid, Paper, Text } as unknown as { +const components = { Badge, Block, Flex, Grid, Paper, Text } as unknown as { [component: string]: EvaluatedForwardRef }