feat: consolidate shared UI and harden browser authority for release
This commit is contained in:
@@ -16,6 +16,7 @@ import FloatingStatus from "../src/components/FloatingStatus";
|
||||
import FormSection from "../src/components/FormSection";
|
||||
import { PlatformLanguageProvider } from "../src/i18n/LanguageContext";
|
||||
import MetricGrid from "../src/components/MetricGrid";
|
||||
import LoadingFrame from "../src/components/LoadingFrame";
|
||||
import PageActionBar from "../src/components/PageActionBar";
|
||||
import SelectionList, { SelectionListItem, SelectionListItemContent } from "../src/components/SelectionList";
|
||||
import StatePanel from "../src/components/StatePanel";
|
||||
@@ -23,6 +24,29 @@ import ProductAvailabilityState from "../src/components/ProductAvailabilityState
|
||||
import WorkspaceLayout from "../src/components/WorkspaceLayout";
|
||||
import WorkspaceFrame from "../src/components/WorkspaceFrame";
|
||||
import WorkspaceActionBar from "../src/components/WorkspaceActionBar";
|
||||
import Card from "../src/components/Card";
|
||||
import FormField from "../src/components/FormField";
|
||||
import ListSelectionFilter from "../src/components/ListSelectionFilter";
|
||||
|
||||
const tableCard = renderToStaticMarkup(<Card title="Directory" bodyLayout="table"><LoadingFrame loading={false}><div className="data-grid-shell">Rows</div></LoadingFrame></Card>);
|
||||
assert(tableCard.includes('data-card-body-layout="table"'), "table cards explicitly declare zero-inset geometry even with a loading wrapper");
|
||||
const wideField = renderToStaticMarkup(<FormField label="Wide field" className="form-field-wide"><input /></FormField>);
|
||||
assert(wideField.includes('class="form-field form-field-wide"'), "form fields retain layout classes on their labelled root");
|
||||
const filterOptions = [{ value: "a", label: "A" }, { value: "b", label: "B" }];
|
||||
for (const [selection, expectedCount] of [[null, 2], [[], 0], [["a"], 1]] as const) {
|
||||
const filter = renderToStaticMarkup(<ListSelectionFilter options={filterOptions} value={selection === null ? null : [...selection]} onChange={() => undefined} />);
|
||||
assert((filter.match(/checked=""/g) ?? []).length === expectedCount, "list filters distinguish unrestricted, none and explicit subset");
|
||||
}
|
||||
|
||||
const progressFrame = renderToStaticMarkup(<LoadingFrame loading indicator="none" label="Extracting" progress={25} progressLabel="1 of 4 files"><p>Preview</p></LoadingFrame>);
|
||||
assert(progressFrame.includes('aria-busy="true"'), "the shared loading frame marks its content busy");
|
||||
assert(progressFrame.includes('value="25"'), "measured progress is reported through a native progress bar");
|
||||
assert(progressFrame.includes('aria-valuetext="1 of 4 files"'), "progress can describe real processed counts");
|
||||
assert(!progressFrame.includes("loading-envelope"), "operation overlays can omit the envelope animation");
|
||||
const unknownFrame = renderToStaticMarkup(<LoadingFrame loading indicator="none" label="Inspecting" progress={null}><p>Preview</p></LoadingFrame>);
|
||||
assert(unknownFrame.includes("<progress") && !unknownFrame.includes('value="'), "unknown progress is indeterminate, never fabricated");
|
||||
const legacyFrame = renderToStaticMarkup(<LoadingFrame loading><p>Existing consumer</p></LoadingFrame>);
|
||||
assert(legacyFrame.includes("loading-envelope") && !legacyFrame.includes("<progress"), "existing loading-frame consumers retain their presentation");
|
||||
|
||||
// @ts-expect-error Refreshable pages must provide a Reload action.
|
||||
const refreshableWithoutReload = <PageActionBar variant="detail" refreshable />;
|
||||
@@ -71,7 +95,8 @@ assert(editorActionBarMarkup.includes('aria-label="Editor actions"'), "page acti
|
||||
assert(editorActionBarMarkup.includes('data-page-refreshable="true"'), "refreshable pages expose their refresh contract");
|
||||
assert(editorActionBarMarkup.includes('data-page-dirty="true"'), "editors expose their dirty state");
|
||||
assert(editorActionBarMarkup.includes('data-page-dirty-state="dirty"'), "dirty editors announce unsaved changes");
|
||||
assert(editorActionBarMarkup.indexOf('data-page-action-slot="reload"') < editorActionBarMarkup.indexOf('data-page-action-slot="context"'), "reload precedes contextual actions");
|
||||
assert(editorActionBarMarkup.indexOf('data-page-action-slot="context"') < editorActionBarMarkup.indexOf('data-page-action-slot="reload"'), "context stays leading while reload belongs to trailing actions");
|
||||
assert(editorActionBarMarkup.indexOf('data-page-action-group="trailing"') < editorActionBarMarkup.indexOf('data-page-action-slot="reload"'), "reload shares the right-aligned primary action group");
|
||||
assert(editorActionBarMarkup.indexOf('data-page-action-slot="help"') < editorActionBarMarkup.indexOf('data-page-action-slot="discard"'), "help precedes editor persistence actions");
|
||||
assert(editorActionBarMarkup.indexOf('data-page-action-slot="destructive"') < editorActionBarMarkup.indexOf('data-page-action-slot="discard"'), "destructive editor actions are separated from persistence actions");
|
||||
assert(editorActionBarMarkup.includes('data-page-action-separation="destructive"'), "destructive actions expose their visual boundary");
|
||||
@@ -103,6 +128,7 @@ const collectionActionBarMarkup = renderToStaticMarkup(
|
||||
</PlatformLanguageProvider>
|
||||
);
|
||||
assert(collectionActionBarMarkup.indexOf('data-page-action-slot="reload"') < collectionActionBarMarkup.indexOf('data-page-action-slot="create"'), "collection creation remains the far-right action");
|
||||
assert(!collectionActionBarMarkup.includes('data-page-action-group="leading"'), "empty context groups do not create phantom rows in narrow toolbars");
|
||||
|
||||
const workspaceEditorActionBarMarkup = renderToStaticMarkup(
|
||||
<PlatformLanguageProvider>
|
||||
|
||||
Reference in New Issue
Block a user