diff --git a/.changeset/tame-mice-lick.md b/.changeset/tame-mice-lick.md
new file mode 100644
index 000000000..96b33bb6a
--- /dev/null
+++ b/.changeset/tame-mice-lick.md
@@ -0,0 +1,5 @@
+---
+"@khanacademy/wonder-blocks-toolbar": minor
+---
+
+Allow title to also support React nodes
diff --git a/__docs__/wonder-blocks-toolbar/toolbar.argtypes.tsx b/__docs__/wonder-blocks-toolbar/toolbar.argtypes.tsx
index 0d0578c28..a80862c0b 100644
--- a/__docs__/wonder-blocks-toolbar/toolbar.argtypes.tsx
+++ b/__docs__/wonder-blocks-toolbar/toolbar.argtypes.tsx
@@ -7,6 +7,7 @@ import magnifyingGlassPlus from "@phosphor-icons/core/regular/magnifying-glass-p
import magnifyingGlassMinus from "@phosphor-icons/core/regular/magnifying-glass-minus.svg";
import Button from "@khanacademy/wonder-blocks-button";
+import {View} from "@khanacademy/wonder-blocks-core";
import IconButton from "@khanacademy/wonder-blocks-icon-button";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import Link from "@khanacademy/wonder-blocks-link";
@@ -45,6 +46,23 @@ export const leftContentMappings: Mappings = {
>
),
+ exitWithTitle: (
+
+
+ |
+
+ Algebra TestBETA
+
+
+ ),
};
const buttonStyle = {width: 160} as const;
diff --git a/__docs__/wonder-blocks-toolbar/toolbar.stories.tsx b/__docs__/wonder-blocks-toolbar/toolbar.stories.tsx
index a62763268..e0eb7bcea 100644
--- a/__docs__/wonder-blocks-toolbar/toolbar.stories.tsx
+++ b/__docs__/wonder-blocks-toolbar/toolbar.stories.tsx
@@ -3,7 +3,7 @@ import {StyleSheet} from "aphrodite";
import type {Meta, StoryObj} from "@storybook/react";
import {View} from "@khanacademy/wonder-blocks-core";
-import {spacing} from "@khanacademy/wonder-blocks-tokens";
+import {semanticColor, spacing} from "@khanacademy/wonder-blocks-tokens";
import Toolbar from "@khanacademy/wonder-blocks-toolbar";
import packageConfig from "../../packages/wonder-blocks-toolbar/package.json";
@@ -211,3 +211,27 @@ Dark.parameters = {
},
},
};
+
+/**
+ * Sometimes we need to have a custom toolbar to include a custom component or a
+ * more complex layout in the center of the toolbar. This can be achieved by
+ * passing a React node to the `title` prop.
+ *
+ * **NOTE:** This approach should be used with caution, as it may break the
+ * layout of the toolbar.
+ */
+export const CustomToolbar: StoryComponentType = {
+ args: {
+ leftContent: leftContentMappings.exitWithTitle,
+ rightContent: rightContentMappings.primaryButton,
+ title: (
+
+ ),
+ },
+};
diff --git a/packages/wonder-blocks-toolbar/src/components/toolbar.tsx b/packages/wonder-blocks-toolbar/src/components/toolbar.tsx
index 96322e75c..04ed13840 100644
--- a/packages/wonder-blocks-toolbar/src/components/toolbar.tsx
+++ b/packages/wonder-blocks-toolbar/src/components/toolbar.tsx
@@ -40,22 +40,16 @@ type Props = AriaProps & {
*/
subtitle?: string;
/**
- * The main title rendered in larger bold text.
+ * The main title rendered in larger bold text. It also supports rendering
+ * React nodes (use with caution).
*/
- title?: string;
+ title?: string | React.ReactNode;
/**
* Test ID used for e2e testing.
*/
testId?: string;
};
-type DefaultProps = {
- color: Props["color"];
- leftContent: Props["leftContent"];
- rightContent: Props["rightContent"];
- size: Props["size"];
-};
-
/**
* The `Toolbar` component is a generic toolbar wrapper that exposes
* customization options. An optional `title` and `subtitle` property can be
@@ -73,74 +67,70 @@ type DefaultProps = {
* />
* ```
*/
-export default class Toolbar extends React.Component {
- static defaultProps: DefaultProps = {
- color: "light",
- leftContent: null,
- rightContent: null,
- size: "medium",
- };
-
- render(): React.ReactNode {
- const {color, leftContent, rightContent, size, subtitle, title} =
- this.props;
-
- const TitleComponent = subtitle ? LabelLarge : HeadingSmall;
+export default function Toolbar({
+ color = "light",
+ leftContent,
+ rightContent,
+ size = "medium",
+ subtitle,
+ title,
+}: Props): React.ReactElement {
+ const TitleComponent = subtitle ? LabelLarge : HeadingSmall;
- return (
+ return (
+
-
- {leftContent}
-
+ {leftContent}
+
- {title && (
-
-
-
- {title}
-
- {subtitle && (
-
- {subtitle}
-
- )}
-
+ {title && typeof title === "string" ? (
+
+
+
+ {title}
+
+ {subtitle && (
+
+ {subtitle}
+
+ )}
- )}
-
-
- {rightContent}
+ ) : (
+ // We don't use wideColumn here to allow more flexibility with
+ // the custom node.
+
+ {title}
+
+ )}
+
+
+ {rightContent}
- );
- }
+
+ );
}
const sharedStyles = StyleSheet.create({