diff --git a/src/components/BaseStories/Heading.stories.tsx b/src/components/Heading/Heading.stories.tsx similarity index 86% rename from src/components/BaseStories/Heading.stories.tsx rename to src/components/Heading/Heading.stories.tsx index 293b9b79ed4..ba701a6038f 100644 --- a/src/components/BaseStories/Heading.stories.tsx +++ b/src/components/Heading/Heading.stories.tsx @@ -1,16 +1,8 @@ import * as React from "react" -import { - Box, - Flex, - Heading as HeadingComponent, - HeadingProps, - Stack, - VStack, -} from "@chakra-ui/react" -import { objectKeys } from "@chakra-ui/utils" +import { Box, Flex, HeadingProps, Stack, VStack } from "@chakra-ui/react" import { Meta, StoryObj } from "@storybook/react" -import Translation from "../Translation" +import HeadingComponent from "." const meta = { title: "Atoms / Typography / Heading", @@ -83,11 +75,12 @@ export const Heading: Story = { as="span" flex="1" textAlign="end" + // Explicit size value passed because the element rendered is not a heading size={obj.size} > {(obj.size as string) || "xl"} - + {`${obj.as} base component`} diff --git a/src/components/Heading/index.tsx b/src/components/Heading/index.tsx new file mode 100644 index 00000000000..66cff4d67b2 --- /dev/null +++ b/src/components/Heading/index.tsx @@ -0,0 +1,51 @@ +import { + forwardRef, + Heading as ChakraHeading, + type HeadingProps, + type ThemingProps, +} from "@chakra-ui/react" + +export type HeadingTags = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" + +const HEADING_SIZE_DEFAULTS: Record< + HeadingTags, + ThemingProps<"Heading">["size"] +> = { + h1: "2xl", + h2: "xl", + h3: "lg", + h4: "md", + h5: "sm", + h6: "xs", +} + +/** + * This is a wrapper component for the Chakra `Heading` component, and forwards its ref and props. + * + * This supplies a default `size` theme token based on the + * heading tag being passed to the `as` prop. Defaults to `h2` with the `xl` + * tag, per the Chakra default. + */ +const Heading = forwardRef((props, ref) => { + const { as = "h2", size: sizeProp, ...rest } = props + + let size: typeof sizeProp + + if (sizeProp) { + // If a `size` value is passed to this wrapper, send it on through! + size = sizeProp + } else { + // If a `size` value is not passed to this wrapper, set a default based on the element + // provided to the `as` prop + // Only heading elemnts will set the defaults (Default heading is `h2`) + const headingDefaultKeys = Object.keys(HEADING_SIZE_DEFAULTS) + + if (typeof as === "string" && headingDefaultKeys.includes(as)) { + size = HEADING_SIZE_DEFAULTS[as] + } + } + + return +}) + +export default Heading