fix(detail,form,app-shell): four layout sets spell richtext the way the spec spells it - #4257
Merged
Merged
Conversation
…he spec spells it (#4250) `@objectstack/spec` spells the WYSIWYG type `richtext` and REJECTS `rich_text` / `rich-text` — both survive only as typo keys in the spec's own `suggestFieldType` table, so `FieldSchema.safeParse` refuses a field declared with either. Four sets that place fields by matching the RAW type string carried nothing but those dead spellings: RelatedList SKIP_TYPES rich_text -> richtext (+ markdown) plugin-detail WIDE_FIELD_TYPES rich-text -> richtext plugin-form WIDE_FIELD_TYPES rich-text -> richtext app-shell SECONDARY_FIELD_TYPES rich-text -> richtext Each set was therefore inert for the only spelling a producer can emit, while naming the very type it failed to handle. All four move together: half of them would leave the detail page and the form disagreeing about the same field. Dead spellings are dropped, not carried alongside — the alias table is the one place aliases live. Pins are DERIVED from the spec's `FieldType` vocabulary rather than enumerated, so the next drift fails by name; this replaces `isWideFieldType('rich-text')`, green only because the set held the string it asked about. `markdown` joins SKIP_TYPES on a measurement, not on the raw-markup story: markdown and richtext both render FORMATTED through MarkdownCellRenderer. What breaks the cell is that the formatted output is block-level (h1/p/ul) inside a `truncate` single-line cell, so a document shows as one clipped heading. `textarea` stays derived — plain truncated text is a useful column — and author-declared columns are untouched, since the set filters only the zero-config auto-derive walk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qqyix2QcnpUC9XeYVDzx3
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4250
@objectstack/specspells the WYSIWYG typerichtext— one word — and rejects the other two spellings outright. Verified against the installed dist rather than by grep:Both dead spellings exist in the spec only as typo keys in its own
suggestFieldTypetable (rich_text: "richtext", andrich-textnormalizes onto the same entry), i.e. inputs the spec corrects, never values a producer emits. Four sets that place fields by matching the RAW type string carried nothing else, so each was inert for the only spelling that can reach it — while naming the very type it failed to handle.Per-set evidence
richtextfield did beforeplugin-detail/src/RelatedList.tsxSKIP_TYPESrich_textrichtext(+markdown)plugin-detail/src/autoLayout.tsWIDE_FIELD_TYPESrich-text,field:rich-textrichtext,field:richtextmarkdown/htmlbeside itplugin-form/src/autoLayout.tsWIDE_FIELD_TYPESrich-text,field:rich-textrichtext,field:richtextapp-shell/src/views/RecordDetailView.tsxSECONDARY_FIELD_TYPESrich-textrichtextAll four move together — the card's own warning is that half of them would leave the detail page and the form disagreeing about the same field, which is worse than the uniform gap.
Dead spellings are dropped, not kept alongside: the alias table is the single place aliases belong, and a set carrying both invites the next drift.
The
markdownquestion — measured, and the measurement contradicts the card's rationaleThe card predicted "raw markup renders in a table cell". It does not. Rendering markdown and richtext columns through the real related-list cell path on the pre-fix tree produced formatted, sanitized GFM:
getCellRenderer('richtext')andgetCellRenderer('markdown')both resolve toMarkdownCellRenderer; there is no raw-syntax state, not even a Suspense flash once the chunk is loaded.So "has a formatting renderer" was never the discriminator this set used —
html, already skipped, formats too (HtmlCellRenderer,proseclasses). The real discriminator, and the reasonmarkdownjoins: the formatted output is BLOCK-level (a heading, paragraphs, a list) inside atruncatesingle-line table cell, so a document renders as one clipped heading with the rest invisible. That is precisely "no useful tabular rendering", the rule the set's own comment states.Two controls keep this from over-skipping (the objectui#2360 harm):
textareastays derived — the same measurement read the other way: plain truncated text is a useful cell.SKIP_TYPESfilters only the zero-config auto-derive walk, pinned by a test that declares a richtext column and asserts it still renders.The repo had already answered this question twice, one package over:
FORM_ONLY_TYPES("read poorly in ANY grid cell") andNON_EDITABLE_TYPESinplugin-form/src/deriveMasterDetail.tsboth grouphtml+markdown+richtexttogether.Pins
Derived from the spec vocabulary rather than enumerated (the #4226/#4207 precedent), so the next drift fails by name instead of passing vacuously the way
isWideFieldType('rich-text')did — that assertion was green only because the set contained the string it asked about.autoLayout.wideSpelling.test.ts(plugin-detail, plugin-form) — every bare member is checked againstFieldType.options; thefield:half is read out ofmapFieldTypeToFormTypeinstead of retyped, so the two halves cannot drift apart; the set's spec-facing surface is asserted to be EXACTLY the long-form family.RelatedList.longFormColumns.test.tsx— the DOM-level pin, asserting the RENDERED column set. Phrased as "no document markup in a cell", not "no raw markup", because the measurement above disproved the raw-markup framing.richtextSurfaceParity.test.tsx(app-shell, which depends on both plugins) — the cross-surface control: one shared fixture field asked of all three placement rules. Its parity assertions were green BEFORE the fix too (the four sets were uniformly wrong); their job is to go red on a HALF fix, and that is how they were verified.isWideFieldType('rich-text')/isWideFieldType('field:rich-text')assertions inplugin-form/__tests__/autoLayout.test.tsare replaced with the spec spellings.Reverse verification
Reverted one set at a time on the committed tree (
git checkout origin/main -- path, nevergit stash), predicting the reds first. All four matched:SKIP_TYPESTests 2 failed | 3 passed—expected span to be nullWIDE_FIELD_TYPESTests 8 failed | 4 passed, includingthe detail and form auto-layouts agree on EVERY spec field type— the half-fix detectorWIDE_FIELD_TYPESTests 10 failed | 45 passedSECONDARY_FIELD_TYPESTests 2 failed | 4 passedSweep completeness
A mechanical pass over all 21 field-type-keyed
Setliterals in the three packages, comparing every bare member againstFieldType.optionsand resolving non-members through the spec's declared alias table: the only members that are a declared typo-alias with the canonical spelling MISSING are the four this PR fixes. Every other non-spec member is either already carried alongside its canonical spelling (auto_number+autonumber,enum+select,attachment/photo+file/image,masterdetail+master_detail, andrich-text+richtextinFORM_ONLY_TYPES) or objectui-local dialect with no spec spelling at all (rollup,object,table,grid). So #4219's sweep found the whole family. One adjacent asymmetry that is NOT this family was filed separately as #4256 (repeatervsfield:grid), and the new derived pin's comment names it as the reason it was excluded.Gates
pnpm exec vitest run packages/plugin-detail/ packages/plugin-form/ packages/app-shell/— 457 files, 4406 passed, 1 skipped, 0 failed--filter 'pkg^...' build) thentype-checkon all three — both commands (tsc --noEmitandtsc -p tsconfig.typetests.json), exit 0linton all three — 0 errors (2279 pre-existing repo-wide warnings unchanged)check:control-bytesOK; targeted self-scan of every touched file cleanpatchfor@object-ui/plugin-detail,@object-ui/plugin-form,@object-ui/app-shell(noskip-changeset)Generated by Claude Code