diff --git a/docs/INTERFACE_PATTERN_MIGRATION.md b/docs/INTERFACE_PATTERN_MIGRATION.md index a692d3e..d1c5db2 100644 --- a/docs/INTERFACE_PATTERN_MIGRATION.md +++ b/docs/INTERFACE_PATTERN_MIGRATION.md @@ -18,6 +18,8 @@ domain modules own their compositions. | Responsive action toolbar | Domain-neutral action and filter grouping for pages, workspaces, editors, and overlays | Density, surface, grouping, flexible space, accessible naming, toolbar help identity, and responsive wrapping are centralized while modules retain action wording, authority, and consequence | `ActionToolbar.tsx`, `layout-primitives.test.tsx`, WYSIWYG, Calendar, Files, Forms, Templates, and the product-wide primitive check | | Content and form grids | Equal-column content, field, and native-form geometry | Explicit 1–4 columns, standard gaps, item spans, alignment, and named narrow/workspace/standard/wide collapse points replace generic and module-prefixed copies; unequal domain tracks remain local | `ContentGrid.tsx`, `layout-primitives.test.tsx`, Core dashboard/settings/mail, Calendar dialogs, Forms editor, Datasources, Postbox, Campaign, administration surfaces, and the product-wide primitive check | | Form sections | Reusable heading/description/action/content grouping inside forms | Plain, separated, and panel variants centralize hierarchy and narrow action placement without moving validation, permissions, values, or domain wording into Core | `FormSection.tsx`, `layout-primitives.test.tsx`, Addresses contact editing, and Quick Access preferences | +| Metric groups | Reusable responsive grouping around metric cards | Fixed one-to-five and auto-fit columns, minimum card widths, density, block/inset/zero spacing, and named collapse points replace the product-wide `metric-grid` class and cross-module dashboard overrides | `MetricGrid.tsx`, `MetricCard.tsx`, `layout-primitives.test.tsx`, Core and Dashboard summaries, administration, Campaign, Ops, Files, Search, and dashboard widgets | +| Description lists | Semantic property and fact presentation | Stacked and inline variants, one-to-five list columns, density, term width, wrapping, and responsive collapse replace both `admin-details-grid` and `detail-list`; `DescriptionItem` preserves native `dt`/`dd` anatomy | `DescriptionList.tsx`, `layout-primitives.test.tsx`, Access and Tenancy administration, Audit, Policy, Campaign reports/imports, Docs, Settings, Ops, and Reporting | | Dialog anatomy | Shared outer dialog plus composable body and footer regions | Size and administration variants, body padding, descriptions, notices, fixed action wrapping, native form flow, and section grouping are centralized; focus trapping and stack lifecycle remain unchanged | `Dialog.tsx`, `DialogAnatomy.tsx`, `dialog-focus.test.tsx`, `layout-primitives.test.tsx`, Addresses, Calendar, Records, Datasources, Distribution Lists, Files, and Templates | | Shared configuration primitives | Cross-module component contract | Dialog focus, blocker structure, disabled-action focus, route/page/field/action F1 help, unsaved changes, confirmation, loading, alerts, problem lists, and policy provenance are centralized | Core component tests, `CONTEXTUAL_HELP_CONTRACT.md`, and module-permutation build | @@ -38,6 +40,8 @@ repository and may only decrease. New headed pages use `PageLayout`; pages inside `WorkspaceLayout` use its `workspace` mode so the pane owns scrolling while the page retains the standard inset. Module CSS continues to own domain content layout, never the shared page or workspace frame. Raw toolbar tags, -retired generic grid classes, raw dialog-form wrappers, and module-local copies -of the shared toolbar/grid/form-section/dialog-anatomy components are rejected -by `check-shared-webui-primitives.py`. +retired generic grid and description-list classes, raw dialog-form wrappers, +and module-local copies of the shared toolbar/grid/form-section/dialog-anatomy +components are rejected by `check-shared-webui-primitives.py`. That check also +requires standard dialog widths to use `Dialog size` and keeps every remaining +domain-specific width in a reviewed, decrease-only exception baseline. diff --git a/webui/src/components/ConfirmDialog.tsx b/webui/src/components/ConfirmDialog.tsx index e9f454e..612c2ac 100644 --- a/webui/src/components/ConfirmDialog.tsx +++ b/webui/src/components/ConfirmDialog.tsx @@ -38,6 +38,7 @@ export default function ConfirmDialog({ open={open} title={title} role="alertdialog" + size="small" className="confirm-dialog" footerClassName="button-row compact-actions" closeOnBackdrop={!busy} diff --git a/webui/src/components/CredentialEnvelopeManager.tsx b/webui/src/components/CredentialEnvelopeManager.tsx index 0201223..769494f 100644 --- a/webui/src/components/CredentialEnvelopeManager.tsx +++ b/webui/src/components/CredentialEnvelopeManager.tsx @@ -512,7 +512,6 @@ export default function CredentialEnvelopeManager({ helpModuleId="access" onClose={closeEditor} closeDisabled={saving} - className="adaptive-config-dialog" footerClassName="button-row compact-actions" footer={ <> diff --git a/webui/src/components/DescriptionList.tsx b/webui/src/components/DescriptionList.tsx new file mode 100644 index 0000000..04d8507 --- /dev/null +++ b/webui/src/components/DescriptionList.tsx @@ -0,0 +1,59 @@ +import type { HTMLAttributes, ReactNode } from "react"; + +export type DescriptionListColumns = 1 | 2 | 3 | 4 | 5; +export type DescriptionListDensity = "compact" | "default"; +export type DescriptionListCollapseAt = "narrow" | "workspace" | "standard" | "wide" | "never"; +export type DescriptionListVariant = "stacked" | "inline"; +export type DescriptionListTermWidth = "compact" | "default" | "wide"; + +export type DescriptionListProps = HTMLAttributes & { + children: ReactNode; + columns?: DescriptionListColumns; + density?: DescriptionListDensity; + collapseAt?: DescriptionListCollapseAt; + variant?: DescriptionListVariant; + termWidth?: DescriptionListTermWidth; +}; + +export default function DescriptionList({ + children, + columns, + density = "default", + collapseAt = "workspace", + variant = "stacked", + termWidth = "default", + className = "", + ...props +}: DescriptionListProps) { + const resolvedColumns = columns ?? (variant === "inline" ? 1 : 2); + return ( +
+ {children} +
+ ); +} + +export type DescriptionItemProps = HTMLAttributes & { + term: ReactNode; + children: ReactNode; +}; + +export function DescriptionItem({ term, children, className = "", ...props }: DescriptionItemProps) { + return ( +
+
{term}
+
{children}
+
+ ); +} diff --git a/webui/src/components/MetricGrid.tsx b/webui/src/components/MetricGrid.tsx new file mode 100644 index 0000000..8de6bad --- /dev/null +++ b/webui/src/components/MetricGrid.tsx @@ -0,0 +1,44 @@ +import type { HTMLAttributes, ReactNode } from "react"; + +export type MetricGridColumns = 1 | 2 | 3 | 4 | 5 | "auto"; +export type MetricGridDensity = "compact" | "default" | "loose"; +export type MetricGridSpacing = "block" | "inset" | "none"; +export type MetricGridMinimum = "fluid" | "compact" | "default" | "wide"; +export type MetricGridCollapseAt = "narrow" | "workspace" | "standard" | "wide" | "never"; + +export type MetricGridProps = HTMLAttributes & { + children: ReactNode; + columns?: MetricGridColumns; + density?: MetricGridDensity; + spacing?: MetricGridSpacing; + minimum?: MetricGridMinimum; + collapseAt?: MetricGridCollapseAt; +}; + +export default function MetricGrid({ + children, + columns = 4, + density = "default", + spacing = "block", + minimum = "default", + collapseAt = "workspace", + className = "", + ...props +}: MetricGridProps) { + return ( +
+ {children} +
+ ); +} diff --git a/webui/src/features/dashboard/DashboardPage.tsx b/webui/src/features/dashboard/DashboardPage.tsx index c745ee1..e26c7ef 100644 --- a/webui/src/features/dashboard/DashboardPage.tsx +++ b/webui/src/features/dashboard/DashboardPage.tsx @@ -1,6 +1,8 @@ import ContentGrid from "../../components/ContentGrid"; import Card from "../../components/Card"; import MetricCard from "../../components/MetricCard"; +import MetricGrid from "../../components/MetricGrid"; +import DescriptionList from "../../components/DescriptionList"; import PageLayout from "../../components/PageLayout"; import { usePlatformModules } from "../../platform/ModuleContext"; @@ -13,22 +15,22 @@ export default function DashboardPage() { description="Install and enable the dashboard module to make this page configurable." viewportClassName="core-dashboard-page" > -
+ -
+ {modules.length === 0 ?

i18n:govoplan-core.no_feature_modules_are_active.e9c2d936

: -
+ {modules.map((module) =>
{module.id}
{module.label} i18n:govoplan-core.v.26c12f1e{module.version}
)} -
+ }
diff --git a/webui/src/features/settings/SettingsPage.tsx b/webui/src/features/settings/SettingsPage.tsx index 3abb0c1..16a7bf5 100644 --- a/webui/src/features/settings/SettingsPage.tsx +++ b/webui/src/features/settings/SettingsPage.tsx @@ -1,3 +1,4 @@ +import DescriptionList from "../../components/DescriptionList"; import ContentGrid, { FormGrid } from "../../components/ContentGrid"; import { useEffect, useMemo, useState } from "react"; import { useSearchParams } from "react-router"; @@ -344,12 +345,12 @@ export default function SettingsPage({ -
+
i18n:govoplan-core.account_id.c5e0db28
{auth.user.account_id}
i18n:govoplan-core.active_tenant.39b16ee9
{auth.active_tenant?.name || auth.tenant.name}
i18n:govoplan-core.tenant_roles.51aca82d
{auth.roles.filter((role) => role.level !== "system").map((role) => role.name).join(", ") || "i18n:govoplan-core.none.6eef6648"}
i18n:govoplan-core.system_roles.a9461aa6
{auth.roles.filter((role) => role.level === "system").map((role) => role.name).join(", ") || "i18n:govoplan-core.none.6eef6648"}
-
+

i18n:govoplan-core.email_changes_and_password_management_require_de.f7443b69

@@ -448,14 +449,14 @@ export default function SettingsPage({ ariaLabel="i18n:govoplan-core.theme.a797e309" /> -
+
i18n:govoplan-core.theme.a797e309
{themeLabel(theme)}
i18n:govoplan-core.accent_color.e49578ed
i18n:govoplan-core.default_brand_accent.606ae693
i18n:govoplan-core.language.89b86ab0
{languageLabel}
i18n:govoplan-core.enabled.df174a3f
{enabledLanguages.map((item) => item.code.toUpperCase()).join(", ")}
i18n:govoplan-core.available.7c62a142
{availableLanguages.map((item) => item.code.toUpperCase()).join(", ")}
i18n:govoplan-core.density.f9160c22
{compactTables ? "i18n:govoplan-core.compact_preview.3e06901d" : "i18n:govoplan-core.comfortable.2313707a"}
-
+ @@ -530,11 +531,11 @@ export default function SettingsPage({ -
+
i18n:govoplan-core.browser_session.cc021a31
i18n:govoplan-core.active_via_httponly_cookie.9d05e6ba
i18n:govoplan-core.automation_key.78f1ddbc
{settings.apiKey ? "i18n:govoplan-core.configured.668c5fff" : "i18n:govoplan-core.not_configured.811931bb"}
i18n:govoplan-core.backend_mode.c863723a
{settings.apiBaseUrl ? "i18n:govoplan-core.explicit_api_url.b117b4b8" : "i18n:govoplan-core.same_origin_proxied.c39e6e2b"}
-
+

i18n:govoplan-core.tenant_user_mail_server_and_policy_administratio.2f551271

diff --git a/webui/src/index.ts b/webui/src/index.ts index d7db136..bd0a49e 100644 --- a/webui/src/index.ts +++ b/webui/src/index.ts @@ -90,6 +90,8 @@ export { default as Dialog } from "./components/Dialog"; export type { DialogBodyPadding, DialogProps, DialogSize, DialogVariant } from "./components/Dialog"; export { DialogActions, DialogForm, DialogSection } from "./components/DialogAnatomy"; export type { DialogActionAlignment, DialogActionsProps, DialogFormProps, DialogSectionProps } from "./components/DialogAnatomy"; +export { default as DescriptionList, DescriptionItem } from "./components/DescriptionList"; +export type { DescriptionItemProps, DescriptionListCollapseAt, DescriptionListColumns, DescriptionListDensity, DescriptionListProps, DescriptionListTermWidth, DescriptionListVariant } from "./components/DescriptionList"; export { default as DisabledActionTooltip } from "./components/DisabledActionTooltip"; export type { DisabledActionTooltipProps } from "./components/DisabledActionTooltip"; export { default as DismissibleAlert } from "./components/DismissibleAlert"; @@ -118,6 +120,8 @@ export { default as LoadingIndicator } from "./components/LoadingIndicator"; export { default as ExplorerTree } from "./components/ExplorerTree"; export type { ExplorerTreeNodeContext, ExplorerTreeProps } from "./components/ExplorerTree"; export { default as MetricCard } from "./components/MetricCard"; +export { default as MetricGrid } from "./components/MetricGrid"; +export type { MetricGridCollapseAt, MetricGridColumns, MetricGridDensity, MetricGridMinimum, MetricGridProps, MetricGridSpacing } from "./components/MetricGrid"; export { default as MessageDisplayPanel } from "./components/MessageDisplayPanel"; export type { MessageDisplayAttachment, MessageDisplayField } from "./components/MessageDisplayPanel"; export { default as PageTitle } from "./components/PageTitle"; diff --git a/webui/src/styles/components.css b/webui/src/styles/components.css index f1b8b64..fa43112 100644 --- a/webui/src/styles/components.css +++ b/webui/src/styles/components.css @@ -522,10 +522,6 @@ gap: 10px; } -.module-management-metrics { - grid-template-columns: repeat(5, minmax(120px, 1fr)); -} - .module-management-row { display: grid; grid-template-columns: minmax(0, 1fr) 170px; @@ -1179,10 +1175,6 @@ min-width: 0; } -.adaptive-config-dialog { - width: min(1040px, calc(100vw - 40px)); -} - .adaptive-config-dialog-body { background: var(--panel-soft); } @@ -3539,9 +3531,6 @@ color: var(--muted); font-weight: 700; } -.compact-detail-list { - gap: 8px; -} .settings-list { display: grid; gap: 12px; @@ -3576,26 +3565,51 @@ .admin-audit-grid .data-grid-header-cell { top: 0; } -.admin-details-grid { +.description-list-layout { + --description-list-term-width: 145px; display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 10px 18px; + margin: 0; } -.admin-details-grid > div { +.description-list-columns-1 { grid-template-columns: minmax(0, 1fr); } +.description-list-columns-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.description-list-columns-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } +.description-list-columns-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } +.description-list-columns-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } +.description-list-stacked { gap: 10px 18px; } +.description-list-stacked > div { min-width: 0; padding: 10px 0; border-bottom: var(--border-line); } -.admin-details-grid dt { +.description-list-stacked.description-list-density-compact { gap: 6px 14px; } +.description-list-stacked.description-list-density-compact > div { padding: 6px 0; } +.description-list-inline { gap: 12px; } +.description-list-inline > div { + min-width: 0; + display: grid; + grid-template-columns: var(--description-list-term-width) minmax(0, 1fr); + align-items: center; + gap: 18px; + padding-bottom: 12px; + border-bottom: var(--border-line); +} +.description-list-inline > div:last-child { padding-bottom: 0; border-bottom: 0; } +.description-list-inline.description-list-density-compact { gap: 8px; } +.description-list-term-compact { --description-list-term-width: minmax(92px, auto); } +.description-list-term-default { --description-list-term-width: 145px; } +.description-list-term-wide { --description-list-term-width: 200px; } +.description-list-layout dt { color: var(--muted); font-size: 12px; font-weight: 700; text-transform: uppercase; } -.admin-details-grid dd { +.description-list-stacked dd { margin: 4px 0 0; overflow-wrap: anywhere; } +.description-list-inline dt { font-weight: 800; letter-spacing: .04em; } +.description-list-inline dd { min-width: 0; margin: 0; overflow-wrap: anywhere; } .admin-governance-mode { display: grid; gap: 8px; @@ -3748,10 +3762,28 @@ a.dashboard-contribution-row:hover { margin-top: 12px; } @media (max-width: 900px) { - .admin-details-grid, + .description-list-collapse-workspace, .admin-tenant-assignment-row { grid-template-columns: 1fr; } + .description-list-inline.description-list-collapse-workspace > div { + grid-template-columns: minmax(0, 1fr); + } +} + +@media (max-width: 1100px) { + .description-list-collapse-wide { grid-template-columns: 1fr; } + .description-list-inline.description-list-collapse-wide > div { grid-template-columns: minmax(0, 1fr); } +} + +@media (max-width: 980px) { + .description-list-collapse-standard { grid-template-columns: 1fr; } + .description-list-inline.description-list-collapse-standard > div { grid-template-columns: minmax(0, 1fr); } +} + +@media (max-width: 700px) { + .description-list-collapse-narrow { grid-template-columns: 1fr; } + .description-list-inline.description-list-collapse-narrow > div { grid-template-columns: minmax(0, 1fr); } } .stage-rail { max-width: 100%; diff --git a/webui/src/styles/dialogs.css b/webui/src/styles/dialogs.css index 2ba2314..2a92eb6 100644 --- a/webui/src/styles/dialogs.css +++ b/webui/src/styles/dialogs.css @@ -177,10 +177,6 @@ .dialog-section-separated { padding-top: 16px; border-top: var(--border-line); } .dialog-section-inset { padding: 14px; border: var(--border-line); border-radius: var(--radius); background: var(--panel-soft); } -.confirm-dialog { - width: min(460px, calc(100vw - 40px)); -} - .confirm-dialog > .dialog-header, .confirm-dialog > .dialog-footer { background: var(--panel); diff --git a/webui/src/styles/layout.css b/webui/src/styles/layout.css index 47e6786..b458a24 100644 --- a/webui/src/styles/layout.css +++ b/webui/src/styles/layout.css @@ -217,8 +217,27 @@ .card-header h2 { margin: 0; font-size: 16px; color: var(--text-strong); } .card-actions { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap;} .card-body { padding: 22px 24px; } -.metric-grid { display: grid; grid-template-columns: repeat(4, minmax(140px, 1fr)); gap: 12px; margin-bottom: 18px; } -.metric-grid.inside { margin: 14px 0; } +.metric-group-layout { + --metric-group-column-minimum: 140px; + min-width: 0; + display: grid; +} +.metric-group-columns-1 { grid-template-columns: minmax(0, 1fr); } +.metric-group-columns-2 { grid-template-columns: repeat(2, minmax(var(--metric-group-column-minimum), 1fr)); } +.metric-group-columns-3 { grid-template-columns: repeat(3, minmax(var(--metric-group-column-minimum), 1fr)); } +.metric-group-columns-4 { grid-template-columns: repeat(4, minmax(var(--metric-group-column-minimum), 1fr)); } +.metric-group-columns-5 { grid-template-columns: repeat(5, minmax(var(--metric-group-column-minimum), 1fr)); } +.metric-group-columns-auto { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--metric-group-column-minimum)), 1fr)); } +.metric-group-density-compact { gap: 8px; } +.metric-group-density-default { gap: 12px; } +.metric-group-density-loose { gap: 18px; } +.metric-group-spacing-block { margin: 0 0 18px; } +.metric-group-spacing-inset { margin: 14px 0; } +.metric-group-spacing-none { margin: 0; } +.metric-group-minimum-fluid { --metric-group-column-minimum: 0px; } +.metric-group-minimum-compact { --metric-group-column-minimum: 112px; } +.metric-group-minimum-default { --metric-group-column-minimum: 140px; } +.metric-group-minimum-wide { --metric-group-column-minimum: 180px; } .metric-card { background: var(--panel); border: var(--border-line); border-radius: var(--radius); padding: 18px; box-shadow: var(--shadow); border-top: 4px solid var(--line-dark); } .metric-good { border-top-color: var(--green); } .metric-warning { border-top-color: var(--amber); } .metric-danger { border-top-color: var(--red); } .metric-info { border-top-color: var(--blue); } .metric-label { color: var(--muted); font-size: 12px; text-transform: uppercase; font-weight: 800; letter-spacing: .05em; } @@ -280,10 +299,22 @@ .workspace-layout-split { grid-template-columns: 1fr; grid-template-rows: minmax(160px, 34%) minmax(0, 1fr); } .section-sidebar { display: none; } .wizard-card { grid-template-columns: 1fr; } - .metric-grid { grid-template-columns: 1fr; } + .metric-group-collapse-workspace { grid-template-columns: minmax(0, 1fr); } .concurrency-conflict-values { grid-template-columns: 1fr; } } +@media (max-width: 1100px) { + .metric-group-collapse-wide { grid-template-columns: minmax(0, 1fr); } +} + +@media (max-width: 980px) { + .metric-group-collapse-standard { grid-template-columns: minmax(0, 1fr); } +} + +@media (max-width: 700px) { + .metric-group-collapse-narrow { grid-template-columns: minmax(0, 1fr); } +} + @media (max-width: 700px) { .action-toolbar-wrap-responsive { align-items: stretch; flex-wrap: wrap; } .action-toolbar-wrap-responsive > .action-toolbar-group { flex: 1 1 100%; } @@ -315,11 +346,6 @@ .crumb-link:hover { background: var(--sidebar-hover-bg); color: var(--text-strong); } .compact-actions { margin: 0; align-items: center; } .below-grid { margin-top: 18px; } -.detail-list { display: grid; gap: 12px; margin: 0; } -.detail-list div { display: grid; grid-template-columns: 145px minmax(0, 1fr); align-items: center; gap: 18px; padding-bottom: 12px; border-bottom: var(--border-line); } -.detail-list div:last-child { border-bottom: 0; padding-bottom: 0; } -.detail-list dt { color: var(--muted); font-size: 12px; text-transform: uppercase; font-weight: 800; letter-spacing: .04em; } -.detail-list dd { margin: 0; min-width: 0; } .next-action-card { border-left: 4px solid var(--blue); padding-left: 16px; } .next-action-card h2 { margin: 0; color: var(--text-strong); font-size: 19px; } .next-action-card p { margin: 8px 0 0; color: var(--muted); } @@ -387,7 +413,7 @@ width: 100%; margin-left: 0; } - .summary-grid, .detail-list div { grid-template-columns: 1fr; } + .summary-grid { grid-template-columns: 1fr; } .docs-workspace { grid-template-columns: 1fr; } .docs-outline { display: none; } .docs-content { grid-template-columns: 1fr; } diff --git a/webui/tests/layout-primitives.test.tsx b/webui/tests/layout-primitives.test.tsx index 7b79e22..77634ef 100644 --- a/webui/tests/layout-primitives.test.tsx +++ b/webui/tests/layout-primitives.test.tsx @@ -7,8 +7,10 @@ import ActionToolbar, { ToolbarGroup, ToolbarSpacer } from "../src/components/Ac import ContentGrid, { FormGrid, FormLayout, GridItem } from "../src/components/ContentGrid"; import Dialog from "../src/components/Dialog"; import { DialogForm, DialogSection } from "../src/components/DialogAnatomy"; +import DescriptionList, { DescriptionItem } from "../src/components/DescriptionList"; import FormSection from "../src/components/FormSection"; import { PlatformLanguageProvider } from "../src/i18n/LanguageContext"; +import MetricGrid from "../src/components/MetricGrid"; const toolbarMarkup = renderToStaticMarkup( @@ -39,6 +41,32 @@ assert(gridMarkup.includes("content-grid-columns-3"), "content grids expose expl assert(gridMarkup.includes("content-grid-collapse-wide"), "content grids expose explicit collapse ownership"); assert(gridMarkup.includes("content-grid-item-full"), "grid items can span the complete layout"); +const metricMarkup = renderToStaticMarkup( + +
Open
Closed
+
+); + +assert(metricMarkup.includes("metric-group-columns-auto"), "metric groups own responsive column geometry"); +assert(metricMarkup.includes("metric-group-spacing-inset"), "metric groups own their surrounding rhythm"); +assert(metricMarkup.includes("metric-group-collapse-standard"), "metric groups expose explicit collapse ownership"); + +const descriptionMarkup = renderToStaticMarkup( + + Ready + +); + +assert(descriptionMarkup.startsWith('
Status
Ready
"), "description items preserve term and description anatomy"); + +const inlineDescriptionMarkup = renderToStaticMarkup( + Ada +); +assert(inlineDescriptionMarkup.includes("description-list-columns-1"), "inline description lists default to one list column"); +assert(inlineDescriptionMarkup.includes("description-list-term-compact"), "inline description lists centralize term sizing"); + const formMarkup = renderToStaticMarkup( Reset}>