diff --git a/src/base/helpers/__tests__/badge.test.tsx b/src/base/helpers/__tests__/badge.test.tsx new file mode 100644 index 00000000..dae03662 --- /dev/null +++ b/src/base/helpers/__tests__/badge.test.tsx @@ -0,0 +1,88 @@ +import { makePropTypes, makeValidatingTransform } from "src/base/helpers/badge"; +import { DEFAULTS } from "src/base/helpers/variables"; +import { tuple } from "../../../utils"; + +import { + validateBoolPropType, + validateOneOfPropType, + validateStringOrNumberPropType, +} from "src/__tests__/testing"; +import { + testItShouldNotSetClassNameOnEmpty, + testItShouldPreserveCustomClassName, + testItShouldPreserveUnknown, + testItShouldUseDefaultLocationProp, +} from "./testing"; + +const CNAME = "foo"; +const LOC = "prop"; + +describe("Badge helpers", () => { + const propTypes = makePropTypes(); + const vtfunc = makeValidatingTransform(); + + describe("propTypes", () => { + validateStringOrNumberPropType(propTypes, "badge"); + validateOneOfPropType(propTypes, "badgeColor", DEFAULTS.colors); + validateBoolPropType(propTypes, "badgeOutlined"); + validateBoolPropType(propTypes, "badgeRounded"); + validateOneOfPropType(propTypes, "badgeSize", DEFAULTS.badgeSizes); + testItShouldUseDefaultLocationProp(vtfunc, { + badgeSize: "__UNKNOWN", + }); + + describe("custom", () => { + const customBadgeSizes = tuple("a", "b"); + const customPropTypes = makePropTypes({ + badgeSizes: customBadgeSizes, + }); + + validateOneOfPropType(customPropTypes, "badgeSize", customBadgeSizes); + }); + }); + + describe("transform", () => { + testItShouldPreserveUnknown(vtfunc); + testItShouldNotSetClassNameOnEmpty(vtfunc); + testItShouldPreserveCustomClassName(vtfunc); + + it("should should get badge className and data-badge", () => { + expect(vtfunc({ badge: "foobar" }, CNAME, LOC)).toEqual({ + className: "badge", + "data-badge": "foobar", + }); + }); + + DEFAULTS.colors.map(color => { + it(`should be ${color}`, () => { + expect(vtfunc({ badgeColor: color }, CNAME, LOC)).toEqual({ + className: `has-badge-${color}`, + }); + }); + }); + + [false, true].map(badgeOutlined => { + it(`should ${badgeOutlined ? "" : "not "}be badgeOutlined`, () => { + expect(vtfunc({ badgeOutlined }, CNAME, LOC)).toEqual({ + className: badgeOutlined ? "has-badge-outlined" : "", + }); + }); + }); + + [false, true].map(badgeRounded => { + it(`should ${badgeRounded ? "" : "not "}be badgeRounded`, () => { + expect(vtfunc({ badgeRounded }, CNAME, LOC)).toEqual({ + className: badgeRounded ? "has-badge-rounded" : "", + }); + }); + }); + + DEFAULTS.badgeSizes.map(badgeSize => { + it(`should be size ${badgeSize}`, () => { + expect(vtfunc({ badgeSize }, CNAME, LOC)).toEqual({ + className: `has-badge-${badgeSize}`, + }); + }); + }); + }); +}); diff --git a/src/base/helpers/__tests__/index.test.ts b/src/base/helpers/__tests__/index.test.ts index 9c2cc15f..ab7fbf9f 100644 --- a/src/base/helpers/__tests__/index.test.ts +++ b/src/base/helpers/__tests__/index.test.ts @@ -17,6 +17,13 @@ describe("Modifiers", () => { testItShouldNotSetClassNameOnEmpty(rvtfunc); testItShouldPreserveCustomClassName(rvtfunc); + it("should apply badge transforms", () => { + expect(rvtfunc({ badge: "asdf" }, CNAME, LOC)).toEqual({ + className: "badge", + "data-badge": "asdf", + }); + }); + it("should apply float transforms", () => { expect(rvtfunc({ clearfix: true }, CNAME, LOC)).toEqual({ className: "is-clearfix", @@ -35,6 +42,13 @@ describe("Modifiers", () => { }); }); + it("should apply tooltip transforms", () => { + expect(rvtfunc({ tooltip: "asdf" }, CNAME, LOC)).toEqual({ + className: "tooltip", + "data-tooltip": "asdf", + }); + }); + it("should apply typography transforms", () => { expect(rvtfunc({ textSize: 1 }, CNAME, LOC)).toEqual({ className: "is-size-1", diff --git a/src/base/helpers/__tests__/tooltip.test.tsx b/src/base/helpers/__tests__/tooltip.test.tsx index b78f6075..61fc0477 100644 --- a/src/base/helpers/__tests__/tooltip.test.tsx +++ b/src/base/helpers/__tests__/tooltip.test.tsx @@ -9,6 +9,7 @@ import { validateBoolPropType, validateOneOfPropType, validatePropType, + validateStringOrNumberPropType, } from "src/__tests__/testing"; import { testItShouldNotSetClassNameOnEmpty, @@ -25,6 +26,7 @@ describe("Tooltip helpers", () => { const vtfunc = makeValidatingTransform(); describe("propTypes", () => { + validateStringOrNumberPropType(propTypes, "tooltip"); validateBoolPropType(propTypes, "tooltipActive"); validateOneOfPropType(propTypes, "tooltipColor", DEFAULTS.colors); validateBoolPropType(propTypes, "tooltipMultiline"); diff --git a/src/base/helpers/badge.ts b/src/base/helpers/badge.ts new file mode 100644 index 00000000..668f9def --- /dev/null +++ b/src/base/helpers/badge.ts @@ -0,0 +1,59 @@ +import classNames from "classnames"; +import PropTypes from "prop-types"; + +import { + makePropTypesFactory, + makeValidatingTransformFactory, + TransformFunction, +} from "./factory"; +import { DEFAULTS, Variables } from "./variables"; + +export type BadgeHelpersProps = Partial<{ + badge: number | string; + badgeColor: Variables["colors"]; + badgeOutlined: boolean; + badgeRounded: boolean; + badgeSize: (typeof DEFAULTS["badgeSizes"])[number]; +}>; + +// Factories +export const makePropTypes = makePropTypesFactory(vars => ({ + badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + badgeColor: PropTypes.oneOf(vars.colors), + badgeOutlined: PropTypes.bool, + badgeRounded: PropTypes.bool, + badgeSize: PropTypes.oneOf(vars.badgeSizes), +})); + +export const transform: TransformFunction = props => { + const { + badge, + badgeColor, + badgeOutlined, + badgeRounded, + badgeSize, + ...rest + } = props; + + rest.className = classNames( + { + badge, + [`has-badge-${badgeColor}`]: badgeColor, + "has-badge-outlined": badgeOutlined, + "has-badge-rounded": badgeRounded, + [`has-badge-${badgeSize}`]: badgeSize, + }, + rest.className, + ); + + if (badge !== undefined) { + rest["data-badge"] = badge; + } + + return rest; +}; + +export const makeValidatingTransform = makeValidatingTransformFactory( + makePropTypes, + transform, +); diff --git a/src/base/helpers/index.ts b/src/base/helpers/index.ts index 6df1f377..8d704919 100644 --- a/src/base/helpers/index.ts +++ b/src/base/helpers/index.ts @@ -1,6 +1,10 @@ import { Prefer } from "../../types"; import { makeRootValidatingTransformFactory } from "./factory"; +import { + BadgeHelpersProps, + makeValidatingTransform as badgeMVT, +} from "./badge"; import { FloatHelpersProps, makeValidatingTransform as floatMVT, @@ -40,7 +44,8 @@ export interface HelpersPropsOverrides {} export type HelpersProps = Prefer< HelpersPropsOverrides, - FloatHelpersProps & + BadgeHelpersProps & + FloatHelpersProps & OverflowHelpersProps & OverlayHelpersProps & TooltipHelpersProps & @@ -53,6 +58,7 @@ export type HelpersProps = Prefer< export const makeRootValidatingTransform = makeRootValidatingTransformFactory< HelpersProps >( + badgeMVT, floatMVT, overflowMVT, overlayMVT, diff --git a/src/base/helpers/variables.ts b/src/base/helpers/variables.ts index d769d6dc..4721246b 100644 --- a/src/base/helpers/variables.ts +++ b/src/base/helpers/variables.ts @@ -5,6 +5,9 @@ export type VariablesDefinitions = { colors: (string | number)[]; shades: (string | number)[]; + // Badge + badgeSizes: (string | number)[]; + // Float floatPulledAlignments: (string | number)[]; @@ -50,6 +53,9 @@ export const DEFAULTS = { "white-bis", ), + // Badge + badgeSizes: tuple("small", "medium", "large"), + // Float floatPulledAlignments: tuple("left", "right"), @@ -89,6 +95,9 @@ export interface VariablesDefaults { colors: (typeof DEFAULTS.colors)[number]; shades: (typeof DEFAULTS.shades)[number]; + // Badge + badgeSizes: (typeof DEFAULTS.badgeSizes)[number]; + // Float floatPulledAlignments: (typeof DEFAULTS.floatPulledAlignments)[number]; diff --git a/src/extensions/badge/__docs__/badge.docs.mdx b/src/extensions/__docs__/badge.docs.mdx similarity index 97% rename from src/extensions/badge/__docs__/badge.docs.mdx rename to src/extensions/__docs__/badge.docs.mdx index eba3c1fb..575fdcdb 100644 --- a/src/extensions/badge/__docs__/badge.docs.mdx +++ b/src/extensions/__docs__/badge.docs.mdx @@ -13,8 +13,8 @@ import { } from "src/__docs__/components"; import { DEFAULTS } from "src/base/helpers/variables"; import { Block, Button, Title } from "src/elements"; -import { Badge, BADGE_DEFAULTS } from "../badge"; +``` # Badge Display a **badge** element in front of another component. @@ -140,7 +140,7 @@ Use the `badgeRounded` prop of `` to round a badge. docUrl="https://wikiki.github.io/elements/badge/" docProvider="Bulma-Extensions" props={{ - badgeContent: { + badge: { description: "the contents of the badge", typeName: "number | string", }, @@ -160,3 +160,4 @@ Use the `badgeRounded` prop of `` to round a badge. }, }} /> +``` diff --git a/src/extensions/badge/__tests__/badge.test.tsx b/src/extensions/badge/__tests__/badge.test.tsx deleted file mode 100644 index 07e568c7..00000000 --- a/src/extensions/badge/__tests__/badge.test.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react"; - -import { DEFAULTS } from "src/base/helpers/variables"; -import { Badge, BADGE_DEFAULTS } from "src/extensions/badge/badge"; - -import { - hasProperties, - makeGenericHOCShallowWrapperInContextConsumer, - testForwardRefAsExoticComponentIntegration, - testThemeIntegration, - validateBoolPropType, - validateStringOrNumberPropType, -} from "src/__tests__/testing"; - -const COMPONENT = Badge; -const DISPLAY_NAME = "Badge"; -const DEFAULT_ELEMENT = "span"; -const BULMA_CLASS_NAME = "badge"; - -describe(`${DISPLAY_NAME} component`, () => { - hasProperties(COMPONENT, { - defaultProps: { - as: DEFAULT_ELEMENT, - badgeContent: "", - }, - }); - - testForwardRefAsExoticComponentIntegration(COMPONENT, { - displayName: DISPLAY_NAME, - bulmaClassName: BULMA_CLASS_NAME, - defaultElement: DEFAULT_ELEMENT, - }); - - testThemeIntegration(COMPONENT); - - describe("props", () => { - const { propTypes } = COMPONENT; - - describe("badgeColor", () => { - validateStringOrNumberPropType(propTypes, "badgeColor"); - - DEFAULTS.colors.map(color => { - it(`should be ${color}`, () => { - const node = ; - const wrapper = makeGenericHOCShallowWrapperInContextConsumer(node); - expect(wrapper.hasClass(`has-badge-${color}`)).toBe(true); - }); - }); - }); - - describe("badgeContent", () => { - validateStringOrNumberPropType(propTypes, "badgeContent"); - - it(`should have proper content`, () => { - const node = ; - const wrapper = makeGenericHOCShallowWrapperInContextConsumer(node); - expect( - (wrapper.props() as React.HTMLAttributes)[ - "data-badge" - ], - ).toBe("foo"); - }); - }); - - describe("badgeOutlined", () => { - validateBoolPropType(propTypes, "badgeOutlined"); - - [false, true].map(outlined => { - it(`should ${outlined ? "" : "not "}be outlined`, () => { - const node = ; - const wrapper = makeGenericHOCShallowWrapperInContextConsumer(node); - expect(wrapper.hasClass(`has-badge-outlined`)).toBe(outlined); - }); - }); - }); - - describe("badgeSize", () => { - validateStringOrNumberPropType(propTypes, "badgeSize"); - - BADGE_DEFAULTS.sizes.map(size => { - it(`should be ${size}`, () => { - const node = ; - const wrapper = makeGenericHOCShallowWrapperInContextConsumer(node); - expect(wrapper.hasClass(`has-badge-${size}`)).toBe(true); - }); - }); - }); - }); -}); diff --git a/src/extensions/badge/badge.tsx b/src/extensions/badge/badge.tsx deleted file mode 100644 index 78fd564d..00000000 --- a/src/extensions/badge/badge.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import classNames from "classnames"; -import PropTypes from "prop-types"; -import React from "react"; - -import { forwardRefAs, Generic } from "../../base"; -import { HelpersProps } from "../../base/helpers"; -import { Variables } from "../../base/helpers/variables"; -import { tuple } from "../../utils"; - -export const BADGE_DEFAULTS = { - sizes: tuple("small", "medium", "large"), -}; - -export type BadgeModifierProps = Partial<{ - badgeColor: Variables["colors"]; - badgeContent: number | string; - badgeOutlined: boolean; - badgeRounded: boolean; - badgeSize: (typeof BADGE_DEFAULTS["sizes"])[number]; -}>; - -export type BadgeProps = HelpersProps & BadgeModifierProps; - -export const Badge = forwardRefAs( - ( - { - className, - badgeColor, - badgeContent, - badgeOutlined, - badgeRounded, - badgeSize, - ...rest - }, - ref, - ) => ( - - ), - { - as: "span", - badgeContent: "", - }, -); - -Badge.displayName = "Badge"; -Badge.propTypes = { - badgeColor: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - badgeContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - badgeOutlined: PropTypes.bool, - badgeSize: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), -}; diff --git a/src/extensions/badge/index.ts b/src/extensions/badge/index.ts deleted file mode 100644 index d3faf405..00000000 --- a/src/extensions/badge/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Badge } from "./badge";