forms(qml): chrome slots -- a host replaces DynamicForm's labels, containers and buttons, not only its controls - #810
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Yaraslaut
added a commit
that referenced
this pull request
Sep 25, 2026
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819) #810 made DynamicForm's chrome replaceable. The two composing views still hard-coded theirs -- title, column headers, row cells, Open / row-action / collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next and the step counter -- and, more to the point, never gave the DynamicForms they embed a slotRegistry at all: a host's field slots and form chrome stopped at the view's edge, so even a fully registered kit drew built-in editors. - `slotRegistry` on both views, handed to modalForm / detailForm and to every wizard step. - CollectionView roles: collectionHeader (title, columns, actions, fire), collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire), confirmDialog (message, action, row, accept, reject -- loaded only while an action waits) and editorDialog (title, open, close, and a contentItem the editor form is reparented into). - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle) and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the built-in gate: the step's action must have replied ok. - DateTimePicker gets no chrome: a host replaces the whole picker with a field slot, byKind("datetime") from #816. Nothing registered, nothing changes: tst_collectionview.qml and tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins each role, the embedded forms receiving the registry, and a fully chromed collection screen with the editor open showing no visible built-in Label or Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1. Stacked on #810 (byChrome / resolveChrome). Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Yaraslaut
added a commit
that referenced
this pull request
Sep 25, 2026
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819) hard-coded theirs -- title, column headers, row cells, Open / row-action / collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next and the step counter -- and, more to the point, never gave the DynamicForms they embed a slotRegistry at all: a host's field slots and form chrome stopped at the view's edge, so even a fully registered kit drew built-in editors. - `slotRegistry` on both views, handed to modalForm / detailForm and to every wizard step. - CollectionView roles: collectionHeader (title, columns, actions, fire), collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire), confirmDialog (message, action, row, accept, reject -- loaded only while an action waits) and editorDialog (title, open, close, and a contentItem the editor form is reparented into). - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle) and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the built-in gate: the step's action must have replied ok. - DateTimePicker gets no chrome: a host replaces the whole picker with a field slot, byKind("datetime") from #816. Nothing registered, nothing changes: tst_collectionview.qml and tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins each role, the embedded forms receiving the registry, and a fully chromed collection screen with the editor open showing no visible built-in Label or Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1. Stacked on #810 (byChrome / resolveChrome). Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Yaraslaut
force-pushed
the
feature/forms-chrome-slots
branch
from
September 25, 2026 07:00
e34375a to
4e5155f
Compare
…tainers and buttons, not only its controls SlotRegistry lets a host swap a field's *control*, but everything around the controls stayed built-in: the bold caption and red `*`, the help line, the section heading and accordion toggle, the TabBar, the action-type heading, the status line, the Submit button, the monospace JSON preview and the reply line. A host whose look comes from one UI kit therefore could not get a form that looked like the rest of the app, whatever slots it registered. `SlotRegistry.byChrome(role, component)` / `resolveChrome(role)` register one Component per role -- fieldLabel, fieldHelp, section, accordion (falls back to section), tabset, header, status, submitButton, preview, result -- and DynamicForm loads it in place of the built-in, which is hidden rather than drawn beside it. Each chrome item is handed only the members it declares (`bindChrome`), as bindings where the value changes: a label gets `required` (including requiredWhen) and `invalid` (typed text that does not encode, via the new `fieldInvalid(name)`); the status line's text moved into `DynamicForm.statusText` so the built-in and a chrome read one source. Container chrome (section / accordion / tabset) declares a `contentItem`, and the form creates its field grid inside it. The built-in grid's Repeater is emptied under a chrome, so each field exists once and its `field_<name>` objectName stays unique -- prefill, resetFields() and name-based lookups keep working. A tabset chrome owns `currentIndex`; the form rebuilds the selected tab's fields on a switch exactly as the built-in tab bar does. A chrome submit button goes through `submit()`, so the `ready` guard still holds. Nothing registered, nothing changes: the existing 317 QML cases are untouched and green. The new tst_DynamicFormChrome.qml (13 cases) pins each role, and a form with every role registered showing no visible built-in Label, Button or TabBar. Restoring the section Repeater under a chrome reddens the fields-created-once case. forms_qml_logic: 330 passed on MSVC 14.51 / Qt 6.11.1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
….byChrome, and the registry reaches the forms they embed (fixes #813) (#819) hard-coded theirs -- title, column headers, row cells, Open / row-action / collection-action buttons, the "Are you sure?" and editor Dialogs, Back / Next and the step counter -- and, more to the point, never gave the DynamicForms they embed a slotRegistry at all: a host's field slots and form chrome stopped at the view's edge, so even a fully registered kit drew built-in editors. - `slotRegistry` on both views, handed to modalForm / detailForm and to every wizard step. - CollectionView roles: collectionHeader (title, columns, actions, fire), collectionRow (row, columns, cells, rowKey, actions, canOpen, open, fire), confirmDialog (message, action, row, accept, reject -- loaded only while an action waits) and editorDialog (title, open, close, and a contentItem the editor form is reparented into). - WizardView roles: wizardHeader (title, stepIndex, stepCount, stepTitle) and wizardNav (canBack, canNext, lastStep, back, next). next() keeps the built-in gate: the step's action must have replied ok. - DateTimePicker gets no chrome: a host replaces the whole picker with a field slot, byKind("datetime") from #816. Nothing registered, nothing changes: tst_collectionview.qml and tst_wizardview.qml are untouched and green. tst_ViewChrome.qml (9 cases) pins each role, the embedded forms receiving the registry, and a fully chromed collection screen with the editor open showing no visible built-in Label or Button. Dropping the registry hand-off and the row-chrome swap reddens 3 of them. forms_qml_logic: 341 passed on MSVC 14.51 / Qt 6.11.1. Stacked on #810 (byChrome / resolveChrome). Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Yaraslaut
force-pushed
the
feature/forms-chrome-slots
branch
from
September 25, 2026 07:54
4e5155f to
14e60d8
Compare
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.
Field slots replace a control, but the caption +
*, help line, section heading / accordion toggle, TabBar, action-type heading, status line, Submit button, JSON preview and reply line were all hard-wired built-ins, so a host drawing from its own UI kit could not fully restyle a form.SlotRegistry.byChrome(role, component)/resolveChrome(role); DynamicForm loads the chrome in place of the built-in (hidden, not drawn beside it). Members are assigned only if the chrome declares them; changing values are bindings; every chrome also getsform.fieldLabel*field,text,required(live, incl.requiredWhen),invalid(live)fieldHelpfield,textsection/accordiontitle,kind,section;contentItemrequiredtabsettabs, chrome-ownedcurrentIndex;contentItemrequiredheader/status/preview/resulttext(+ready,reason,explicitSubmit/ok)submitButtonready,submit()(form'sreadyguard still applies)contentItem; the built-in Repeater is emptied, so each field exists once andfield_<name>stays unique (prefill /resetFields()/ lookups unaffected).DynamicForm.statusText,fieldInvalid(name),chrome(role).Item. TheFrameborder/padding are set on the instance (background: null) — documented, no slot needed.Spec:
docs/spec/forms/forms.md— new "Chrome slots" subsection.Tests (MSVC 14.51, Qt 6.11.1): new
tst_DynamicFormChrome.qml(13 cases, incl. a fully chromed form with no visible built-in Label/Button/TabBar). Restoring the built-in Repeater under a chrome reddens the fields-created-once case.forms_qml_logic330 passed.Touches
DynamicForm.qmlalongside #808/#809: merged together onfeature/forms-host-visuals-combined, the QML merges automatically and onlyCHANGELOG.mdconflicts (each PR adds an entry at the head of "Added").🤖 Generated with Claude Code