diff --git a/.changeset/thirty-jars-grow.md b/.changeset/thirty-jars-grow.md new file mode 100644 index 000000000..b137ef2a9 --- /dev/null +++ b/.changeset/thirty-jars-grow.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-core": minor +--- + +- Add the `Id` component for cases where `useId` cannot be used directly diff --git a/__docs__/wonder-blocks-core/id.stories.tsx b/__docs__/wonder-blocks-core/id.stories.tsx new file mode 100644 index 000000000..504afd931 --- /dev/null +++ b/__docs__/wonder-blocks-core/id.stories.tsx @@ -0,0 +1,32 @@ +import * as React from "react"; + +import {Meta} from "@storybook/react"; +import {View, Id} from "@khanacademy/wonder-blocks-core"; +import {Body, BodyMonospace} from "@khanacademy/wonder-blocks-typography"; +import {Strut} from "@khanacademy/wonder-blocks-layout"; +import {spacing} from "@khanacademy/wonder-blocks-tokens"; + +export default { + title: "Packages / Core / Id", + + parameters: { + chromatic: { + // We don't need a snapshot for this. + disableSnapshot: true, + }, + }, +} as Meta; + +export const BasicExample = () => ( + + + {(id) => ( + + Generated identifier: + + {id} + + )} + + +); diff --git a/packages/wonder-blocks-core/src/components/__tests__/id.test.tsx b/packages/wonder-blocks-core/src/components/__tests__/id.test.tsx new file mode 100644 index 000000000..7b0869aef --- /dev/null +++ b/packages/wonder-blocks-core/src/components/__tests__/id.test.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +import {render} from "@testing-library/react"; +import {Id} from "../id"; + +describe("Id", () => { + it("should provide an id to the children", () => { + // Arrange + const childrenFn = jest.fn().mockReturnValue(null); + + // Act + render({childrenFn}); + + // Assert + expect(childrenFn).toHaveBeenCalledWith(expect.any(String)); + }); +}); diff --git a/packages/wonder-blocks-core/src/components/id.tsx b/packages/wonder-blocks-core/src/components/id.tsx new file mode 100644 index 000000000..8a0b0b084 --- /dev/null +++ b/packages/wonder-blocks-core/src/components/id.tsx @@ -0,0 +1,21 @@ +import {useId} from "react"; +import * as React from "react"; + +type Props = { + /** + * A function that to render children with the given identifier. + */ + children: (id: string) => React.ReactNode; +}; + +/** + * A component that provides a unique identifier to its children. + * + * This component is useful when you need to generate unique identifiers for + * elements in components that cannot use hooks. Where possible, use `useId` + * instead. + */ +export const Id = ({children}: Props) => { + const id = useId(); + return <>{children(id)}; +}; diff --git a/packages/wonder-blocks-core/src/index.ts b/packages/wonder-blocks-core/src/index.ts index 1d68fbef8..55df69118 100644 --- a/packages/wonder-blocks-core/src/index.ts +++ b/packages/wonder-blocks-core/src/index.ts @@ -13,6 +13,7 @@ export {default as IDProvider} from "./components/id-provider"; export {default as UniqueIDProvider} from "./components/unique-id-provider"; export {default as addStyle} from "./util/add-style"; export {default as Server} from "./util/server"; +export {Id} from "./components/id"; export { useUniqueIdWithMock, useUniqueIdWithoutMock,