Repository navigation
fix(types,components,plugin-form): declare a form field's step (the spec's number) and className; built-in branches merge the class and derive the number step, ObjectForm stops writing 'any' (objectui#12130) - #12166
Conversation
…ives its step; ObjectForm stops writing `step` (objectui#12130) The built-in `input` arm and the unregistered-widget `default` arm draw a native number input under `inputType: 'number'`. Each now derives its step from the metadata carrier by the registered `number` widget's rule: an explicit numeric `step` wins, else `10^-scale`, else `'any'`. So `ObjectForm` no longer writes `step` onto the entries it builds. It used to write `'any'` when no `scale` was declared, a value the spec's numeric `FieldSchema.step` refuses. `objectFormNumericStep-9574.test.tsx` passes unmodified on both of its routes. The premise measurement for round 3, committed before any declaration. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
… into its control's classes (objectui#12130) The built-in `input`, `textarea`, `checkbox` and `switch` branches and the unregistered-widget default spread the entry's `className` over their own classes, so an authored class erased the touch-target height and the read-only tint. Each now writes `cn(own, entry.className)` after the spread, as the built-in `select` already did. The effects pins measure it per element class (a built-in control, a registered widget, a section-divider), and a sweep over every type the form draws pins that the class never lands on the field row, its label or a wrapper the host draws, editable or read-only. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
…assName`; the census has no open row left (objectui#12130) `step` is `FieldSchema.step` by reference on both faces, so HTML's `'any'` is refused, on the tolerant face too, which used to strip it. No producer writes it any more: the controls that draw a number derive `'any'` themselves when a field declares neither `step` nor `scale`. `className` is the classes of the element the field's type renders, measured per type through the real `SchemaRenderer` with and without `@object-ui/fields`: the control, a registered widget's own element, or a section-divider's divider, never the field row or a wrapper the host draws. The census moves both rows into DECLARED_BY_12130; its ledger has no open row left. The face pin, the zod coverage list, form.mdx and one changeset follow. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
…ber input, and that no producer writes `'any'` (objectui#12130) Comment-only. The default arm's note said an object-bound number field reaches it when its widget is unregistered; the entries that draw a number input there are the ones that say `inputType: 'number'` and name no registered widget. The `FormField` note said no producer writes `step`; it is `'any'` that no producer writes. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
…bjectui#12130) Brings in objectui#12155's DOM allowlist for the form's built-in branches. Conflicts in renderFieldComponent resolved by keeping both: the allowlist (`toFormControlDomProps` plus `builtinHostAttributes`) and the explicit react-hook-form binding from objectui#12155, then this branch's merged `className` (`cn(own, entry.className)`) and the number input's derived `step` after the spread. `BUILTIN_HOST_ATTRIBUTES`' note said `ObjectForm` writes `step`; since this branch it writes none, so the note now says `FormField` declares `step` and the number input resolves it from the metadata carrier. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
…lared FormField key; round 1's changeset and the 9574 header follow (objectui#12130) Claim amendment 6114408150, the seat's answers to open questions 1-3: - content/docs/plugins/plugin-form.mdx: `className` moves from the "Not a `FormField` key" table to the declared keys; the two-key sentence becomes one key, keeping `defaultValue`; the clause saying nothing in the contract promises a field-level `className` is deleted; the stale key cardinal is dropped. - scripts/__tests__/check-doc-component-types.test.ts: the `className` assertion flips to `toMatch`, so the pin re-derives the page's now positive claim. The `defaultValue` non-member assertion stays. - .changeset/12130-form-field-channel-keys.md: its "Still undeclared" sentence goes, since no OPEN row remains; the new changeset's "Supersedes" bullet goes with it. Prose only. - objectFormNumericStep-9574.test.tsx: header prose only. Every assertion is byte-identical. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
…ld key (objectui#12130) Claim amendment 6114675131: the same correction as plugin-form.mdx. `className` moves from the "Not a `FormField` key" list into the declared keys, and the stale key cardinal is dropped. Claude-Session: https://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73 Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
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
Size Limits
|
Contract reviewServed-tier: Inputs: card #12130 (body, 19 comments), PR #12166 (body, 16 files, net diff ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #12130
Clause-②: yes (narrowing): declaring
stepandclassNamewidens the strict authoring face by two keys. Typingstepas the spec's number narrows the tolerant face, from acceptingstep: 'any'(stripped) to refusing it atfields[].step.Round 3 of objectui#12130 (
step,className), the census's last two OPEN rows. After it the census ledger has no OPEN row. Implemented by the os-dev for thedomain:spec@ objectui seat, sessionhttps://claude.ai/code/session_01V8qYZseSLfKH3V8tPu2f73, claim 6113481475 as amended by 6114408150. Basec0c2f79, synced by mergingmainf3d5408(objectui#12155's DOM allowlist; conflicts kept both sides). Head9c93615.Premises (measured before any declaration): both held
step. The built-in number input can derive the step from the metadata carrier (field.field || field; on theObjectFormroute that is the raw object field withscale), byNumberField's rule: an explicitstep, else10^-scale, elseany. SoObjectFormnow writes nostep.objectFormNumericStep-9574.test.tsxpasses on both routes with every assertion byte-identical tomain: its 7expect(lines diff empty, and only header prose changed. Ablating the derivation turns its two route-1 tests red. A hand-authoredinputwithinputType: 'number'steps byany/0.01(scale 2) /5(explicit), where it had no step attribute / none /5before.className. Measured per type through the realSchemaRenderer, with components only and with@object-ui/fields, in three states. Every reader puts it on an element the field's own widget or branch renders: the control in most types, the widget's own box fortags,file,imageandslider, the first sub-input foraddressandgeolocation, a display element, or asection-divider's divider. None puts it on the field row, the label, the host's read-only group or outside the row.lookup,master_detail,userandsignaturedraw no class from it.What changed
packages/components/src/renderers/form/form.tsx: theinputanddefaultarms derive a number input's step (nativeNumberStep), and the built-in branches merge an entry'sclassNamewith their own classes (cn(own, className)), asselectalready did. Before, the entry's class replaced the touch-target and read-only classes.packages/plugin-form/src/ObjectForm.tsx: theformField.step = … : 'any'write is removed.FormField/FormFieldSchema:stepdeclared by reference to the spec'sFieldSchema.step;classNamedeclared asstring.DECLARED_BY_12130), the effects and components-only pins (with/without cases, one per element class, and a never-the-row sweep), the face pin and the zod coverage list.form.mdxandplugin-form.mdx(classNameis now a declared key). Its pin incheck-doc-component-types.test.tsflips totoMatch..changeset/12130-step-classname.md(types / componentsminor, plugin-formpatch, breaking semantics stated). Round 1's pending changeset loses its 「Still undeclared」 sentence.Gates run (code at
215da7e;9c93615adds theplugin-form/README.mdcorrection only)os-verify-lock:scripts/__tests__/「Test Files 180 passed | 2 skipped (182)」; the 9574 pin 「Tests 3 passed (3)」;examples/schema-catalog/「Test Files 46 passed (46)」. Atb1fd4c4:packages/types/,packages/plugin-form/,packages/components/: all exit 0.pnpm --filtertype-checkfor types, components, plugin-form and example-schema-catalog: exit 0.pnpm check: 「0 did not validate」.check-doc-component-types,-doc-snippet-types,-doc-json-fences,check:doc-fences,-doc-example-ids: all exit 0.check-changeset-presence「7 source file(s) of 3 released package(s) changed, and this change declares 1 changeset(s)」.-claims,-no-major,-overwriteand-fixedexit 0 (-overwritereports the round-1 changeset edit, report-only).check:pending-changeset-literals,check:control-bytesandcheck:new-line-citations(「0 new citation(s)」): exit 0.Acceptance notes
packages/plugin-form/README.mdlistedclassNameas 「Not aFormFieldkey」. It ships with the package, so it is corrected in this PR (9c93615, claim amendment6114675131):classNamemoves to the declared keys and the stale 「23 keys」 count is dropped.lookup,master_detail,userandsignatureacceptclassNameand draw nothing from it. That is noted, not filed.Generated by Claude Code