Skip to content

feat(types): declare RichtextFieldMetadata for the widget's third registry key - #8373

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-7083-richtext-field-metadata
Sep 7, 2026
Merged

feat(types): declare RichtextFieldMetadata for the widget's third registry key#8373
os-zhuang merged 5 commits into
mainfrom
claude/issue-7083-richtext-field-metadata

Conversation

@claude

@claude claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #7083

Executes the maintainer's ruling of 2026-09-07 (director seat, decision batch #71, comment 5565745438): the three registry keys one widget serves each get an exported metadata type. RichtextFieldMetadata is added to @object-ui/types, joins the FieldMetadata union, and the deliberate as unknown as MarkdownFieldMetadata in packages/fields/src/widgets/__tests__/RichTextField.rows.test.tsx — with the comment above it — is gone.

Contract-review rework — round 2

A CONTRACT_REVIEW_TIER review returned FAIL with three reproducible items. The member's shape was judged correct and evidenced, and is untouched by this round: no change to the member, the union, the barrel, or any test's logic. What changed is one docs page and three pieces of prose that were false.

R1 — this diff had made a published docs page false

content/docs/fields/rich-text.mdx said markdown and html "are two field types served by one widget", that "each has its own exported metadata type", and that "there is no combined 'rich text' metadata type". The page never mentioned the richtext key at all. Declaring RichtextFieldMetadata is exactly what made those sentences false, and leaving them would have restarted the rediscovery loop the ruling exists to end.

Corrected by following the objectui#7061 precedent, which updated this same page for the analogous rows change:

