From be690be131ae4ba43751187fbf242202fac27d43 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Aug 2026 01:48:27 +0000 Subject: [PATCH 1/2] fix(components): declare the I18nLabel arm on element:text_input's label / placeholder / description (#5717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The renderer has resolved all three keys through `pickLocalized` since it was written, while the `ComponentMeta` entries still declared a single `'string'` arm — so `validateTree` reported `type-mismatch` on a locale map the contract admits and the screen renders correctly in the viewer's language. The inverse of #5590 / #5637, where the declaration correctly stayed narrow until the render site caught up. Here the render site was never behind. Per-key, not blanket: `defaultValue` keeps `['string','number']` (no object arm in its contract) and the console specimen control asserting that stays green. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4m --- .changeset/text-input-i18n-label-arms-5717.md | 45 ++++ .../component-input-union-specimens.test.ts | 203 +++++++++++++++++- .../text-input-i18n-label-arms.test.tsx | 185 ++++++++++++++++ .../text-input-inputs-spec-parity.test.ts | 108 ++++++++++ .../src/renderers/basic/text-input.tsx | 76 ++++++- 5 files changed, 613 insertions(+), 4 deletions(-) create mode 100644 .changeset/text-input-i18n-label-arms-5717.md create mode 100644 packages/components/src/__tests__/text-input-i18n-label-arms.test.tsx diff --git a/.changeset/text-input-i18n-label-arms-5717.md b/.changeset/text-input-i18n-label-arms-5717.md new file mode 100644 index 0000000000..f8cbd403a3 --- /dev/null +++ b/.changeset/text-input-i18n-label-arms-5717.md @@ -0,0 +1,45 @@ +--- +'@object-ui/components': patch +--- + +`element:text_input` now DECLARES the inline-translation arm on `label`, +`placeholder` and `description`, so the manifest gate stops reporting +`type-mismatch` on a locale map its own renderer has always resolved correctly +(objectui#5717). + +`@objectstack/spec` types all three keys as the `I18nLabel` union +(`string | Record`) — measured on the installed 17.1.0 pin, per +key, from the schema's own verdicts — and `text-input.tsx` has resolved all +three through `pickLocalized` at their read sites since it was written. Only the +`ComponentMeta` entries stayed at a single `'string'` arm. Driven through the +same `manifestFromConfigs` + `validateTree` pair the JSX-page compiler and the +save gate use, an author writing `{ en: 'Owner', 'zh-CN': '负责人' }` got three +warnings on a write that renders correctly in the viewer's language: + +``` + prop "label" expected a string + prop "placeholder" expected a string + prop "description" expected a string +``` + +That is the INVERSE of the direction the rest of this family moved in. +`element:record_picker.emptyText` (objectui#5590) and that block's `label` / +`placeholder` (objectui#5637) each held one arm for exactly as long as their +render site dropped the map, and gained the object arm in the change that taught +the render site to resolve it — never declare an arm the renderer drops. Here +the render site was never behind, so the same rule's other half applies: +withholding an arm the renderer resolves is the false declaration in the other +direction, and noise on legal writes trains authors (AI authors included) to +dismiss the `unknown-prop` and `type-mismatch` reports that are real. + +Per-key, not blanket. `defaultValue` on this same block keeps `['string', +'number']` — its contract has no object arm, measured the same way — and the +console specimen file keeps asserting that an `I18N_MAP` there still reports +`type-mismatch`. That control is what makes this a widening of three keys rather +than of a component. + +All three keys also gain a `description` written from what the renderer does +rather than from restating the contract: where each one lands in the rendered +output (a `