diff --git a/web/src/app/admin/configuration/llm/forms/components/FormWrapper.tsx b/web/src/app/admin/configuration/llm/forms/components/FormWrapper.tsx index a4342b1887d..c66d78c0691 100644 --- a/web/src/app/admin/configuration/llm/forms/components/FormWrapper.tsx +++ b/web/src/app/admin/configuration/llm/forms/components/FormWrapper.tsx @@ -120,9 +120,7 @@ export function ProviderFormEntrypointWrapper({ title={`Setup ${providerName}`} onClose={onClose} /> - - {children(context)} - + {children(context)} )} @@ -208,9 +206,7 @@ export function ProviderFormEntrypointWrapper({ }`} onClose={onClose} /> - - {children(context)} - + {children(context)} )} diff --git a/web/src/app/admin/configuration/search/UpgradingPage.tsx b/web/src/app/admin/configuration/search/UpgradingPage.tsx index 1c7974dcd07..e99dfaad4d1 100644 --- a/web/src/app/admin/configuration/search/UpgradingPage.tsx +++ b/web/src/app/admin/configuration/search/UpgradingPage.tsx @@ -142,7 +142,7 @@ export default function UpgradingPage({ previous model and all progress will be lost. - + diff --git a/web/src/app/admin/configuration/web-search/page.tsx b/web/src/app/admin/configuration/web-search/page.tsx index c24d7da135d..3af5599c0c8 100644 --- a/web/src/app/admin/configuration/web-search/page.tsx +++ b/web/src/app/admin/configuration/web-search/page.tsx @@ -935,7 +935,6 @@ export default function Page() { provider ); }} - className="h-6 w-6 opacity-70 hover:opacity-100" aria-label={`Edit ${label}`} /> )} @@ -1134,7 +1133,6 @@ export default function Page() { provider ); }} - className="h-6 w-6 opacity-70 hover:opacity-100" aria-label={`Edit ${label}`} /> )} diff --git a/web/src/app/admin/connector/[ccPairId]/IndexAttemptErrorsModal.tsx b/web/src/app/admin/connector/[ccPairId]/IndexAttemptErrorsModal.tsx index a8bdd156df9..048c2966bbc 100644 --- a/web/src/app/admin/connector/[ccPairId]/IndexAttemptErrorsModal.tsx +++ b/web/src/app/admin/connector/[ccPairId]/IndexAttemptErrorsModal.tsx @@ -136,7 +136,7 @@ export default function IndexAttemptErrorsModal({ } onClose={onClose} /> - + {!isResolvingErrors && (
diff --git a/web/src/app/admin/connector/[ccPairId]/InlineFileManagement.tsx b/web/src/app/admin/connector/[ccPairId]/InlineFileManagement.tsx index d2509833c8e..c5849daee58 100644 --- a/web/src/app/admin/connector/[ccPairId]/InlineFileManagement.tsx +++ b/web/src/app/admin/connector/[ccPairId]/InlineFileManagement.tsx @@ -37,7 +37,7 @@ interface InlineFileManagementProps { onRefresh: () => void; } -export function InlineFileManagement({ +export default function InlineFileManagement({ connectorId, onRefresh, }: InlineFileManagementProps) { @@ -360,7 +360,7 @@ export function InlineFileManagement({ description="When you save these changes, the following will happen:" /> - + {selectedFilesToRemove.size > 0 && (
- + - diff --git a/web/src/app/admin/connector/[ccPairId]/page.tsx b/web/src/app/admin/connector/[ccPairId]/page.tsx index d2f9cbe3ac4..65ac6aea9e2 100644 --- a/web/src/app/admin/connector/[ccPairId]/page.tsx +++ b/web/src/app/admin/connector/[ccPairId]/page.tsx @@ -25,7 +25,7 @@ import { } from "./ConfigDisplay"; import DeletionErrorStatus from "./DeletionErrorStatus"; import { IndexAttemptsTable } from "./IndexAttemptsTable"; -import { InlineFileManagement } from "./InlineFileManagement"; +import InlineFileManagement from "./InlineFileManagement"; import { buildCCPairInfoUrl, triggerIndexing } from "./lib"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { diff --git a/web/src/app/admin/embeddings/RerankingFormPage.tsx b/web/src/app/admin/embeddings/RerankingFormPage.tsx index b647ae79043..98e2d25288e 100644 --- a/web/src/app/admin/embeddings/RerankingFormPage.tsx +++ b/web/src/app/admin/embeddings/RerankingFormPage.tsx @@ -339,7 +339,7 @@ const RerankingDetailsForm = forwardRef< better performance.

- +
- +
- + diff --git a/web/src/app/admin/embeddings/modals/InstantSwitchConfirmModal.tsx b/web/src/app/admin/embeddings/modals/InstantSwitchConfirmModal.tsx index 60b7caa3068..f75aa6ec234 100644 --- a/web/src/app/admin/embeddings/modals/InstantSwitchConfirmModal.tsx +++ b/web/src/app/admin/embeddings/modals/InstantSwitchConfirmModal.tsx @@ -29,7 +29,7 @@ export default function InstantSwitchConfirmModal({ This is not reversible.
- + - - - - )} - - - - ); -}; diff --git a/web/src/app/admin/settings/SettingsForm.tsx b/web/src/app/admin/settings/SettingsForm.tsx index 82693088e9c..c82d7206524 100644 --- a/web/src/app/admin/settings/SettingsForm.tsx +++ b/web/src/app/admin/settings/SettingsForm.tsx @@ -320,7 +320,7 @@ export function SettingsForm() { anyone to use Onyx without signing in.

- + diff --git a/web/src/app/chat/components/ChatPopup.tsx b/web/src/app/chat/components/ChatPopup.tsx index fa7949c8f8c..8b34fc05034 100644 --- a/web/src/app/chat/components/ChatPopup.tsx +++ b/web/src/app/chat/components/ChatPopup.tsx @@ -79,7 +79,7 @@ export function ChatPopup() { icon={headerIcon} title={popupTitle || "Welcome to Onyx!"} /> - +
)} - + - + diff --git a/web/src/app/css/z-index.css b/web/src/app/css/z-index.css index 510f387fbbf..9aff2c688b4 100644 --- a/web/src/app/css/z-index.css +++ b/web/src/app/css/z-index.css @@ -7,7 +7,6 @@ /* Interactive overlays */ --z-modal-overlay: 900; --z-modal: 1000; - --z-confirmation: 1050; --z-toast: 1100; --z-popover: 1200; --z-tooltip: 1300; @@ -31,9 +30,6 @@ .z-modal { z-index: var(--z-modal); } -.z-confirmation { - z-index: var(--z-confirmation); -} .z-toast { z-index: var(--z-toast); } diff --git a/web/src/components/chat/TextView.tsx b/web/src/components/chat/TextView.tsx index d4061a9ec26..080138a06b3 100644 --- a/web/src/components/chat/TextView.tsx +++ b/web/src/components/chat/TextView.tsx @@ -201,10 +201,9 @@ export default function TextView({ }} > e.preventDefault()} - className="overflow-hidden h-[80dvh] max-h-[calc(100dvh-4rem)]" >
@@ -242,7 +241,7 @@ export default function TextView({
- + {isLoading ? (
diff --git a/web/src/components/credentials/actions/ModifyCredential.tsx b/web/src/components/credentials/actions/ModifyCredential.tsx index 0d5a280ea7c..a4982530825 100644 --- a/web/src/components/credentials/actions/ModifyCredential.tsx +++ b/web/src/components/credentials/actions/ModifyCredential.tsx @@ -202,7 +202,7 @@ export default function ModifyCredential({ delete credentials that are linked to live connectors. - + diff --git a/web/src/components/modals/AddInstructionModal.tsx b/web/src/components/modals/AddInstructionModal.tsx index dde9b7c6b97..6da14e9b3e7 100644 --- a/web/src/components/modals/AddInstructionModal.tsx +++ b/web/src/components/modals/AddInstructionModal.tsx @@ -38,14 +38,14 @@ export default function AddInstructionModal() { description="Instruct specific behaviors, focus, tones, or formats for the response in this project." onClose={() => modal.toggle(false)} /> - + setInstructionText(event.target.value)} placeholder="Think step by step and show reasoning for complex problems. Use specific examples." /> - + diff --git a/web/src/components/modals/CreateProjectModal.tsx b/web/src/components/modals/CreateProjectModal.tsx index f8b15c51d69..95f148871c2 100644 --- a/web/src/components/modals/CreateProjectModal.tsx +++ b/web/src/components/modals/CreateProjectModal.tsx @@ -42,14 +42,14 @@ export default function CreateProjectModal() { description="Use projects to organize your files and chats in one place, and add custom instructions for ongoing work." onClose={() => modal.toggle(false)} /> - + - + diff --git a/web/src/components/modals/ExceptionTraceModal.tsx b/web/src/components/modals/ExceptionTraceModal.tsx index b29ea10b56e..4f5fa44f66a 100644 --- a/web/src/components/modals/ExceptionTraceModal.tsx +++ b/web/src/components/modals/ExceptionTraceModal.tsx @@ -22,7 +22,7 @@ export default function ExceptionTraceModal({ title="Full Exception Trace" onClose={onOutsideClick} /> - +
{!copyClicked ? ( diff --git a/web/src/components/modals/UserFilesModal.tsx b/web/src/components/modals/UserFilesModal.tsx index ccb89db03a0..ba338a1ec8a 100644 --- a/web/src/components/modals/UserFilesModal.tsx +++ b/web/src/components/modals/UserFilesModal.tsx @@ -14,10 +14,8 @@ import IconButton from "@/refresh-components/buttons/IconButton"; import SimpleLoader from "@/refresh-components/loaders/SimpleLoader"; import AttachmentButton from "@/refresh-components/buttons/AttachmentButton"; import Modal from "@/refresh-components/Modal"; -import ScrollIndicatorDiv from "@/refresh-components/ScrollIndicatorDiv"; import { useModal } from "@/refresh-components/contexts/ModalContext"; import CounterSeparator from "@/refresh-components/CounterSeparator"; -import useFilter from "@/hooks/useFilter"; import { SvgEye, SvgFiles, @@ -26,6 +24,9 @@ import { SvgTrash, SvgXCircle, } from "@opal/icons"; +import { Section } from "@/layouts/general-layouts"; +import useFilter from "@/hooks/useFilter"; +import ScrollIndicatorDiv from "@/refresh-components/ScrollIndicatorDiv"; function getIcon( file: ProjectFile, @@ -127,16 +128,13 @@ export default function UserFilesModal({ const triggerUploadPicker = () => fileInputRef.current?.click(); useEffect(() => { - if (selectedFileIds) { - setSelectedIds(new Set(selectedFileIds)); - } else { - setSelectedIds(new Set()); - } + if (selectedFileIds) setSelectedIds(new Set(selectedFileIds)); + else setSelectedIds(new Set()); }, [selectedFileIds]); const selectedCount = selectedIds.size; - const handleDeselectAll = () => { + function handleDeselectAll() { selectedIds.forEach((id) => { const file = recentFiles.find((f) => f.id === id); if (file) { @@ -144,7 +142,7 @@ export default function UserFilesModal({ } }); setSelectedIds(new Set()); - }; + } const files = useMemo( () => @@ -180,7 +178,7 @@ export default function UserFilesModal({ > {/* Search bar section */} -
+
)} -
+
- + {/* File display section */} {filtered.length === 0 ? ( -
- - No files found - -
+ No files found ) : ( - + {filtered.map((projectFle) => { const isSelected = selectedIds.has(projectFle.id); return ( @@ -262,10 +260,10 @@ export default function UserFilesModal({ )}
- + {/* Left side: file count and controls */} {onPickRecent && ( -
+
{selectedCount} {selectedCount === 1 ? "file" : "files"}{" "} selected @@ -274,7 +272,7 @@ export default function UserFilesModal({ icon={SvgEye} internal onClick={() => setShowOnlySelected(!showOnlySelected)} - className={showOnlySelected ? "bg-background-tint-02" : ""} + transient={showOnlySelected} /> -
+ )} {/* Right side: Done button */} -
diff --git a/web/src/components/oauth/OAuthConfigSelector.tsx b/web/src/components/oauth/OAuthConfigSelector.tsx deleted file mode 100644 index a55bf0892ca..00000000000 --- a/web/src/components/oauth/OAuthConfigSelector.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { OAuthConfig } from "@/lib/tools/interfaces"; -import { SelectorFormField } from "@/components/Field"; -import Button from "@/refresh-components/buttons/Button"; -import { useState } from "react"; -import { OAuthConfigForm } from "@/app/admin/oauth-configs/OAuthConfigForm"; -import { PopupSpec } from "@/components/admin/connectors/Popup"; -import { useFormikContext } from "formik"; -import CreateButton from "@/refresh-components/buttons/CreateButton"; -import { KeyedMutator } from "swr"; -import { SvgEdit, SvgPlusCircle } from "@opal/icons"; -interface OAuthConfigSelectorProps { - name: string; - label?: string; - oauthConfigs: OAuthConfig[]; - onSelect?: (configId: number | null) => void; - onConfigCreated?: (config: OAuthConfig) => void; - setPopup: (popupSpec: PopupSpec | null) => void; - mutateOAuthConfigs?: KeyedMutator; -} - -export const OAuthConfigSelector = ({ - name, - label = "OAuth Configuration:", - oauthConfigs, - onSelect, - onConfigCreated, - setPopup, - mutateOAuthConfigs, -}: OAuthConfigSelectorProps) => { - const [showModal, setShowModal] = useState(false); - const [editingConfig, setEditingConfig] = useState(null); - const { setFieldValue, values } = useFormikContext(); - - // Get the currently selected config ID - const selectedConfigId = values[name]; - - const options = [ - { name: "None", value: -1 }, - ...oauthConfigs.map((config) => ({ - name: config.name, - value: config.id, - })), - ]; - - const handleConfigSaved = (savedConfig: OAuthConfig) => { - const isCreating = !editingConfig; - - // Refresh the OAuth configs list - if (mutateOAuthConfigs) { - mutateOAuthConfigs(); - } - - // If creating a new config, also call the onConfigCreated callback - // and select the new config - if (isCreating && onConfigCreated) { - onConfigCreated(savedConfig); - - // Wait a moment for the options list to update before setting the field value - // This ensures the new config is in the options when the selector tries to find it - setTimeout(() => { - // Now set the newly created config as selected - setFieldValue(name, savedConfig.id.toString(), true); - - // Call the onSelect callback if provided - if (onSelect) { - onSelect(savedConfig.id); - } - }, 100); - } - }; - - const handleModalClose = () => { - setShowModal(false); - setEditingConfig(null); - }; - - const handleEditClick = () => { - // Find the selected config - const configId = - typeof selectedConfigId === "string" - ? parseInt(selectedConfigId) - : selectedConfigId; - const config = oauthConfigs.find((c) => c.id === configId); - if (config) { - setEditingConfig(config); - setShowModal(true); - } - }; - - // Check if a valid config is selected (not null and not "None") - const hasValidSelection = - selectedConfigId && - selectedConfigId !== -1 && - selectedConfigId !== "-1" && - selectedConfigId !== "null"; - - return ( -
- { - // SelectorFormField passes the value string directly, not an object - let configId: number | null; - if ( - !selected || - selected === "null" || - selected === -1 || - selected === "-1" - ) { - configId = null; - } else if (typeof selected === "number") { - configId = selected; - } else { - configId = parseInt(selected); - } - if (onSelect) { - onSelect(configId); - } - }} - /> -
- setShowModal(true)}> - New OAuth Configuration - - {hasValidSelection && ( - - )} -
- - {showModal && ( - - )} -
- ); -}; diff --git a/web/src/layouts/general-layouts.tsx b/web/src/layouts/general-layouts.tsx index 575526b7285..aba703807a1 100644 --- a/web/src/layouts/general-layouts.tsx +++ b/web/src/layouts/general-layouts.tsx @@ -1,9 +1,9 @@ import { cn } from "@/lib/utils"; import { WithoutStyles } from "@/types"; -import React from "react"; +import React, { forwardRef } from "react"; export type FlexDirection = "row" | "column"; -export type JustifyContent = "start" | "center" | "end"; +export type JustifyContent = "start" | "center" | "end" | "between"; export type AlignItems = "start" | "center" | "end"; const directionClassMap: Record = { @@ -14,6 +14,7 @@ const justifyClassMap: Record = { start: "justify-start", center: "justify-center", end: "justify-end", + between: "justify-between", }; const alignClassMap: Record = { start: "items-start", @@ -81,30 +82,39 @@ export interface SectionProps wrap?: boolean; } -export function Section({ - flexDirection = "column", - justifyContent = "center", - alignItems = "center", - gap = 1, - padding = 0, - fit, - wrap, - ...rest -}: SectionProps) { - const width = fit ? "w-fit" : "w-full"; +const Section = forwardRef( + ( + { + flexDirection = "column", + justifyContent = "center", + alignItems = "center", + gap = 1, + padding = 0, + fit, + wrap, + ...rest + }, + ref + ) => { + const width = fit ? "w-fit" : "w-full"; - return ( -
- ); -} + return ( +
+ ); + } +); +Section.displayName = "Section"; + +export { Section }; diff --git a/web/src/layouts/input-layouts.tsx b/web/src/layouts/input-layouts.tsx index 73f78ac44a5..903587a3388 100644 --- a/web/src/layouts/input-layouts.tsx +++ b/web/src/layouts/input-layouts.tsx @@ -5,7 +5,7 @@ import Text from "@/refresh-components/texts/Text"; import { SvgXOctagon, SvgAlertCircle } from "@opal/icons"; import { useField, useFormikContext } from "formik"; -export interface OrientationLayoutProps extends LabelLayoutProps { +interface OrientationLayoutProps extends LabelLayoutProps { name?: string; children?: React.ReactNode; } @@ -32,28 +32,30 @@ export interface OrientationLayoutProps extends LabelLayoutProps { * * ``` */ +export interface VerticalLayoutProps extends OrientationLayoutProps { + subDescription?: React.ReactNode; +} function VerticalInputLayout({ children, + subDescription, name, ...fieldLabelProps -}: OrientationLayoutProps) { +}: VerticalLayoutProps) { return (
{children} {name && } + {subDescription && ( + + {subDescription} + + )}
); } -export interface HorizontalLayoutProps extends OrientationLayoutProps { - /** Align input to the start (top) of the label/description */ - start?: boolean; - /** Align input to the center (middle) of the label/description */ - center?: boolean; -} - /** * HorizontalInputLayout - A layout component for form fields with horizontal label arrangement * @@ -96,6 +98,12 @@ export interface HorizontalLayoutProps extends OrientationLayoutProps { * * ``` */ +export interface HorizontalLayoutProps extends OrientationLayoutProps { + /** Align input to the start (top) of the label/description */ + start?: boolean; + /** Align input to the center (middle) of the label/description */ + center?: boolean; +} function HorizontalInputLayout({ children, @@ -136,15 +144,6 @@ function HorizontalInputLayout({ ); } -export interface LabelLayoutProps { - name?: string; - label?: string; - optional?: boolean; - description?: string; - start?: boolean; - center?: boolean; -} - /** * LabelLayout - A reusable label component for form fields * @@ -171,6 +170,14 @@ export interface LabelLayoutProps { * /> * ``` */ +export interface LabelLayoutProps { + name?: string; + label?: string; + optional?: boolean; + description?: string; + start?: boolean; + center?: boolean; +} function LabelLayout({ name, label, @@ -214,10 +221,6 @@ function LabelLayout({ ); } -interface FieldErrorLayoutProps { - name: string; -} - /** * ErrorLayout - Displays Formik field validation errors * @@ -240,6 +243,9 @@ interface FieldErrorLayoutProps { * This component uses Formik's `useField` hook internally and requires * the component to be rendered within a Formik context. */ +interface FieldErrorLayoutProps { + name: string; +} function ErrorLayout({ name }: FieldErrorLayoutProps) { const [, meta] = useField(name); const { status } = useFormikContext(); diff --git a/web/src/refresh-components/EmptyMessage.tsx b/web/src/refresh-components/EmptyMessage.tsx index 66101d2a4c9..fadd2e90435 100644 --- a/web/src/refresh-components/EmptyMessage.tsx +++ b/web/src/refresh-components/EmptyMessage.tsx @@ -30,24 +30,42 @@ import { SvgEmpty } from "@opal/icons"; import Card from "@/refresh-components/cards/Card"; -import * as GeneralLayouts from "@/layouts/general-layouts"; +import { Section } from "@/layouts/general-layouts"; import Text from "@/refresh-components/texts/Text"; +import { IconProps } from "@opal/types"; +import { cn } from "@/lib/utils"; export interface EmptyMessageProps { - children: string; + icon?: React.FunctionComponent; + title: string; + description?: string; } -export default function EmptyMessage({ children }: EmptyMessageProps) { +export default function EmptyMessage({ + icon: Icon = SvgEmpty, + title, + description, +}: EmptyMessageProps) { return ( - - - {children} - +
+ +
+
+ {title} + {description && ( + + {description} + + )} +
+
); } diff --git a/web/src/refresh-components/Modal.tsx b/web/src/refresh-components/Modal.tsx index 1b0921a7773..99aa73e2235 100644 --- a/web/src/refresh-components/Modal.tsx +++ b/web/src/refresh-components/Modal.tsx @@ -8,6 +8,8 @@ import Text from "@/refresh-components/texts/Text"; import IconButton from "@/refresh-components/buttons/IconButton"; import { SvgX } from "@opal/icons"; import Truncated from "@/refresh-components/texts/Truncated"; +import { WithoutStyles } from "@/types"; +import { Section, SectionProps } from "@/layouts/general-layouts"; /** * Modal Root Component @@ -37,15 +39,14 @@ const ModalRoot = DialogPrimitive.Root; */ const ModalOverlay = React.forwardRef< React.ComponentRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( + WithoutStyles> +>(({ ...props }, ref) => ( @@ -53,12 +54,13 @@ const ModalOverlay = React.forwardRef< ModalOverlay.displayName = DialogPrimitive.Overlay.displayName; /** - * Modal Context for managing close button ref and warning state + * Modal Context for managing close button ref, warning state, and size variant */ interface ModalContextValue { closeButtonRef: React.RefObject; hasAttemptedClose: boolean; setHasAttemptedClose: (value: boolean) => void; + sizeVariant: "large" | "medium" | "small" | "tall" | "mini"; } const ModalContext = React.createContext(null); @@ -118,7 +120,9 @@ const sizeClassNames = { * ``` */ interface ModalContentProps - extends React.ComponentPropsWithoutRef { + extends WithoutStyles< + React.ComponentPropsWithoutRef + > { large?: boolean; medium?: boolean; small?: boolean; @@ -133,7 +137,6 @@ const ModalContent = React.forwardRef< >( ( { - className, children, large, medium, @@ -268,7 +271,12 @@ const ModalContent = React.forwardRef< return ( {!skipOverlay && } @@ -284,10 +292,10 @@ const ModalContent = React.forwardRef< contentRef(node); }} className={cn( - "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2", + "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden", "z-modal", "bg-background-tint-00 border rounded-16 shadow-2xl", - "flex flex-col overflow-auto", + "flex flex-col", // Never exceed viewport on small screens "max-w-[calc(100dvw-2rem)] max-h-[calc(100dvh-2rem)]", "data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0", @@ -295,8 +303,7 @@ const ModalContent = React.forwardRef< "data-[state=open]:slide-in-from-top-1/2 data-[state=closed]:slide-out-to-top-1/2", "duration-200", // Size variants - sizeClassNames[variant], - className + sizeClassNames[variant] )} onOpenAutoFocus={(e) => { // Reset typing detection when modal opens @@ -330,33 +337,30 @@ ModalContent.displayName = DialogPrimitive.Content.displayName; * * @example * ```tsx - * + * * * // With custom content * // Children render below the provided title/description stack. - * + * * * * ``` */ -interface ModalHeaderProps extends React.HTMLAttributes { +interface ModalHeaderProps extends WithoutStyles { icon: React.FunctionComponent; title: string; titleClassName?: string; description?: string; onClose?: () => void; - withBottomShadow?: boolean; } const ModalHeader = React.forwardRef( ( { - withBottomShadow = false, icon: Icon, title, titleClassName, description, onClose, - className, children, ...props }, @@ -365,17 +369,14 @@ const ModalHeader = React.forwardRef( const { closeButtonRef } = useModalContext(); return ( -
-
-
+
+
+
{onClose && (
(
)} -
+ {title} {description && ( - + {description} )} -
+ {children} -
+ ); } ); @@ -425,16 +426,30 @@ ModalHeader.displayName = "ModalHeader"; * * ``` */ -interface ModalBodyProps extends React.HTMLAttributes {} +interface ModalBodyProps extends WithoutStyles { + twoTone?: boolean; +} const ModalBody = React.forwardRef( - ({ className, children, ...props }, ref) => { + ({ twoTone = true, children, ...props }, ref) => { + const { sizeVariant } = useModalContext(); + + // Apply overflow-auto for fixed height variants (large, small, tall) + const hasFixedHeight = + sizeVariant === "large" || + sizeVariant === "small" || + sizeVariant === "tall"; + return (
- {children} +
+ {children} +
); } @@ -449,35 +464,27 @@ ModalBody.displayName = "ModalBody"; * @example * ```tsx * // Right-aligned buttons - * + * * * * - * - * // Space-between layout - * - * 3 files selected - * - * * ``` */ -interface ModalFooterProps extends React.HTMLAttributes {} -const ModalFooter = React.forwardRef( - ({ className, children, ...props }, ref) => { - return ( -
- {children} -
- ); - } -); +const ModalFooter = React.forwardRef< + HTMLDivElement, + WithoutStyles +>(({ ...props }, ref) => { + return ( +
+ ); +}); ModalFooter.displayName = "ModalFooter"; export default Object.assign(ModalRoot, { diff --git a/web/src/refresh-components/ScrollIndicatorDiv.tsx b/web/src/refresh-components/ScrollIndicatorDiv.tsx index 2d59656e418..9eaa018fa28 100644 --- a/web/src/refresh-components/ScrollIndicatorDiv.tsx +++ b/web/src/refresh-components/ScrollIndicatorDiv.tsx @@ -97,7 +97,7 @@ export default function ScrollIndicatorDiv({ }; return ( -
+
{/* Top indicator */} {!disableIndicators && showTopIndicator && (
( - ( - { main, internal, error, disabled, action, className, rows = 4, ...props }, - ref - ) => { + ({ main, internal, error, disabled, className, rows = 4, ...props }, ref) => { const variant = main ? "main" : internal @@ -66,8 +62,6 @@ const InputTextArea = React.forwardRef( ? "disabled" : "main"; - const paddingClasses = action ? "pl-0.5 pr-16 py-0.5" : "p-0.5"; - return (
( className )} > - {action && ( -
- {action} -
- )}