before after
Field Schema lede "markdown and html are two field types served by one widget, and each has its own exported metadata type — MarkdownFieldMetadata and HtmlFieldMetadatathere is no combined "rich text" metadata type." "markdown, html and richtext are three field types served by one widget, and each has its own exported metadata type — MarkdownFieldMetadata, HtmlFieldMetadata and RichtextFieldMetadata … there is no combined "rich text" metadata type."
the ts fence imports two types; declares releaseNotes and emailBody imports three; adds an annotated articleBody: RichtextFieldMetadata literal with type / name / label / rows / max_length
rows paragraph "declared on both types … so neither metadata type declares one" "declared on all three types … so none of the three metadata types declares one"
new prose what richtext is (stores HTML, reads through the same display pipeline as html, objectui#5452), when it became declarable, and what max_length on it actually does
Editor Modes 1. Markdown Mode · 2. HTML Mode + 3. Rich Text Mode (type: 'richtext')

The Editor Modes entry is the same correction applied to the same page: the section enumerates the widget's modes and stopped at two. The seat's authorisation for this file-surface widening covers content/docs/fields/rich-text.mdx and nothing else; no other doc page is touched, and content/docs/releases/ is untouched.

R2 — the published TSDoc stated a false claim, for the wrong reason, citing the wrong pin

Three sub-items, all in RichtextFieldMetadata's max_length section of packages/types/src/field-types.ts and mirrored in the changeset body.

1. The "symmetric on every measurable axis" claim is dropped — it is false. Located by content, not by line: ObjectForm forwards max_length to the HTML maxlength attribute under if (field.type === 'text' || field.type === 'textarea' || field.type === 'markdown' || field.type === 'html'), and EmbeddableForm's DEFAULT_MAX_LENGTH record lists text, email, url, phone, textarea, markdown, html. richtext is absent from both.

before — "It is declared because the cross-check against MarkdownFieldMetadata and HtmlFieldMetadata found richtext symmetric with both on every axis that can be measured, not because they happen to have it"

after — "RichTextField never reads this key. It is declared because a live reader outside the widget does, on every field regardless of type"

2. The real reader is now stated, and it is checkable. The spec-symmetry argument is non-discriminating for this key: FieldSchema answers identically for every field type, text included, on maxLength and max_length, so it says nothing about richtext versus its siblings. The reader the round-1 derivation missed is buildValidationRules in packages/fields/src/index.tsx:

const maxLength = (field as any).maxLength ?? field.max_length;
if (maxLength) {
  rules.maxLength = { value: maxLength, message: , messageKey: 'validation.maxLength' };
}

Generic — no field-type gate anywhere in the function. It is applied to every field by ObjectForm (validation: buildValidationRules(field)) and by the identical line in sectionFields.ts; the form renderer spreads the result into the react-hook-form rules object and localizes the maxLength entry. ⇒ max_length on a richtext field is enforced at submit. That is the checkable reason the key is declared, and it now replaces the symmetry argument in both the docblock and the changeset. The two sites that do not reach richtext are stated alongside it, so the boundary cannot be re-derived as symmetry.

3. The pin citation is re-pointed. The docblock credited richtext-field-metadata-7083.test.tsx for three facts; that file pins only two of them.

fact cited before pinned in fact by
maxLength admitted richtext-field-metadata-7083.test.tsx same — correct
max_length refused by name richtext-field-metadata-7083.test.tsx same — correct
rows admitted richtext-field-metadata-7083.test.tsx packages/types/src/__tests__/select-option-spec-extension-7014.test.ts, its "FieldSchema declares rows on the four multiline editor types" group

Carried into the pin test's own docblock. That file repeated the same false rationale — "Putting it on the new member was a decision, and it rests on this reading rather than on the two siblings having it" — while being cited by the corrected docblock, so it is corrected with it. Comment-only, proven: stripped of every block and line comment, the file hashes c1d01d39c24f2ada70c58b52b8fa829574594315875f5d3ffc17bcccc65b74bf both before and after, at 68 non-comment lines either way. No assertion, fixture or describe body is touched.

R3 — the PR body contradicted its own diff

Since de98ffd3 this body was false in three places. The reviewer independently verified that the RichTextField.tsx edit is comment-only (stripped-of-// hashes identical, 0 non-comment lines changed, and the comment text appears nowhere in built dist/), so the correction is wording, not code.

# before after
1 "that file is read-only in this change and is unmodified" "that file carries a comment-only edit in this change, proven to ship nothing"
2 验收备注 1: "It is a two-line prose correction inside a file this dispatch declared READ ONLY, so it is deliberately not touched here." the stale comment was corrected in de98ffd3; the note now records that, and that the edit is comment-only
3 "packages/fields changes are test-only" "packages/fields changes are test-only plus one comment-only edit, proven to ship nothing"

All three are corrected in place below. The read-site table has also lost its line numbers, which had drifted with the merge; it now anchors on the expressions themselves.

What was missing

markdown, html and richtext are one widget (#5498). Two of the three carried an exported metadata type; richtext carried none, so the runtime served it happily by structure while an author could not write its metadata under an annotation at all. The state was neither a member nor a recorded alias — a silent gap whose only evidence was a cast in this repo's own pin test. That asymmetry is why the gap had to be rediscovered to be seen, and #7083 is itself that rediscovery.

So the comment goes with the cast, and the surrounding docblock in that file is re-pointed: the next reader should not be able to find the gap again.

The read set was DERIVED, not copied

The ruling's load-bearing sentence is "do not copy 'probably the same'". Every key was read off packages/fields/src/widgets/RichTextField.tsx on the richtext path. That file carries a comment-only edit in this change — the stale comment described in 验收备注 1 — and ships nothing: its executable text is byte-identical, and the reviewer confirmed the comment text appears nowhere in the built dist/.

key read site in RichTextField.tsx where it is declared
type resolveRichTextFieldType reads field.type and strips a field: prefix narrowed to 'richtext' on the new member
rows const rows = richField?.rows || 8 new line on the member
mobile_fullscreen Boolean(richField?.mobile_fullscreen) already on BaseFieldMetadata
placeholder richField?.placeholder || t(...) already on BaseFieldMetadata
label passed to FullscreenFieldEditor already on BaseFieldMetadata

The readonly branch hands field whole to the RICH_TEXT_CELL_RENDERERS entry for the type; both renderers in richTextDisplay.tsx destructure value only, so the display half contributes no metadata key. type is also the only thing that differs between the three keys at runtime — it selects the display pipeline (richtext reads through the HTML renderer, #5452) and the format label. Nothing else in the widget branches on it.

The one key that needed a decision

MarkdownFieldMetadata and HtmlFieldMetadata are byte-identical to each other apart from their type literal: type + max_length?: number + rows?: number over BaseFieldMetadata. So the cross-check produced exactly one open question — max_length, the one key on the siblings that RichTextField does not read.

It is declared, because a live reader outside the widget reads it on every field: buildValidationRules (see R2 above) compiles it into a submit-time react-hook-form rule with no field-type gate, and both form producers call it on every field they build. A max_length written on a richtext field is therefore enforced when the form is submitted.

⚠️ It is not forwarded to the editor's HTML maxlength attribute, and it gets no default cap in EmbeddableForm — both of those enumerate field types and omit richtext. Those two omissions predate this PR, are not this PR's, and are not touched here.

Separately — and not the reason for the key — the authoring boundary at @objectstack/spec 17.3.0 answers identically for all three of the field types this widget serves. That reading is non-discriminating (every field type answers the same way, text included) but is pinned anyway so the docblock cannot rot into a false canonical claim about the spelling:

payload markdown html richtext
control (no ceiling key) accepted accepted accepted
maxLength: 50 (the spec's own spelling) accepted accepted accepted
max_length: 50 (objectui legacy spelling) refused by name refused by name refused by name

rows: 4 is admitted for all three too, and that half is pinned in packages/types/src/__tests__/select-option-spec-extension-7014.test.ts, not in this PR's file.

The pin has two halves, and both are non-vacuous

packages/fields/src/widgets/__tests__/richtext-field-metadata-7083.test.tsx:

  • compiles — the literal is annotated, never as, so TypeScript's excess-property check judges every key, and it is assigned to FieldMetadata to pin the union membership the ruling granted plus the narrowing on type. Measured, not assumed, that this leg actually runs: packages/fields's type-check script is tsc --noEmit && tsc -p tsconfig.test.json, and tsc -p tsconfig.test.json --listFiles names both this file and RichTextField.rows.test.tsx. On the pre-change tree the file does not compile at all — there is no member to annotate against — which is what makes this leg real rather than decorative. A pin proving only the render would still have passed with the cast in place, i.e. in the state this card ends.
  • rendersrows, placeholder, mobile_fullscreen and label are each asserted at the DOM, against a control fixture with all the optional keys absent at once, so a green reads "the widget consumed the declared key" and never "the default happened to match".

Scope

Additive only. Nothing is removed or narrowed; richtext metadata previously written through a cast keeps compiling; RichTextField's behaviour is untouched — it already served all three keys, and this change only gives the third one a face. Round-1 downstream sweep: turbo run type-check --filter='...@object-ui/types'77/77 tasks green, so widening the FieldMetadata union breaks no consumer.

packages/fields changes are test-only plus one comment-only edit (RichTextField.tsx), proven to ship nothing, so the changeset grades @object-ui/types minor and nothing else.

Verification — round 2

Merged origin/main in first (9b1b105d, merge, never rebase; conflict-free) because the PR's mergeable_state read unknown on two consecutive API reads rather than clean. Every reading below is from after that merge, on the pushed head. Exit codes captured before any pipe (cmd > log 2>&1; EXIT=$?), each verdict read from the gate's own printed line.

gate exit verdict line
pnpm --filter @object-ui/types type-check 0 tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json — no diagnostics
pnpm --filter @object-ui/types build 0 ✓ dist completeness: 1 package(s) complete (124 emitted files verified)
pnpm --filter @object-ui/fields type-check 0 no diagnostics
node scripts/check-changeset-presence.mjs 0 5 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)
node scripts/check-doc-snippet-types.mjs (check:doc-snippets) 0 Semantic phase: 632 of 632 block(s) judged, 0 failed · 240 covered
node scripts/check-doc-component-types.mjs (check:doc-types) 0 Every documented component type is registered.
check:doc-fences 0 every TypeScript block in 227 document(s) is fenced ts/tsx/typescript
check:doc-examples 0 Every covered @example compiles, or fails exactly as its ledger row declares.
docs:check-links 0 Links are valid across 17 scan roots.
check:control-bytes 0 OK (scanned 6645 tracked text file(s); skipped 85 binary)
vitest run — the three pin files 0 Test Files 3 passed (3) · Tests 56 passed (56)

Beyond the gates, a control-byte self-scan over the four touched paths (grep -naP over the C0 range plus DEL) found none.

check:doc-snippets compiles fences against built dist/*.d.ts, so its closure (--build-filter, 34 packages) was rebuilt after the merge before the reading above was taken — an unbuilt tree exits 2 there and is not a verdict about any document.

The new fence is proven compiled, not assumed

The gate reports a block count, not which block is yours, so a red/green pair was measured rather than inferred. Mutation and restore both anchored on the target text and verified on disk:

  • mutationtoolbar: ['bold'] injected into the articleBody: RichtextFieldMetadata literal. On-disk proof: injected text present exactly 1 time; blob 8bfe7787…49956cd3… (a no-op mutation would have failed the run loudly).
  • red legcheck-doc-snippet-types.mjs exit 1, naming the file: [semantic] content/docs/fields/rich-text.mdx:52:3 TS2353: Object literal may only specify known properties, and 'toolbar' does not exist in type 'RichtextFieldMetadata'. · Semantic phase: 632 of 632 block(s) judged, 1 failed.
  • restore leggit checkout HEAD -- content/docs/fields/rich-text.mdx (never a bare git checkout --; the implementation was committed first, so HEAD carries it). Proven by state, not by exit code: working blob back to 8bfe7787…, identical to the HEAD blob, and git diff HEAD empty. The script carried a trap … EXIT INT TERM restore with an absolute repo-root path throughout.
  • green leg — gate re-run after restore: exit 0, Semantic phase: 632 of 632 block(s) judged, 0 failed.

⇒ the gate does read the new RichtextFieldMetadata literal, and it can fail on it.

验收备注

Observations. None is filed as a card by this seat.

  1. RichTextField.tsx's metadata-face comment was stale after the member landed, and it was corrected — in de98ffd3, not left. Its old text said the third key "has no union member of its own"; it now names RichtextFieldMetadata and explains why the cast below it still names only two of the three. The edit is comment-only: stripped-of-comment hashes identical, 0 non-comment lines changed, and the comment text appears nowhere in built dist/. The round-1 body claimed the file was untouched; that claim is what R3 corrected.
  2. The rows docblocks on MarkdownFieldMetadata and HtmlFieldMetadata still describe the @objectstack/spec 17.2.0 boundary (where rows was refused by name); at 17.3.0 it is admitted. That prose is When the @objectstack/spec pin moves to 17.3: PR #7510 / #7520's comment "repairs" become FALSE — rows and options[].description are now declared keys #7635's declared surface, so this PR states the 17.3.0 reading for richtext only and does not correct the neighbours.
  3. Noted, not filed — richtext is missing from three pre-existing enumerations. ObjectForm's maxlength-attribute forwarding, EmbeddableForm's DEFAULT_MAX_LENGTH, and designer.ts's DESIGNER_FIELD_TYPES each list field types and omit richtext, even though one widget serves all three. They are real, they predate this PR, and touching any of them would widen it. The dispatching PM seat is filing the finding card; this seat files nothing and changes nothing there.

Review

Clause-② applies (a new published type-face member), so needs:contract-review is hung on this PR as well as on the card, and stays — this round does not clear it. This PR stays draft, is not enqueued, and has no auto-merge armed; parking green is the intended end state until a fresh CONTRACT_REVIEW_TIER review passes. No label was added or removed and no review was submitted by this seat.

Authored by the domain:spec @ objectui execution seat, session https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX — kept in prose as a code span because a PATCH to this body downgrades a link-form attribution footer and drops the session reference.

…istry key

`markdown`, `html` and `richtext` are one widget (objectui#5498). Two of the
three carried an exported metadata type; `richtext` carried none, so the
runtime served it by structure while an author could not write its metadata
under an annotation at all. The only way to write one was
`as unknown as MarkdownFieldMetadata` — a deliberate cast in this repo's own
pin test that was the gap's sole evidence.

`RichtextFieldMetadata` is now exported from `@object-ui/types` and joins the
`FieldMetadata` union, so a richtext field's metadata is a typed literal and
narrows out of the union on `type`. The cast and its comment are gone, and the
surrounding docblock is re-pointed so the gap cannot be rediscovered.

The member's shape was derived from what `RichTextField` reads on the
`richtext` path, not copied from the two siblings: `type`, `rows`,
`placeholder`, `mobile_fullscreen` and `label` (the last three already sit on
`BaseFieldMetadata`), with the readonly branch's cell renderers contributing
no metadata key. `max_length` is declared on the measurement that `richtext`
is symmetric with `markdown`/`html` at the `@objectstack/spec` 17.3.0
authoring boundary, not on the siblings having it.

Additive only: nothing is removed or narrowed, `RichTextField` is unchanged,
and metadata previously written through a cast keeps compiling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3472.2 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-AHEZfBfj.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.55KB 114.03KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 189.15KB 52.56KB
fields (index.js) 243.15KB 61.40KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 193.79KB 46.09KB
plugin-dashboard (index.js) 131.48KB 34.45KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.65KB 63.91KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 55.38KB 15.72KB
plugin-list (index.js) 113.38KB 27.73KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.46KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…ew union member

Comment only — no behaviour, no read site, no signature changes.

The paragraph above `richField` said "the third key, `richtext`, has no union
member of its own". This branch is what makes that false, so the correction
belongs to this diff rather than to a follow-up: the ruling's stated reason for
deleting the pin test's comment was that the gap must not stay rediscoverable,
and the same sentence sat four lines from where a reader of the widget looks.

The cast itself is unchanged and stays correct. It names two of the three
members because it never had to discriminate: every key this widget consumes
off the carrier is declared on all three, so the two named already admit each
read below. The comment now says that outright instead of implying the third
key is undeclarable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3472.4 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-BqSg3AyZ.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.55KB 114.03KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 189.15KB 52.56KB
fields (index.js) 243.15KB 61.40KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.49KB 46.33KB
plugin-dashboard (index.js) 131.48KB 34.45KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.66KB 63.92KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 55.38KB 15.72KB
plugin-list (index.js) 113.38KB 27.73KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.46KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…te max_length's real reader

Contract-review rework on #7083 (three items, all reproducible).

R1 — content/docs/fields/rich-text.mdx said `markdown` and `html` are "two
field types served by one widget", "each has its own exported metadata type",
and "there is no combined 'rich text' metadata type"; the page never mentioned
the `richtext` key. Declaring RichtextFieldMetadata is what made that false.
The Field Schema section now names all three types, the fence carries a
RichtextFieldMetadata literal, and Editor Modes lists the third mode. Follows
the #7061 precedent, which updated this same page for the analogous change.

R2 — the member's TSDoc credited "richtext symmetric with both on every axis
that can be measured". That is false: ObjectForm forwards max_length to the
HTML maxlength attribute for text|textarea|markdown|html only, and
EmbeddableForm's DEFAULT_MAX_LENGTH caps markdown/html only — richtext is
absent from both. The spec-symmetry reading is also non-discriminating for
this key (FieldSchema answers identically for every field type, `text`
included). The real reader is buildValidationRules — generic, no field-type
gate, called on every field by ObjectForm and sectionFields, spread into the
RHF rules and localized — so max_length on a richtext field IS enforced at
submit. Same correction in the changeset body. The pin citation is re-pointed:
richtext-field-metadata-7083.test.tsx pins `maxLength` admitted and
`max_length` refused; `rows` admitted is pinned by
select-option-spec-extension-7014.test.ts.

The pin test's own docblock carried the same false rationale and is corrected
with it — comment-only, proven: stripped of comments the file hashes
identically before and after (68 non-comment lines, unchanged).

No change to the member's shape, the union, the barrel, or any test's logic.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3472.8 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-GQp8O3AY.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.55KB 114.03KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 189.15KB 52.56KB
fields (index.js) 243.15KB 61.40KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.52KB 46.34KB
plugin-dashboard (index.js) 131.48KB 34.45KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.68KB 63.94KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 55.38KB 15.72KB
plugin-list (index.js) 112.74KB 27.70KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-zhuang
os-zhuang marked this pull request as ready for review September 7, 2026 23:34
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 7, 2026
Merged via the queue into main with commit 0b1ac58 Sep 7, 2026
34 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7083-richtext-field-metadata branch September 7, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] richtext registry key 在 @object-ui/types 无 FieldMetadata union 成员(markdown/html 有)——结构上被服务但不可声明

2 participants