Compare commits

..

1 Commits

Author SHA1 Message Date
Raunak Bhagat
8f5d7e271a refactor: migrate ModalHeader to Content layout
Modal.Header now uses opal Content component for icon + title rendering.
Description passed to Content directly with a hidden
DialogPrimitive.Description for accessibility. Close button absolutely
positioned per Figma mocks.
2026-03-01 12:06:18 -08:00
7 changed files with 12 additions and 25 deletions

View File

@@ -5,7 +5,7 @@ import type { SizeVariant } from "@opal/shared";
import SvgEdit from "@opal/icons/edit";
import type { IconFunctionComponent } from "@opal/types";
import { cn } from "@opal/utils";
import { useState } from "react";
import { useRef, useState } from "react";
// ---------------------------------------------------------------------------
// Types
@@ -89,6 +89,7 @@ function ContentLg({
}: ContentLgProps) {
const [editing, setEditing] = useState(false);
const [editValue, setEditValue] = useState(title);
const inputRef = useRef<HTMLInputElement>(null);
const config = CONTENT_LG_PRESETS[sizePreset];
@@ -130,6 +131,7 @@ function ContentLg({
{editValue || "\u00A0"}
</span>
<input
ref={inputRef}
className={cn(
"opal-content-lg-input",
config.titleFont,

View File

@@ -5,7 +5,7 @@ import type { SizeVariant } from "@opal/shared";
import SvgEdit from "@opal/icons/edit";
import type { IconFunctionComponent } from "@opal/types";
import { cn } from "@opal/utils";
import { useState } from "react";
import { useRef, useState } from "react";
// ---------------------------------------------------------------------------
// Types
@@ -109,6 +109,7 @@ function ContentXl({
}: ContentXlProps) {
const [editing, setEditing] = useState(false);
const [editValue, setEditValue] = useState(title);
const inputRef = useRef<HTMLInputElement>(null);
const config = CONTENT_XL_PRESETS[sizePreset];
@@ -188,6 +189,7 @@ function ContentXl({
{editValue || "\u00A0"}
</span>
<input
ref={inputRef}
className={cn(
"opal-content-xl-input",
config.titleFont,

View File

@@ -148,8 +148,7 @@ function Content(props: ContentProps) {
}
}
// ContentMd: main-content/main-ui/secondary with section/heading variant
// (variant defaults to "heading" when omitted on MdContentProps, so both arms are needed)
// ContentMd: main-content/main-ui/secondary with section variant
else if (variant === "section" || variant === "heading") {
layout = (
<ContentMd

View File

@@ -8,7 +8,7 @@ Layout primitives for composing icon + title + description rows. These component
| Component | Description | Docs |
|---|---|---|
| [`Content`](./Content/README.md) | Icon + title + description row. Routes to an internal layout (`ContentXl`, `ContentLg`, `ContentMd`, or `ContentSm`) based on `sizePreset` and `variant`. | [Content README](./Content/README.md) |
| [`Content`](./Content/README.md) | Icon + title + description row. Routes to an internal layout (`ContentLg`, `ContentMd`, or `ContentSm`) based on `sizePreset` and `variant`. | [Content README](./Content/README.md) |
| [`ContentAction`](./ContentAction/README.md) | Wraps `Content` in a flex-row with an optional `rightChildren` slot for action buttons. Adds padding alignment via the shared `SizeVariant` scale. | [ContentAction README](./ContentAction/README.md) |
## Quick Start

View File

@@ -16,7 +16,7 @@
// - Interactive.Container (height + min-width + padding)
// - Button (icon sizing)
// - ContentAction (padding only)
// - Content (ContentXl / ContentLg / ContentMd) (edit-button size)
// - Content (ContentLg / ContentMd) (edit-button size)
// ---------------------------------------------------------------------------
/**

View File

@@ -408,26 +408,12 @@ ModalContent.displayName = DialogPrimitive.Content.displayName;
*/
interface ModalHeaderProps extends WithoutStyles<SectionProps> {
icon?: IconFunctionComponent;
moreIcon1?: IconFunctionComponent;
moreIcon2?: IconFunctionComponent;
title: string;
description?: string;
onClose?: () => void;
}
const ModalHeader = React.forwardRef<HTMLDivElement, ModalHeaderProps>(
(
{
icon,
moreIcon1,
moreIcon2,
title,
description,
onClose,
children,
...props
},
ref
) => {
({ icon: Icon, title, description, onClose, children, ...props }, ref) => {
const { closeButtonRef, setHasDescription } = useModalContext();
React.useLayoutEffect(() => {
@@ -468,9 +454,7 @@ const ModalHeader = React.forwardRef<HTMLDivElement, ModalHeaderProps>(
<DialogPrimitive.Title asChild>
<div>
<Content
icon={icon}
moreIcon1={moreIcon1}
moreIcon2={moreIcon2}
icon={Icon}
title={title}
description={description}
sizePreset="section"

View File

@@ -248,7 +248,7 @@ export default function AgentViewerModal({ agent }: AgentViewerModalProps) {
bottomSlot={<AgentChatInput agent={agent} onSubmit={handleStartChat} />}
>
<Modal.Header
icon={(props) => <AgentAvatar agent={agent} {...props} size={24} />}
icon={(props) => <AgentAvatar agent={agent} {...props} size={28} />}
title={agent.name}
onClose={() => agentViewerModal.toggle(false)}
/>