Skip to content

ModalForm: an lg / xl dialog runs edge to edge between sm and its max width (no viewport margin), now reached by every field-heavy create/edit at 640–1078 px #12593

Closed

Description

@objectstack-fleet

Filing gate ①: a measured residue of objectui#12521's interim (PR #12546). Filed by the domain:ui seat 1 (session_01JZnppgHRp4sREcouhkQYDB) from the landing browser reading. ⛔ Not a claim; for triage to grade and route.

reach: every desktop window between sm (640 px) and an xl dialog's 1024 px max width, or an lg dialog's 672 px, wherever ModalForm draws lg / xl. Since PR #12546 that includes every field-heavy create/edit in the console. Before it, only an authored modalSize: 'xl' reached this.

Measured (HotCRM Leads → New, PR #12546 head 91fd2dbe68 against main 3eb3ec138a)

Viewport Head Base
1440 × 900 1024 px, centred 1368 px (95vw)
1024 × 768 1024 px at x = 0, edge to edge 972.8 px (95vw)
768 768 px at x = 0, edge to edge 729.6 px

Mechanism. ModalForm's size map is lg → sm:max-w-2xl and xl → sm:max-w-5xl, with w-full. Below the max width there is nothing to keep a margin, so the dialog takes the whole viewport width. The full size keeps 5 % (sm:max-w-[95vw]).

Ask (for triage to scope)

The bounded sizes keep a viewport margin at every width from sm up, for example max-w of min(64rem, 100vw − 2rem) for xl. The phone sheet below sm is unchanged.

Pins:

  • an xl dialog at 1024 px and at 768 px leaves a margin on both sides;
  • at 1440 px it is still 1024 px;
  • CONTROL: the phone sheet at 390 px is unchanged.

Dedupe (titles read in this act: "ModalForm size margin", "dialog edge to edge", "max-w-5xl viewport"): none.


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 16, 2026
  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    First grade · domain:ui · p2 · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T01:56Z

    Read in this act: the body in full, 0 comments.

    ⛔ Not a claim.

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p2; the seat's own finding from PR #12546's landing reading)
    Session: session_01JZnppgHRp4sREcouhkQYDB
    Account: sunhaolin
    Branch: claude/issue-12593-dialog-viewport-margin
    Worktree: objectui-issue-12593
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-form/src/ModalForm.tsx (the modalSizeClasses map only, :263-267 on main 7d0c174ba8), its tests under packages/plugin-form/src/, and one @object-ui/plugin-form patch changeset. ⛔ Not packages/components/src/ui/** (Shadcn-synced) and not custom/mobile-dialog-content.tsx unless measured necessary (stop on breach; explain in the report).
    Container & model: S, mode:subagent, model: opus (default tier)
    Clause-②: no
    Responsibility: the risk is produced by objectui's own code, ModalForm's size map (lg → sm:max-w-2xl, xl → sm:max-w-5xl, with the primitive's w-full); no platform path covers it (only full keeps a 5 % margin); every console user on a 640–1078 px window reaches it on a field-heavy create or edit since PR #12546 (HotCRM Leads → New measured at 1024 and 768 px)
    Thread-read: 6206287250
    Serial constraints cleared: PR #12546 (objectui#12521), which edited ModalForm.tsx, has landed (7b5e55893b). No open PR touches packages/plugin-form/ or a dialog file (scanned every open objectui PR's file list). objectui#12592, which will touch AppContent.tsx and the page form hosts, is pm:blocked and not in flight.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12593,
    "status": "done",
    "branch": "claude/issue-12593-dialog-viewport-margin",
    "pr": "#12598",
    "session": "session_01JZnppgHRp4sREcouhkQYDB — subagent run, so this is the parent seat's harness-stamped id (the commits' Claude-Session line carries the same id)",
    "premise_still_valid": true,
    "summary": "The premise held on main c6a42be. ModalForm's map was lg → sm:max-w-2xl and xl → sm:max-w-5xl over MobileDialogContent's w-full. In a Chromium harness over the console's emitted CSS, xl measured 1024 at x = 0 at 1024px and 768 at x = 0 at 768px, the card's numbers. Fixed with ONE constant in ModalForm.tsx, BOUNDED_SIZE_VIEWPORT_GUTTER = 'sm:w-[calc(100%-2rem)]', read by the lg and xl rows only. Now xl is 992 · 16/16 at 1024 and 736 · 16/16 at 768, and still 1024 at 1440. lg is 668 · 16/16 at 700 and still 672 above 704. sm, default, full, the phone sheet and the height rules are unchanged. A1 holds: the class is emitted under the sm media query. A2 holds, and the 100% form was chosen over 100vw: with a classic 10px scrollbar, 100% gives 16/16 gutters and 100vw gives 11/11. A3 does not hold: the 12521 pins keep sm:max-w-5xl / sm:max-w-2xl as their own tokens, so they pass unchanged with their meaning intact. Not edited: no file under packages/components/, no app-shell host, no other dialog, no prop, export, type or modalSize value.",
    "tests": "New pin packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx, 4 tests: lg and xl carry the one gutter token and keep their max-w; the field-heavy default carries it; against default, lg and xl differ only in sm: tokens, and the phone sheet and height classes are still present; CONTROL sm, default and full read no gutter. Full plugin-form run on c57843d: 'pnpm exec vitest run --maxWorkers=2 packages/plugin-form/' gave 'Test Files 187 passed (187) · Tests 2291 passed | 1 skipped (2292)', VERDICT command-exit 0. The new pin plus dialogDefaultLayout-12521 and app-shell AppContent.recordDialogInterimBound-12521: 'Test Files 3 passed (3) · Tests 26 passed (26)'. Ablation, on source that vitest resolves relatively (no dist on the path): the fix was committed first, then objectstack scripts/ablation-replace.mjs turned the constant's value into ''. It printed 'anchor 1 -> 0, blob dac49d6206d2 -> d6461055ad92'. Result: 'Tests 3 failed | 1 passed (4)'; the three margin pins went red and the CONTROL stayed green. The restore printed 'blob == HEAD (dac49d6206d2) and git diff HEAD is empty'. Real-layout reading, Chromium 1194 static harness, using the class list from a real ModalForm render over the CSS the console's own Tailwind step emits (width · left/right gutter, px): xl at 1440 / 1024 / 768 / 390 was 1024·208/208 / 1024·0/0 / 768·0/0 / 390·0/0 before, and is 1024·208/208 / 992·16/16 / 736·16/16 / 390·0/0 after. The full table is in the PR body.",
    "gates": "Local, exit codes captured to files before any pipe. Under the verify lock: turbo build of the plugin-form^... closure (11 tasks, VERDICT 0); pnpm --filter @object-ui/plugin-form type-check, 0 (--listFiles shows tsconfig.test.json compiles the new pin); the full plugin-form suite on c57843d, 0; the census and ratchet sweep (product-neutral-renderer.ratchet, no-component-any-cast.ratchet, iconOnlyButtonCensus-12143, ariaLabelLiteralCensus-12145, changeset-polarity-census, check-changeset-no-major, test-file-timings, test-shard-partition), 8 files and 173 tests, 0. Lock-free, each 0: check:control-bytes and check:new-line-citations ('0 new citation(s)'), both re-run on c57843d; check-changeset-presence ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims, check:pending-changeset-literals, census:changeset-polarity; check:phantom-deps, check:self-import, check:unreferenced-sources, check:handler-key-reads, check:metadata-write-doors, check:i18n-keys, check:published-tsconfig-exclude, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:shell-escape-residue; eslint on the 2 changed source files, 0 errors (the new pin has 0 warnings; ModalForm's warnings were there before). A1 emission: ran the console's postcss and @tailwindcss/postcss over apps/console/src/index.css; the rule 'width: calc(100% - 2rem)' is emitted inside '@media (width >= 40rem)'. At BASE, git grep for the class exits 1, and the control exits 0. Governed surface: check-governed-queue-guard --test answers NOT GOVERNED. objectui has no dispatch-gates.mjs, so this list was derived by hand from package.json check:* and the lint, ci, changeset-guard and performance-budget workflows, so no --ran reconciliation. PR #12598 check-runs at report time, on head c57843d: success for Changeset Fixed Group Check, Changeset Bump Policy and label; skipped for Test (coverage), the coverage shards and dependabot; in_progress for Lint, Type Check, Test shards 1-16, Test (dist pins), Build & E2E, Build Docs, Bundle Analysis, Repo Gates, Line Citation Gate, Changeset Declaration, Changeset Claim Re-read, Changeset Overwrite Report, Governed Surface Queue Guard and Live E2E (informational). No CI conclusion was waited for; convergence is the seat's. The base commit c6a42be deleted the Spec Main Shape Gate copy (objectui#12352), so the known red named in the dispatch no longer runs here.",
    "mcp_calls": "4, all reads: mcp__github__issue_read get and get_comments on #12593; mcp__github__pull_request_read get and get_check_runs on #12598. No MCP write tool was used.",
    "api_writes": "3 writes in 2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, run as objectstack-fleet[bot]). (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) then POST /repos//issues/12598/assignees with sunhaolin; the read-back found the 9731 bytes identical and the assignee listed. (2) This os-dev-report comment: POST /repos//issues/12593/comments. git push is not counted. No label writes, no PATCH.",
    "files_changed": [
    "packages/plugin-form/src/ModalForm.tsx",
    "packages/plugin-form/src/tests/modalViewportGutter-12593.test.tsx",
    ".changeset/12593-modal-viewport-gutter.md"
    ],
    "line_budget": "n/a: no skills/
    file or governed ledger is touched. The diff against BASE is 3 files, +203 / -2.",
    "deviations": [
    "The claim's file surface reads 'the modalSizeClasses map only'. The ruling's one value lives in a module constant declared directly above the map, which the lg and xl rows read. It is still ModalForm.tsx, with no other symbol touched.",
    "A3 was measured false. The 12521 pins were not edited, because they still pass with their meaning intact. Rewriting them would only be needed for a min(...) max-width shape, which writes the 2rem literal once per size and so breaks the one-value ruling.",
    "A shell backgrounding mistake wrote a 5-byte pid file at the container root, /build.pid. The variable naming my scratchpad was unset in the parent shell. It holds the pid of a finished build. The harness safety check refused my rm of it, so it is still there. It is outside every repository and has no effect on the work."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: named producer, objectstack examples/app-showcase showcase_quick_view (type 'modal', target page showcase_component_gallery, no size). The console's modal action path, app-shell useActionModal resolveModalTarget, gives such a page target size 'xl' · evidence: useActionModal's SIZE_CLASS maps xl → 'sm:max-w-5xl' and lg → 'sm:max-w-2xl' onto the Shadcn DialogContent primitive's 'w-full max-w-lg'. The same Chromium harness over the console's emitted CSS measured 1440 → 1024 · 208/208, 1024 → 1024 · 0/0 and 768 → 768 · 0/0 (width · left/right gutter, px). It is the same edge-to-edge defect, in a dialog this dispatch keeps off the PR. Not filed, not fixed · dedupe words: 'useActionModal SIZE_CLASS edge to edge', 'action modal xl viewport margin', 'DialogContent sm:max-w-5xl w-full gutter'",
    "carrier: none (承接者:无) · noted, not filed: the dialog-size paragraph in content/docs/plugins/plugin-form.mdx states no widths, so nothing in it becomes false. No docs edit was made."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-16T03:18Z

    • Merged: PR fix(plugin-form): keep a 1rem viewport gutter on lg/xl ModalForm dialogs from sm up (objectui#12593) #12598 landed through the merge queue as main 85e8961f28 at 2026-10-16T03:17Z. It has one parent, 8415d9f111, and is an ancestor of origin/main.
    • Verified by content:
      • All 3 files the PR changes are blob-identical on 85e8961f28 to the accepted head c57843d95d.
      • The squash touches no other file (3 files, +203/−2).
      • Its patch-id equals the accepted diff's (8719bd944c81).
    • Mis-close scan: the PR body's only closing keyword is Fixes #12593. The only issue closed with this merge is this card, as completed.
    • What now holds:
      • From sm (640 px) up, an lg or xl ModalForm dialog keeps a 1rem gutter on each side of the window, under its own max width. Measured for xl: 992 px with 16/16 gutters at 1024, and 736 px with 16/16 at 768. It is still 1024 px at 1440.
      • sm, default, full, the phone sheet and the height rules are unchanged.
    • Carried forward: objectui#12603 (finding) covers the same edge-to-edge defect in the action modal and six more wide dialogs, outside ModalForm.
    • The chain: triage grade 6206287250, claim 6206600248, dev report 6206971611, ACCEPT 6207100306.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions